diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 67e9f8925d..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "actors/sunbird-lms-mw"] - path = actors/sunbird-lms-mw - url = https://github.com/project-sunbird/sunbird-lms-mw.git - branch = master diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ec4b7ca93a..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: java -jdk: openjdk8 -install: echo "Over-riding default script for travis-ci" -dist: trusty -script: - - jdk_switcher use openjdk8 - - mvn clean package -q '-Dtest=!%regex[io.opensaber.registry.client.*]' -DfailIfNoTests=false - - bash <(curl -s https://codecov.io/bash) -cache: - directories: - - "$HOME/.m2" -notifications: - slack: sunbird-ci:UegIg4Bf86V3HcXAB2uXNLGI - on_success: never - on_failure: always - email: - recipients: - - manzarul.haque@tarento.com - - amit.kumar@tarento.com - - vinayab@ilimi.in - on_success: never - on_failure: always -git: - submodules: false -before_install: - - git submodule update --init --recursive --remote diff --git a/Dockerfile b/Dockerfile index 8522ff90f1..d639491e11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,4 +12,5 @@ USER sunbird COPY ./service/target/learning-service-1.0-SNAPSHOT-dist.zip /home/sunbird/learner/ RUN unzip /home/sunbird/learner/learning-service-1.0-SNAPSHOT-dist.zip -d /home/sunbird/learner/ WORKDIR /home/sunbird/learner/ -CMD java -XX:+PrintFlagsFinal $JAVA_OPTIONS -cp '/home/sunbird/learner/learning-service-1.0-SNAPSHOT/lib/*' play.core.server.ProdServerStart /home/sunbird/learner/learning-service-1.0-SNAPSHOT +CMD java -XX:+PrintFlagsFinal $JAVA_OPTIONS -Dplay.server.http.idleTimeout=180s -cp '/home/sunbird/learner/learning-service-1.0-SNAPSHOT/lib/*' play.core.server.ProdServerStart /home/sunbird/learner/learning-service-1.0-SNAPSHOT + diff --git a/actors/sunbird-lms-mw b/actors/sunbird-lms-mw deleted file mode 160000 index fd4f8c41bf..0000000000 --- a/actors/sunbird-lms-mw +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fd4f8c41bfe25a3bdb83ad8849d47c50a4324fef diff --git a/actors/sunbird-lms-mw/.gitignore b/actors/sunbird-lms-mw/.gitignore new file mode 100644 index 0000000000..b5a3968b66 --- /dev/null +++ b/actors/sunbird-lms-mw/.gitignore @@ -0,0 +1,25 @@ +/target/ +project/project +project/target +target +tmp +.history +dist +/.idea +/*.iml +/out +/.idea_modules +/.classpath +/.project +/.settings +/.target/ +/bin/ +/logs +.settings +.classpath +.project +**/*.iml +**/.DS_Store +actors/badge/logs +dependency-reduced-pom.xml +**/velocity.log diff --git a/actors/sunbird-lms-mw/actors/badge/pom.xml b/actors/sunbird-lms-mw/actors/badge/pom.xml new file mode 100644 index 0000000000..45b40c234c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + org.sunbird + mw-actors + 1.0-SNAPSHOT + ../pom.xml + + badge + Badging Infra + + UTF-8 + + + + org.sunbird + actor-common + 1.0-SNAPSHOT + + + com.typesafe.akka + akka-testkit_2.11 + 2.5.19 + test + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + **/*Spec.java + **/*Test.java + + + + + + diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/BadgeOperations.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/BadgeOperations.java new file mode 100644 index 0000000000..21057b11a4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/BadgeOperations.java @@ -0,0 +1,14 @@ +package org.sunbird.badge; + +/** @author Mahesh Kumar Gangula */ +public enum BadgeOperations { + assignBadgeMessage, + revokeBadgeMessage, + createBadgeIssuer, + createBadgeAssertion, + assignBadgeToUser, + revokeBadgeFromUser, + getBadgeIssuer, + getAllIssuer, + deleteIssuer +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeAssertionActor.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeAssertionActor.java new file mode 100644 index 0000000000..12ca197c41 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeAssertionActor.java @@ -0,0 +1,126 @@ +/** */ +package org.sunbird.badge.actors; + +import java.io.IOException; +import java.util.Map; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.badge.BadgeOperations; +import org.sunbird.badge.service.impl.BadgingFactory; +import org.sunbird.badge.util.BadgeAssertionValidator; +import org.sunbird.badge.util.BadgingUtil; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.Util; + +/** @author Manzarul */ +@ActorConfig( + tasks = {"createBadgeAssertion", "getBadgeAssertion", "getBadgeAssertionList", "revokeBadge"}, + asyncTasks = {} +) +public class BadgeAssertionActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + ProjectLogger.log("BadgeAssertionActor onReceive called", LoggerEnum.INFO.name()); + String operation = request.getOperation(); + + Util.initializeContext(request, TelemetryEnvKey.BADGE_ASSERTION); + + switch (operation) { + case "createBadgeAssertion": + createAssertion(request); + break; + case "getBadgeAssertion": + getAssertionDetails(request); + break; + case "getBadgeAssertionList": + getAssertionList(request); + break; + case "revokeBadge": + revokeAssertion(request); + break; + default: + onReceiveUnsupportedOperation("BadgeClassActor"); + } + } + + /** + * This method will call the badger server to create badge assertion. + * + * @param actorMessage Request + */ + private void createAssertion(Request actorMessage) throws IOException { + ProjectLogger.log( + "BadgeAssertionActor:createAssertion: Call started ", + actorMessage.getRequest(), + LoggerEnum.INFO.name()); + String recipientId = (String) actorMessage.getRequest().get(BadgingJsonKey.RECIPIENT_ID); + String objectType = (String) actorMessage.getRequest().get(BadgingJsonKey.RECIPIENT_TYPE); + String badgeId = (String) actorMessage.getRequest().get(BadgingJsonKey.BADGE_ID); + BadgeAssertionValidator.validateRootOrg(recipientId, objectType, badgeId); + Response result = BadgingFactory.getInstance().badgeAssertion(actorMessage); + ProjectLogger.log( + "BadgeAssertionActor:createAssertion: Assertion Response : " + result.getResult(), + LoggerEnum.INFO.name()); + sender().tell(result, self()); + Map map = BadgingUtil.createBadgeNotifierMap(result.getResult()); + Request request = new Request(); + ProjectLogger.log( + "BadgeAssertionActor:createAssertion: Notifying badge assertion for " + + objectType + + " with id: " + + recipientId, + actorMessage.getRequest(), + LoggerEnum.INFO.name()); + map.put(JsonKey.OBJECT_TYPE, objectType); + map.put(JsonKey.ID, recipientId); + request.getRequest().putAll(map); + request.setOperation(BadgeOperations.assignBadgeMessage.name()); + tellToAnother(request); + } + + /** + * This method will get single assertion details based on issuerSlug, badgeClassSlug and + * assertionSlug + * + * @param request Request + */ + private void getAssertionDetails(Request request) throws IOException { + Response result = BadgingFactory.getInstance().getAssertionDetails(request); + sender().tell(result, self()); + } + + /** + * This method will get single assertion details based on issuerSlug, badgeClassSlug and + * assertionSlug + * + * @param request Request + */ + private void getAssertionList(Request request) throws IOException { + Response result = BadgingFactory.getInstance().getAssertionList(request); + sender().tell(result, self()); + } + + /** + * This method will make a call for revoking the badges. + * + * @param request Request + */ + private void revokeAssertion(Request request) throws IOException { + Response result = BadgingFactory.getInstance().revokeAssertion(request); + sender().tell(result, self()); + Map map = BadgingUtil.createRevokeBadgeNotifierMap(request.getRequest()); + Request notificationReq = new Request(); + map.put(JsonKey.OBJECT_TYPE, request.getRequest().get(BadgingJsonKey.RECIPIENT_TYPE)); + map.put(JsonKey.ID, request.getRequest().get(BadgingJsonKey.RECIPIENT_ID)); + notificationReq.getRequest().putAll(map); + notificationReq.setOperation(BadgeOperations.revokeBadgeMessage.name()); + tellToAnother(notificationReq); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeClassActor.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeClassActor.java new file mode 100644 index 0000000000..8d2d367149 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeClassActor.java @@ -0,0 +1,151 @@ +package org.sunbird.badge.actors; + +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.badge.service.BadgingService; +import org.sunbird.badge.service.impl.BadgingFactory; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.Util; + +/** + * BadgeClassActor handles BadgeClass requests. + * + * @author B Vinaya Kumar + */ +@ActorConfig( + tasks = {"createBadgeClass", "getBadgeClass", "searchBadgeClass", "deleteBadgeClass"}, + asyncTasks = {} +) +public class BadgeClassActor extends BaseActor { + + private BadgingService badgingService; + + public BadgeClassActor() { + this.badgingService = BadgingFactory.getInstance(); + } + + public BadgeClassActor(BadgingService badgingService) { + this.badgingService = badgingService; + } + + @Override + public void onReceive(Request request) throws Throwable { + ProjectLogger.log("BadgeClassActor onReceive called"); + String operation = request.getOperation(); + + Util.initializeContext(request, TelemetryEnvKey.BADGE_CLASS); + + switch (operation) { + case "createBadgeClass": + createBadgeClass(request); + break; + case "getBadgeClass": + getBadgeClass(request); + break; + case "searchBadgeClass": + searchBadgeClass(request); + break; + case "deleteBadgeClass": + deleteBadgeClass(request); + break; + default: + onReceiveUnsupportedOperation("BadgeClassActor"); + } + } + + /** + * Creates a new badge class for a particular issuer. + * + * @param actorMessage Request message containing following request data: issuerId: The ID of the + * Issuer to be owner of the new Badge Class name: The name of the Badge Class description: A + * short description of the new Badge Class. image: An image to represent the Badge Class. + * criteria: Either a text string or a URL of a remotely hosted page describing the criteria + * rootOrgId: Root organisation ID type: Badge class type (user / content) subtype: Badge + * class subtype (e.g. award) roles: JSON array of roles (e.g. [ + * "OFFICIAL_TEXTBOOK_BADGE_ISSUER" ]) + * @return Return a promise for create badge class API result. + */ + private void createBadgeClass(Request actorMessage) { + ProjectLogger.log("createBadgeClass called"); + + try { + Response response = badgingService.createBadgeClass(actorMessage); + + sender().tell(response, self()); + } catch (ProjectCommonException e) { + ProjectLogger.log("createBadgeClass: exception = ", e); + + sender().tell(e, self()); + } + } + + /** + * Get details of requsted badge class. + * + * @param actorMessage Request message containing following request data: badgeId The ID of the + * Badge Class whose details to view + */ + private void getBadgeClass(Request actorMessage) { + ProjectLogger.log("getBadgeClass called"); + + try { + Response response = + badgingService.getBadgeClassDetails( + (String) actorMessage.getRequest().get(BadgingJsonKey.BADGE_ID)); + + sender().tell(response, self()); + } catch (ProjectCommonException e) { + ProjectLogger.log("getBadgeClass: exception = ", e); + + sender().tell(e, self()); + } + } + + /** + * Get list of badge classes for given issuer(s) and matching given context. + * + * @param actorMessage Request message containing following request data issuerList: List of + * Issuer IDs whose badge classes are to be listed badgeList: List of badge IDs whose badge + * classes are to be listed rootOrgId: Root organisation ID type: Badge class type (user / + * content) subtype: Badge class subtype (e.g. award) roles: JSON array of roles (e.g. [ + * "OFFICIAL_TEXTBOOK_BADGE_ISSUER" ]) + */ + private void searchBadgeClass(Request actorMessage) { + ProjectLogger.log("searchBadgeClass called"); + + try { + Response response = badgingService.searchBadgeClass(actorMessage); + + sender().tell(response, self()); + } catch (ProjectCommonException e) { + ProjectLogger.log("searchBadgeClass: exception = ", e); + + sender().tell(e, self()); + } + } + + /** + * Delete a badge class that has never been issued. + * + * @param actorMessage Request message containing following request data: badgeId The ID of the + * Badge Class to delete + */ + private void deleteBadgeClass(Request actorMessage) { + ProjectLogger.log("deleteBadgeClass called"); + + try { + Response response = badgingService.removeBadgeClass(actorMessage); + + sender().tell(response, self()); + } catch (ProjectCommonException e) { + ProjectLogger.log("deleteBadgeClass: exception = ", e); + + sender().tell(e, self()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeIssuerActor.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeIssuerActor.java new file mode 100644 index 0000000000..9a176f4fb3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeIssuerActor.java @@ -0,0 +1,81 @@ +package org.sunbird.badge.actors; + +import java.io.IOException; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.badge.service.BadgingService; +import org.sunbird.badge.service.impl.BadgingFactory; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.Util; + +/** Created by arvind on 5/3/18. */ +@ActorConfig( + tasks = {"createBadgeIssuer", "getBadgeIssuer", "getAllIssuer", "deleteIssuer"}, + asyncTasks = {} +) +public class BadgeIssuerActor extends BaseActor { + + private BadgingService badgingService; + + public BadgeIssuerActor() { + this.badgingService = BadgingFactory.getInstance(); + } + + public BadgeIssuerActor(BadgingService badgingService) { + this.badgingService = badgingService; + } + + @Override + public void onReceive(Request request) throws Throwable { + ProjectLogger.log("BadgeIssuerActor onReceive called", LoggerEnum.INFO.name()); + String operation = request.getOperation(); + + Util.initializeContext(request, TelemetryEnvKey.BADGE); + + switch (operation) { + case "createBadgeIssuer": + createBadgeIssuer(request); + break; + case "getBadgeIssuer": + getBadgeIssuer(request); + break; + case "getAllIssuer": + getAllIssuer(request); + break; + case "deleteIssuer": + deleteIssuer(request); + break; + default: + onReceiveUnsupportedOperation("BadgeIssuerActor"); + } + } + + /** + * Actor mathod to create the issuer of badge . + * + * @param actorMessage + */ + private void createBadgeIssuer(Request actorMessage) throws IOException { + Response response = badgingService.createIssuer(actorMessage); + sender().tell(response, self()); + } + + private void getBadgeIssuer(Request actorMessage) throws IOException { + Response response = badgingService.getIssuerDetails(actorMessage); + sender().tell(response, self()); + } + + private void getAllIssuer(Request actorMessage) throws IOException { + Response response = badgingService.getIssuerList(actorMessage); + sender().tell(response, self()); + } + + private void deleteIssuer(Request request) throws IOException { + Response response = badgingService.deleteIssuer(request); + sender().tell(response, self()); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeNotifier.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeNotifier.java new file mode 100644 index 0000000000..7dd957de7d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/BadgeNotifier.java @@ -0,0 +1,86 @@ +package org.sunbird.badge.actors; + +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.badge.BadgeOperations; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.response.ResponseParams; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.Util; + +/** @author Mahesh Kumar Gangula */ +@ActorConfig( + tasks = {}, + asyncTasks = {"assignBadgeMessage", "revokeBadgeMessage"} +) +public class BadgeNotifier extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + List asyncTasks = Arrays.asList("assignBadgeMessage", "revokeBadgeMessage"); + String operation = request.getOperation(); + String objectType = (String) request.getRequest().get(JsonKey.OBJECT_TYPE); + ProjectLogger.log( + "Processing badge notification for " + operation, + request.getRequest(), + LoggerEnum.INFO.name()); + Response response; + if (StringUtils.isNotBlank(operation) && asyncTasks.contains(operation)) { + response = processBadge(operation, objectType, request); + sender().tell(response, self()); + } else { + onReceiveUnsupportedMessage(request.getOperation()); + } + } + + private Response processBadge(String operation, String objectType, Request request) + throws Exception { + Response response; + String INVALID_BADGE_NOTIFICATION_REQUEST = "INVALID_BADGE_NOTIFICATION_REQUEST"; + if (StringUtils.isBlank(objectType)) { + response = invalidObjectType(INVALID_BADGE_NOTIFICATION_REQUEST, objectType); + } else { + String caseVal = objectType.toUpperCase() + ":" + operation.toUpperCase(); + switch (caseVal) { + case "USER:ASSIGNBADGEMESSAGE": + request.setOperation(BadgeOperations.assignBadgeToUser.name()); + response = notifyUser(request); + break; + case "USER:REVOKEBADGEMESSAGE": + request.setOperation(BadgeOperations.revokeBadgeFromUser.name()); + response = notifyUser(request); + break; + default: + response = invalidObjectType(INVALID_BADGE_NOTIFICATION_REQUEST, objectType); + break; + } + } + return response; + } + + private Response notifyUser(Request request) { + tellToAnother(request); + Response response = new Response(); + response.setResponseCode(ResponseCode.success); + return response; + } + + private Response invalidObjectType(String error, String objectType) { + Response response = new Response(); + response.setResponseCode(ResponseCode.CLIENT_ERROR); + ResponseParams params = new ResponseParams(); + params.setErrmsg("ObjectType is invalid to assign/revoke badge: " + objectType); + params.setErr(error); + response.setParams(params); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/UserBadgeAssertion.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/UserBadgeAssertion.java new file mode 100644 index 0000000000..43fd15cb4b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/actors/UserBadgeAssertion.java @@ -0,0 +1,156 @@ +package org.sunbird.badge.actors; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.badge.BadgeOperations; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.learner.util.Util.DbInfo; +import org.sunbird.telemetry.util.TelemetryUtil; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {}, + asyncTasks = {"assignBadgeToUser", "revokeBadgeFromUser"} +) +public class UserBadgeAssertion extends BaseActor { + + @Override + public void onReceive(Request request) { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + if (BadgeOperations.assignBadgeToUser.name().equalsIgnoreCase(operation)) { + addBadgeData(request); + } else if (BadgeOperations.revokeBadgeFromUser.name().equalsIgnoreCase(operation)) { + revokeBadgeData(request); + } + } + + private void revokeBadgeData(Request request) { + // request came to revoke the badge from user + DbInfo dbInfo = Util.dbInfoMap.get(BadgingJsonKey.USER_BADGE_ASSERTION_DB); + Map badge = getBadgeAssertion(request); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + cassandraOperation.deleteRecord( + dbInfo.getKeySpace(), + dbInfo.getTableName(), + (String) badge.get(BadgingJsonKey.ASSERTION_ID)); + updateUserBadgeDataToES(badge); + tellToSender(request, badge); + } + + private void addBadgeData(Request request) { + // request came to assign the badge from user + DbInfo dbInfo = Util.dbInfoMap.get(BadgingJsonKey.USER_BADGE_ASSERTION_DB); + Map badge = getBadgeAssertion(request); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + cassandraOperation.insertRecord(dbInfo.getKeySpace(), dbInfo.getTableName(), badge); + updateUserBadgeDataToES(badge); + tellToSender(request, badge); + } + + @SuppressWarnings("unchecked") + private void updateUserBadgeDataToES(Map map) { + Future> resultF = + EsClientFactory.getInstance(JsonKey.REST) + .getDataByIdentifier( + ProjectUtil.EsType.user.getTypeName(), (String) map.get(JsonKey.USER_ID)); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (MapUtils.isEmpty(result)) { + ProjectLogger.log( + "UserBadgeAssertion:updateUserBadgeDataToES user with userId " + + (String) map.get(JsonKey.USER_ID) + + " not found", + LoggerEnum.INFO.name()); + return; + } + if (CollectionUtils.isNotEmpty( + (List>) result.get(BadgingJsonKey.BADGE_ASSERTIONS))) { + List> badgeAssertionsList = + (List>) result.get(BadgingJsonKey.BADGE_ASSERTIONS); + + boolean bool = true; + Iterator> itr = badgeAssertionsList.iterator(); + while (itr.hasNext()) { + Map tempMap = itr.next(); + if (((String) tempMap.get(JsonKey.ID)).equalsIgnoreCase((String) map.get(JsonKey.ID))) { + itr.remove(); + bool = false; + } + } + + if (bool) { + badgeAssertionsList.add(map); + } + } else { + List> mapList = new ArrayList<>(); + mapList.add(map); + result.put(BadgingJsonKey.BADGE_ASSERTIONS, mapList); + } + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) result.get(JsonKey.IDENTIFIER), + result); + } + + private boolean updateDataToElastic( + String indexName, String typeName, String identifier, Map data) { + + Future responseF = + EsClientFactory.getInstance(JsonKey.REST).update(typeName, identifier, data); + boolean response = (boolean) ElasticSearchHelper.getResponseFromFuture(responseF); + if (!response) { + ProjectLogger.log( + "unbale to save the data inside ES for user badge " + identifier, LoggerEnum.INFO.name()); + } + return response; + } + + private Map getBadgeAssertion(Request request) { + String userId = (String) request.getRequest().get(JsonKey.ID); + @SuppressWarnings("unchecked") + Map badge = + (Map) request.getRequest().get(BadgingJsonKey.BADGE_ASSERTION); + badge.put(JsonKey.USER_ID, userId); + badge.put(JsonKey.ID, badge.get(BadgingJsonKey.ASSERTION_ID)); + // removing status from map + badge.remove(JsonKey.STATUS); + return badge; + } + + private void tellToSender(Request request, Map badge) { + Response reponse = new Response(); + reponse.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(reponse, self()); + sendTelemetry(request, badge); + } + + private void sendTelemetry(Request request, Map badge) { + List> correlatedObject = new ArrayList<>(); + Map targetObject; + String userId = (String) badge.get(JsonKey.USER_ID); + targetObject = TelemetryUtil.generateTargetObject(userId, JsonKey.USER, JsonKey.UPDATE, null); + TelemetryUtil.generateCorrelatedObject( + (String) badge.get(BadgingJsonKey.ASSERTION_ID), + BadgingJsonKey.BADGE_ASSERTION, + null, + correlatedObject); + TelemetryUtil.generateCorrelatedObject(userId, JsonKey.USER, null, correlatedObject); + TelemetryUtil.telemetryProcessingCall( + request.getRequest(), targetObject, correlatedObject, request.getContext()); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/model/BadgeClassExtension.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/model/BadgeClassExtension.java new file mode 100644 index 0000000000..993628f33d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/model/BadgeClassExtension.java @@ -0,0 +1,87 @@ +package org.sunbird.badge.model; + +import java.util.List; +import java.util.Map; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; + +public class BadgeClassExtension { + private String badgeId; + private String issuerId; + private String rootOrgId; + private String type; + private String subtype; + private List roles; + + public BadgeClassExtension( + String badgeId, + String issuerId, + String rootOrgId, + String type, + String subtype, + List roles) { + this.badgeId = badgeId; + this.issuerId = issuerId; + this.rootOrgId = rootOrgId; + this.type = type; + this.subtype = subtype; + this.roles = roles; + } + + public BadgeClassExtension(Map map) { + this.badgeId = (String) map.get(JsonKey.ID); + this.issuerId = (String) map.get(BadgingJsonKey.ISSUER_ID); + this.rootOrgId = (String) map.get(JsonKey.ROOT_ORG_ID); + this.type = (String) map.get(JsonKey.TYPE); + this.subtype = (String) map.get(JsonKey.SUBTYPE); + this.roles = (List) map.get(JsonKey.ROLES); + } + + public String getBadgeId() { + return badgeId; + } + + public void setBadgeId(String badgeId) { + this.badgeId = badgeId; + } + + public String getIssuerId() { + return issuerId; + } + + public void setIssuerId(String issuerId) { + this.issuerId = issuerId; + } + + public String getRootOrgId() { + return rootOrgId; + } + + public void setRootOrgId(String rootOrgId) { + this.rootOrgId = rootOrgId; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getSubtype() { + return subtype; + } + + public void setSubtype(String subtype) { + this.subtype = subtype; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgeAssociationService.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgeAssociationService.java new file mode 100644 index 0000000000..6dec6d4388 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgeAssociationService.java @@ -0,0 +1,35 @@ +package org.sunbird.badge.service; + +import java.util.List; +import java.util.Map; + +public interface BadgeAssociationService { + + /* + * This method will return map for badgeAssociations in content-metadta + * + * @param Map badgeMap + * @return Map associatedBadgeMetadata + */ + public Map getBadgeAssociationMapForContentUpdate(Map badgeMap); + + /* + * This method will return create map for badgeAssociations in cassandraDB + * + * @param Map badgeMap + * @return Map associatedBadgeMetadata + */ + public Map getCassandraBadgeAssociationCreateMap( + Map badgeMap, String requestedBy, String contentId); + + /* + * This method will return update map for badgeAssociations in cassandraDB + * + * @param Map badgeMap + * @return Map associatedBadgeMetadata + */ + public Map getCassandraBadgeAssociationUpdateMap( + String associationId, String requestedBy); + + public void syncToES(List> badgeAssociationMapList, boolean toBeCreated); +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgeClassExtensionService.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgeClassExtensionService.java new file mode 100644 index 0000000000..0f23be971f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgeClassExtensionService.java @@ -0,0 +1,21 @@ +package org.sunbird.badge.service; + +import java.util.List; +import org.sunbird.badge.model.BadgeClassExtension; +import org.sunbird.common.exception.ProjectCommonException; + +public interface BadgeClassExtensionService { + void save(BadgeClassExtension badgeClassExtension); + + List search( + List issuerList, + List badgeList, + String rootOrgId, + String type, + String subtype, + List roles); + + BadgeClassExtension get(String badgeId) throws ProjectCommonException; + + void delete(String badgeId); +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgingService.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgingService.java new file mode 100644 index 0000000000..ae717150de --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/BadgingService.java @@ -0,0 +1,125 @@ +package org.sunbird.badge.service; + +import java.io.IOException; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.request.Request; + +/** + * This interface will have all the methods required for badging framework. any new method required + * for badging need to be added here. + * + * @author Manzarul + */ +public interface BadgingService { + + /** + * This method will create an issuer based on user requested data. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response createIssuer(Request request) throws IOException; + + /** + * This method will provide particular issuer details based on requested issuer id. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response getIssuerDetails(Request request) throws IOException; + + /** + * This method will provide list of issuers. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response getIssuerList(Request request) throws IOException; + + /** + * This method will create a badge class for a particular issuer. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response createBadgeClass(Request request) throws ProjectCommonException; + + /** + * This method will provide badge class details based on badgeId + * + * @param String badgeId + * @exception IOException + * @return Response + */ + public Response getBadgeClassDetails(String badgeId) throws ProjectCommonException; + + /** + * This method will provide list of badge class either for one issuer or multiple or all , this + * will depends on requested param. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response searchBadgeClass(Request request) throws ProjectCommonException; + + /** + * This method will remove badge class from db. Badge class can be removed if it is not assign to + * any one. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response removeBadgeClass(Request request) throws ProjectCommonException; + + /** + * This method will issue a badge assertion to either user or content. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response badgeAssertion(Request request) throws IOException; + + /** + * This method will provide particular assertion details. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response getAssertionDetails(Request request) throws IOException; + + /** + * This method will provide list of assertions. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response getAssertionList(Request request) throws IOException; + + /** + * This method is used to remove the assertion from either user or content. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response revokeAssertion(Request request) throws IOException; + + /** + * This method will provide particular issuer details based on requested issuer id. + * + * @param request Request + * @exception IOException + * @return Response + */ + public Response deleteIssuer(Request request) throws IOException; +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgeClassExtensionServiceImpl.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgeClassExtensionServiceImpl.java new file mode 100644 index 0000000000..d02718af5a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgeClassExtensionServiceImpl.java @@ -0,0 +1,120 @@ +package org.sunbird.badge.service.impl; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.badge.model.BadgeClassExtension; +import org.sunbird.badge.service.BadgeClassExtensionService; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +public class BadgeClassExtensionServiceImpl implements BadgeClassExtensionService { + private CassandraOperation cassandraOperation; + public static final String BADGE_CLASS_EXT_TABLE_NAME = "badge_class_extension"; + + public BadgeClassExtensionServiceImpl() { + this.cassandraOperation = ServiceFactory.getInstance(); + } + + public BadgeClassExtensionServiceImpl(CassandraOperation cassandraOperation) { + this.cassandraOperation = cassandraOperation; + } + + @Override + public void save(BadgeClassExtension badgeClassExtension) { + Map request = new HashMap<>(); + + request.put(JsonKey.ID, badgeClassExtension.getBadgeId()); + request.put(BadgingJsonKey.ISSUER_ID, badgeClassExtension.getIssuerId()); + + request.put(JsonKey.ROOT_ORG_ID, badgeClassExtension.getRootOrgId()); + request.put(JsonKey.TYPE, badgeClassExtension.getType()); + request.put(JsonKey.SUBTYPE, badgeClassExtension.getSubtype()); + request.put(JsonKey.ROLES, badgeClassExtension.getRoles()); + + cassandraOperation.upsertRecord(Util.KEY_SPACE_NAME, BADGE_CLASS_EXT_TABLE_NAME, request); + } + + @Override + public List search( + List issuerList, + List badgeList, + String rootOrgId, + String type, + String subtype, + List roles) { + Map propertyMap = new HashMap<>(); + + if (rootOrgId != null) { + propertyMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + } + + if (type != null) { + propertyMap.put(JsonKey.TYPE, type); + } + + if (subtype != null) { + propertyMap.put(JsonKey.SUBTYPE, subtype); + } + + Response response = + cassandraOperation.getRecordsByProperties( + Util.KEY_SPACE_NAME, BADGE_CLASS_EXT_TABLE_NAME, propertyMap); + List> badgeClassExtList = + (List>) response.get(JsonKey.RESPONSE); + + return badgeClassExtList + .stream() + .map(badgeClassExtMap -> new BadgeClassExtension(badgeClassExtMap)) + .filter( + badgeClassExt -> + roles == null + || CollectionUtils.isEmpty(badgeClassExt.getRoles()) + || !Collections.disjoint(roles, badgeClassExt.getRoles())) + .filter( + badgeClassExt -> + CollectionUtils.isEmpty(issuerList) + || issuerList.contains(badgeClassExt.getIssuerId())) + .filter( + badgeClassExt -> + CollectionUtils.isEmpty(badgeList) + || badgeList.contains(badgeClassExt.getBadgeId())) + .collect(Collectors.toList()); + } + + @Override + public BadgeClassExtension get(String badgeId) throws ProjectCommonException { + Response response = + cassandraOperation.getRecordById(Util.KEY_SPACE_NAME, BADGE_CLASS_EXT_TABLE_NAME, badgeId); + List> badgeList = + (List>) response.get(JsonKey.RESPONSE); + + if ((badgeList == null) || badgeList.isEmpty()) { + ProjectLogger.log( + "BadgeClassExtensionServiceImpl:get: Badge not found " + badgeId, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.resourceNotFound.getErrorCode(), + ResponseCode.resourceNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + + return new BadgeClassExtension(badgeList.get(0)); + } + + @Override + public void delete(String badgeId) { + cassandraOperation.deleteRecord(Util.KEY_SPACE_NAME, BADGE_CLASS_EXT_TABLE_NAME, badgeId); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgingFactory.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgingFactory.java new file mode 100644 index 0000000000..baa030a24f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgingFactory.java @@ -0,0 +1,26 @@ +/** */ +package org.sunbird.badge.service.impl; + +import org.sunbird.badge.service.BadgingService; + +/** @author Manzarul */ +public class BadgingFactory { + + private static BadgingService service; + + static { + service = new BadgrServiceImpl(); + } + + /** private default constructor. */ + private BadgingFactory() {} + + /** + * This method will provide singleton instance for badging service impl. + * + * @return BadgingService + */ + public static BadgingService getInstance() { + return service; + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgrServiceImpl.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgrServiceImpl.java new file mode 100644 index 0000000000..bacf4f814d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/service/impl/BadgrServiceImpl.java @@ -0,0 +1,684 @@ +package org.sunbird.badge.service.impl; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.stream.Collectors; +import org.apache.commons.lang.StringUtils; +import org.json.JSONException; +import org.json.JSONObject; +import org.sunbird.badge.model.BadgeClassExtension; +import org.sunbird.badge.service.BadgeClassExtensionService; +import org.sunbird.badge.service.BadgingService; +import org.sunbird.badge.util.BadgingUtil; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.HttpUtilResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.telemetry.util.TelemetryUtil; + +/** @author Manzarul */ +public class BadgrServiceImpl implements BadgingService { + private BadgeClassExtensionService badgeClassExtensionService; + private ObjectMapper mapper = new ObjectMapper(); + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + public static Map headerMap = new HashMap<>(); + + static { + String header = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(header)) { + header = PropertiesCache.getInstance().readProperty(JsonKey.EKSTEP_AUTHORIZATION); + } else { + header = JsonKey.BEARER + header; + } + headerMap.put(JsonKey.AUTHORIZATION, header); + headerMap.put("Content-Type", "application/json"); + } + + public BadgrServiceImpl() { + this.badgeClassExtensionService = new BadgeClassExtensionServiceImpl(); + } + + public BadgrServiceImpl(BadgeClassExtensionService badgeClassExtensionService) { + this.badgeClassExtensionService = badgeClassExtensionService; + } + + @Override + public Response createIssuer(Request request) throws IOException { + + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + Map req = request.getRequest(); + byte[] image = null; + Map fileData = new HashMap<>(); + if (req.containsKey(JsonKey.IMAGE) && null != req.get(JsonKey.IMAGE)) { + image = (byte[]) req.get(JsonKey.IMAGE); + } + Map requestData = new HashMap<>(); + requestData.put(JsonKey.NAME, (String) req.get(JsonKey.NAME)); + requestData.put(JsonKey.DESCRIPTION, (String) req.get(JsonKey.DESCRIPTION)); + requestData.put(JsonKey.URL, (String) req.get(JsonKey.URL)); + requestData.put(JsonKey.EMAIL, (String) req.get(JsonKey.EMAIL)); + requestData.put(JsonKey.SLUG, BadgingJsonKey.ISSUER_SLUG); + + if (null != image) { + fileData.put(JsonKey.IMAGE, image); + } + HttpUtilResponse httpResponse = + HttpUtil.postFormData( + requestData, + fileData, + BadgingUtil.getBadgrHeaders(false), + BadgingUtil.getBadgeIssuerUrl()); + + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpResponse.getStatusCode(), null, BadgingJsonKey.ISSUER); + Response response = new Response(); + BadgingUtil.prepareBadgeIssuerResponse(httpResponse.getBody(), response.getResult()); + + targetObject = + TelemetryUtil.generateTargetObject( + (String) response.getResult().get(BadgingJsonKey.ISSUER_ID), + BadgingJsonKey.BADGE_ISSUER, + JsonKey.CREATE, + null); + TelemetryUtil.telemetryProcessingCall( + req, targetObject, correlatedObject, request.getContext()); + + return response; + } + + @Override + public Response getIssuerDetails(Request request) throws IOException { + Map req = request.getRequest(); + String slug = (String) req.get(JsonKey.SLUG); + HttpUtilResponse httpResponse = + HttpUtil.doGetRequest(BadgingUtil.getBadgeIssuerUrl(slug), BadgingUtil.getBadgrHeaders()); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpResponse.getStatusCode(), null, BadgingJsonKey.ISSUER); + Response response = new Response(); + BadgingUtil.prepareBadgeIssuerResponse(httpResponse.getBody(), response.getResult()); + return response; + } + + @Override + public Response getIssuerList(Request request) throws IOException { + HttpUtilResponse httpResponse = + HttpUtil.doGetRequest(BadgingUtil.getBadgeIssuerUrl(), BadgingUtil.getBadgrHeaders()); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpResponse.getStatusCode(), null, BadgingJsonKey.ISSUER); + Response response = new Response(); + + List> issuers = new ArrayList<>(); + List> data = + mapper.readValue(httpResponse.getBody(), new TypeReference>>() {}); + for (Object badge : data) { + Map mappedBadge = new HashMap<>(); + BadgingUtil.prepareBadgeIssuerResponse((Map) badge, mappedBadge); + issuers.add(mappedBadge); + } + Map res = new HashMap<>(); + res.put(BadgingJsonKey.ISSUERS, issuers); + response.getResult().putAll(res); + return response; + } + + @Override + public Response createBadgeClass(Request request) throws ProjectCommonException { + Response response = new Response(); + + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + try { + Map requestData = request.getRequest(); + + Map formParams = new HashMap<>(); + formParams.put( + BadgingJsonKey.ISSUER_SLUG, (String) requestData.get(BadgingJsonKey.ISSUER_ID)); + formParams.put(JsonKey.NAME, (String) requestData.get(JsonKey.NAME)); + formParams.put(JsonKey.DESCRIPTION, (String) requestData.get(JsonKey.DESCRIPTION)); + formParams.put(JsonKey.CRITERIA, (String) requestData.get(JsonKey.CRITERIA)); + formParams.put(JsonKey.SLUG, BadgingJsonKey.BADGE_SLUG); + + Map fileParams = new HashMap<>(); + fileParams.put(JsonKey.IMAGE, (byte[]) requestData.get(JsonKey.IMAGE)); + + String issuerId = (String) requestData.get(BadgingJsonKey.ISSUER_ID); + String rootOrgId = (String) requestData.get(JsonKey.ROOT_ORG_ID); + String type = (String) requestData.get(JsonKey.TYPE); + String subtype = (String) requestData.get(JsonKey.SUBTYPE); + String roles = (String) requestData.get(JsonKey.ROLES); + + if (type != null) { + type = type.toLowerCase(); + } + + if (subtype != null) { + subtype = subtype.toLowerCase(); + } + + List rolesList; + if (roles != null) { + String trimmedRoles = roles.trim(); + if (trimmedRoles.startsWith("[") && trimmedRoles.endsWith("]")) { + rolesList = mapper.readValue(trimmedRoles, ArrayList.class); + } else { + rolesList = new ArrayList<>(); + rolesList.add(trimmedRoles); + } + } else { + rolesList = new ArrayList<>(); + } + // validating incoming roles. + validateRoles(rolesList); + + Map headers = BadgingUtil.getBadgrHeaders(false); + + HttpUtilResponse httpUtilResponse = + HttpUtil.postFormData( + formParams, fileParams, headers, BadgingUtil.getBadgeClassUrl(issuerId)); + String badgrResponseStr = httpUtilResponse.getBody(); + + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpUtilResponse.getStatusCode(), badgrResponseStr, BadgingJsonKey.BADGE_CLASS); + + Map badgrResponseMap = mapper.readValue(badgrResponseStr, HashMap.class); + String badgeId = (String) badgrResponseMap.get(BadgingJsonKey.SLUG); + + BadgeClassExtension badgeClassExt = + new BadgeClassExtension(badgeId, issuerId, rootOrgId, type, subtype, rolesList); + badgeClassExtensionService.save(badgeClassExt); + + BadgingUtil.prepareBadgeClassResponse(badgrResponseStr, badgeClassExt, response.getResult()); + targetObject = + TelemetryUtil.generateTargetObject( + (String) response.getResult().get(BadgingJsonKey.BADGE_ID), + BadgingJsonKey.BADGE_CLASS, + JsonKey.CREATE, + null); + TelemetryUtil.generateCorrelatedObject( + issuerId, BadgingJsonKey.BADGE_ISSUER, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject( + rootOrgId, JsonKey.ORGANISATION, null, correlatedObject); + TelemetryUtil.telemetryProcessingCall( + requestData, targetObject, correlatedObject, request.getContext()); + + } catch (IOException e) { + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.SERVER_ERROR.getResponseCode(), e.getMessage(), BadgingJsonKey.BADGE_CLASS); + } + + return response; + } + + @Override + public Response getBadgeClassDetails(String badgeId) throws ProjectCommonException { + Response response = new Response(); + + try { + + Map headers = BadgingUtil.getBadgrHeaders(); + String badgrUrl = BadgingUtil.getBadgeClassUrl(BadgingJsonKey.ISSUER_ID, badgeId); + + HttpUtilResponse httpUtilResponse = HttpUtil.doGetRequest(badgrUrl, headers); + String badgrResponseStr = httpUtilResponse.getBody(); + + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpUtilResponse.getStatusCode(), badgrResponseStr, BadgingJsonKey.BADGE_CLASS); + + BadgeClassExtension badgeClassExtension = badgeClassExtensionService.get(badgeId); + + BadgingUtil.prepareBadgeClassResponse( + badgrResponseStr, badgeClassExtension, response.getResult()); + } catch (IOException e) { + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.SERVER_ERROR.getResponseCode(), e.getMessage(), BadgingJsonKey.BADGE_CLASS); + } + + return response; + } + + @Override + public Response searchBadgeClass(Request request) throws ProjectCommonException { + Response response = new Response(); + + Map filtersMap = + (Map) request.getRequest().get(JsonKey.FILTERS); + + List issuerList = (List) filtersMap.get(BadgingJsonKey.ISSUER_LIST); + List badgeList = (List) filtersMap.get(BadgingJsonKey.BADGE_LIST); + String rootOrgId = (String) filtersMap.get(JsonKey.ROOT_ORG_ID); + String type = (String) filtersMap.get(JsonKey.TYPE); + String subtype = (String) filtersMap.get(JsonKey.SUBTYPE); + List allowedRoles = (List) filtersMap.get(JsonKey.ROLES); + + if (type != null) { + type = type.toLowerCase(); + } + + if (subtype != null) { + subtype = subtype.toLowerCase(); + } + + List badgeClassExtList = + badgeClassExtensionService.search( + issuerList, badgeList, rootOrgId, type, subtype, allowedRoles); + List filteredIssuerList = + badgeClassExtList + .stream() + .map(badge -> badge.getIssuerId()) + .distinct() + .collect(Collectors.toList()); + + List badges = new ArrayList<>(); + + for (String issuerSlug : filteredIssuerList) { + badges.addAll(listBadgeClassForIssuer(issuerSlug, badgeClassExtList)); + } + + response.put(BadgingJsonKey.BADGES, badges); + + return response; + } + + private List listBadgeClassForIssuer( + String issuerSlug, List badgeClassExtensionList) + throws ProjectCommonException { + List filteredBadges = new ArrayList<>(); + + try { + Map headers = BadgingUtil.getBadgrHeaders(); + String badgrUrl = BadgingUtil.getBadgeClassUrl(issuerSlug); + + HttpUtilResponse httpUtilResponse = HttpUtil.doGetRequest(badgrUrl, headers); + String badgrResponseStr = httpUtilResponse.getBody(); + + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpUtilResponse.getStatusCode(), badgrResponseStr, BadgingJsonKey.BADGE_CLASS); + + List> badges = mapper.readValue(badgrResponseStr, ArrayList.class); + + for (Map badge : badges) { + BadgeClassExtension matchedBadgeClassExt = + badgeClassExtensionList + .stream() + .filter(x -> x.getBadgeId().equals(badge.get(BadgingJsonKey.SLUG))) + .findFirst() + .orElse(null); + + if (matchedBadgeClassExt != null) { + Map mappedBadge = new HashMap<>(); + BadgingUtil.prepareBadgeClassResponse(badge, matchedBadgeClassExt, mappedBadge); + filteredBadges.add(mappedBadge); + } + } + } catch (IOException e) { + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.SERVER_ERROR.getResponseCode(), e.getMessage(), BadgingJsonKey.BADGE_CLASS); + } + + return filteredBadges; + } + + @Override + public Response removeBadgeClass(Request requestMsg) throws ProjectCommonException { + Response response = new Response(); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + try { + Map requestData = requestMsg.getRequest(); + + String badgeId = (String) requestData.get(BadgingJsonKey.BADGE_ID); + + Map headers = BadgingUtil.getBadgrHeaders(); + // Using dummy issuer ID (rather than getting it from DB) as badgr ignores it anyway. + String badgrUrl = BadgingUtil.getBadgeClassUrl(BadgingJsonKey.ISSUER_ID, badgeId); + + HttpUtilResponse httpUtilResponse = HttpUtil.sendDeleteRequest(headers, badgrUrl); + String badgrResponseStr = httpUtilResponse.getBody(); + + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpUtilResponse.getStatusCode(), badgrResponseStr, BadgingJsonKey.BADGE_CLASS); + + badgeClassExtensionService.delete(badgeId); + response.put(JsonKey.MESSAGE, badgrResponseStr.replaceAll("^\"|\"$", "")); + targetObject = + TelemetryUtil.generateTargetObject( + badgeId, BadgingJsonKey.BADGE_CLASS, JsonKey.DELETE, null); + TelemetryUtil.telemetryProcessingCall( + requestData, targetObject, correlatedObject, requestMsg.getContext()); + + } catch (IOException e) { + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.SERVER_ERROR.getResponseCode(), e.getMessage(), BadgingJsonKey.BADGE_CLASS); + } + + return response; + } + + @Override + @SuppressWarnings("unchecked") + public Response badgeAssertion(Request request) throws IOException { + // Based on incoming recipientType and recipientId collect the email. + Map requestedData = request.getRequest(); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + String email = + getEmail( + (String) requestedData.get(BadgingJsonKey.RECIPIENT_ID), + (String) requestedData.get(BadgingJsonKey.RECIPIENT_TYPE)); + if (StringUtils.isBlank(email) && !ProjectUtil.isEmailvalid(email)) { + ProjectLogger.log("Recipient email is not valid ==" + email); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), null, BadgingJsonKey.BADGE_ASSERTION); + } + requestedData.put(BadgingJsonKey.RECIPIENT_EMAIL, email); + String requestBody = BadgingUtil.createAssertionReqData(requestedData); + String url = + BadgingUtil.createBadgerUrl( + requestedData, BadgingUtil.SUNBIRD_BADGER_CREATE_ASSERTION_URL, 2); + ProjectLogger.log( + "AssertionData==" + requestBody + " " + url + " " + BadgingUtil.getBadgrHeaders(), + LoggerEnum.INFO.name()); + HttpUtilResponse httpResponse = + HttpUtil.doPostRequest(url, requestBody, BadgingUtil.getBadgrHeaders()); + + ProjectLogger.log( + "AssertionDataResponse==" + httpResponse.getStatusCode(), LoggerEnum.INFO.name()); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpResponse.getStatusCode(), null, BadgingJsonKey.BADGE_ASSERTION); + Map res = mapper.readValue(httpResponse.getBody(), HashMap.class); + // calling to create response as per sunbird + res = BadgingUtil.prepareAssertionResponse(res, new HashMap()); + Response response = new Response(); + response.getResult().putAll(res); + targetObject = + TelemetryUtil.generateTargetObject( + (String) response.getResult().get(BadgingJsonKey.BADGE_ID), + BadgingJsonKey.BADGE_CLASS, + JsonKey.CREATE, + null); + TelemetryUtil.generateCorrelatedObject( + (String) requestedData.get(BadgingJsonKey.RECIPIENT_ID), + (String) requestedData.get(BadgingJsonKey.RECIPIENT_TYPE), + null, + correlatedObject); + TelemetryUtil.generateCorrelatedObject( + (String) requestedData.get(BadgingJsonKey.ISSUER_ID), + BadgingJsonKey.BADGE_ISSUER, + null, + correlatedObject); + TelemetryUtil.generateCorrelatedObject( + (String) requestedData.get(BadgingJsonKey.BADGE_ID), + BadgingJsonKey.BADGE_CLASS, + null, + correlatedObject); + TelemetryUtil.telemetryProcessingCall( + requestedData, targetObject, correlatedObject, request.getContext()); + return response; + } + + @Override + @SuppressWarnings("unchecked") + public Response getAssertionDetails(Request request) throws IOException { + String url = + BadgingUtil.createBadgerUrl( + request.getRequest(), BadgingUtil.SUNBIRD_BADGER_GETASSERTION_URL, 3); + HttpUtilResponse httpResponse = HttpUtil.doGetRequest(url, BadgingUtil.getBadgrHeaders()); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpResponse.getStatusCode(), null, BadgingJsonKey.BADGE_ASSERTION); + Map res = mapper.readValue(httpResponse.getBody(), HashMap.class); + // calling to create response as per sunbird + res = BadgingUtil.prepareAssertionResponse(res, new HashMap()); + Response response = new Response(); + response.getResult().putAll(res); + return response; + } + + @Override + @SuppressWarnings("unchecked") + public Response getAssertionList(Request request) throws IOException { + Map filterMap = (Map) request.getRequest().get(JsonKey.FILTERS); + List requestData = (List) filterMap.get(BadgingJsonKey.ASSERTIONS); + List> responseList = new ArrayList<>(); + for (String assertionId : requestData) { + WeakHashMap map = new WeakHashMap<>(); + map.put(BadgingJsonKey.ASSERTION_ID, assertionId); + String url = BadgingUtil.createBadgerUrl(map, BadgingUtil.SUNBIRD_BADGER_GETASSERTION_URL, 3); + HttpUtilResponse httpResponse = HttpUtil.doGetRequest(url, BadgingUtil.getBadgrHeaders()); + if (httpResponse.getStatusCode() == 200) { + Map res = mapper.readValue(httpResponse.getBody(), HashMap.class); + // calling to create response as per sunbird + res = BadgingUtil.prepareAssertionResponse(res, new HashMap()); + responseList.add(res); + } + } + Response response = new Response(); + response.getResult().put(BadgingJsonKey.ASSERTIONS, responseList); + return response; + } + + @Override + public Response revokeAssertion(Request request) throws IOException { + // do the recipient id validation + Map requestedData = request.getRequest(); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + // This is doing the validation of incoming userId or contnetId + // only this value is not passed to badgr.io + getEmail( + (String) requestedData.get(BadgingJsonKey.RECIPIENT_ID), + (String) requestedData.get(BadgingJsonKey.RECIPIENT_TYPE)); + String url = + BadgingUtil.createBadgerUrl( + request.getRequest(), BadgingUtil.SUNBIRD_BADGER_GETASSERTION_URL, 3); + String requestBody = BadgingUtil.createAssertionRevokeData(request.getRequest()); + HttpUtilResponse httpResponse = + HttpUtil.sendDeleteRequest(requestBody, BadgingUtil.getBadgrHeaders(), url); + String badgrResponseStr = httpResponse.getBody(); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpResponse.getStatusCode(), badgrResponseStr, BadgingJsonKey.BADGE_ASSERTION); + Response response = new Response(); + response.getResult().put(JsonKey.STATUS, JsonKey.SUCCESS); + targetObject = + TelemetryUtil.generateTargetObject( + (String) requestedData.get(BadgingJsonKey.ASSERTION_ID), + BadgingJsonKey.BADGE_ISSUER, + JsonKey.DELETE, + null); + TelemetryUtil.generateCorrelatedObject( + (String) requestedData.get(BadgingJsonKey.RECIPIENT_ID), + (String) requestedData.get(BadgingJsonKey.RECIPIENT_TYPE), + null, + correlatedObject); + TelemetryUtil.telemetryProcessingCall( + requestedData, targetObject, correlatedObject, request.getContext()); + return response; + } + + @Override + public Response deleteIssuer(Request request) throws IOException { + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + Map req = request.getRequest(); + String slug = (String) req.get(JsonKey.SLUG); + HttpUtilResponse httpResponse = + HttpUtil.sendDeleteRequest( + BadgingUtil.getBadgrHeaders(), BadgingUtil.getBadgeIssuerUrl(slug)); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + httpResponse.getStatusCode(), null, BadgingJsonKey.ISSUER); + Response response = new Response(); + // since the response from badger service contains " at beging and end so remove that from + // response string + response.put(JsonKey.MESSAGE, StringUtils.strip(httpResponse.getBody(), "\"")); + + targetObject = + TelemetryUtil.generateTargetObject(slug, BadgingJsonKey.BADGE_ISSUER, JsonKey.DELETE, null); + TelemetryUtil.telemetryProcessingCall( + req, targetObject, correlatedObject, request.getContext()); + return response; + } + + /** + * This method wu + * + * @param recipientId + * @param recipientType + * @return + */ + public static String getEmail(String recipientId, String recipientType) { + if (BadgingJsonKey.BADGE_TYPE_USER.equalsIgnoreCase(recipientType)) { + return getUserEmailFromDB(recipientId); + } else { + return verifyContent(recipientId); + } + } + + /** + * This method will provide user email id. + * + * @param userId String + * @return String + */ + private static String getUserEmailFromDB(String userId) { + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response response = + cassandraOperation.getRecordById(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userId); + List> user = (List>) response.get(JsonKey.RESPONSE); + if ((user == null) || user.isEmpty()) { + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), null, BadgingJsonKey.USER); + } + String email = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getDecryptionServiceInstance(null) + .decryptData((String) user.get(0).get(JsonKey.EMAIL)); + // verify the email format. + if (ProjectUtil.isEmailvalid(email)) { + return email; + } else { + return getDefaultEmail(); + } + } + + /** + * This method will take contentId and make EKstep api call to do the content validation, if + * content found inside Ekstep then it will take createdBy attribute and make sunbird api call to + * get the user email. if content not found then user will get 404 error. + * + * @param contentId String + * @return String + */ + private static String verifyContent(String contentId) { + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + String url = + ekStepBaseUrl + + PropertiesCache.getInstance().getProperty("sunbird_content_read") + + "/" + + contentId; + Map headerMap = new HashMap<>(); + + String header = ProjectUtil.getConfigValue(JsonKey.EKSTEP_AUTHORIZATION); + header = JsonKey.BEARER + header; + headerMap.put(JsonKey.AUTHORIZATION, header); + headerMap.put("Content-Type", "application/json"); + + try { + HttpUtilResponse response = HttpUtil.doGetRequest(url, headerMap); + if (response == null || response.getStatusCode() >= 300) { + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), null, BadgingJsonKey.CONTENT); + } + String userId = getUserIdFromContent(response.getBody()); + // some of the content won't have createdBy , so in that case + // take do the content validation only and used default + // set admin email + if (StringUtils.isBlank(userId)) { + return getDefaultEmail(); + } + try { + return getUserEmailFromDB(userId); + } catch (Exception e) { + // no need to throw the exception if content id is valid. + } + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + BadgingUtil.throwBadgeClassExceptionOnErrorStatus( + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), null, BadgingJsonKey.CONTENT); + } + return getDefaultEmail(); + } + + /** + * This method will provide default email set inside env. + * + * @return String + */ + private static String getDefaultEmail() { + String adminEmail = ProjectUtil.getConfigValue(BadgingJsonKey.SUNBIRD_INSTALLATION_EMAIL); + ProjectLogger.log("Default email is set to ==" + adminEmail); + return adminEmail; + } + + /** + * This method will read ekstep content body and get createdBy from that, which will internally + * refer to our user id. + * + * @param body Stirng + * @return String + */ + private static String getUserIdFromContent(String body) { + String userId = null; + try { + JSONObject object = new JSONObject(body); + JSONObject data = object.getJSONObject(JsonKey.RESULT); + JSONObject contentData = data.getJSONObject(JsonKey.CONTENT); + userId = contentData.getString(JsonKey.CREATED_BY); + } catch (JSONException e) { + ProjectLogger.log(e.getMessage(), e); + } + return userId; + } + + /** + * This method will validate the roles. + * + * @param roleList + */ + private static void validateRoles(List roleList) { + if (null == roleList || roleList.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.badgeRolesRequired.getErrorCode(), + ResponseCode.badgeRolesRequired.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + String result = Util.validateRoles(roleList); + if (!(JsonKey.SUCCESS.equalsIgnoreCase(result))) { + throw new ProjectCommonException( + ResponseCode.badgeRolesRequired.getErrorCode(), + ResponseCode.badgeRolesRequired.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgeAssertionValidator.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgeAssertionValidator.java new file mode 100644 index 0000000000..1b8aa0821c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgeAssertionValidator.java @@ -0,0 +1,94 @@ +package org.sunbird.badge.util; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.badge.model.BadgeClassExtension; +import org.sunbird.badge.service.BadgeClassExtensionService; +import org.sunbird.badge.service.impl.BadgeClassExtensionServiceImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.DbConstant; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; + +/** + * Class to provide badge assertion validation + * + * @author arvind + */ +public class BadgeAssertionValidator { + + private static BadgeClassExtensionService badgeClassExtensionService = + new BadgeClassExtensionServiceImpl(); + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + + /** + * Method to check whether root org of recipient and badge are same or not , if not same then + * throw exception. Current implementation validate root org if the recipient type is user + * + * @param recipientId represents the id of recipient to whom badge is going to assign + * @param recipientType represents the type of recipient .Possible values are - user, content + * @param badgeId represents the id of the badge + */ + public static void validateRootOrg(String recipientId, String recipientType, String badgeId) { + ProjectLogger.log("BadgeAssertionValidator:validateRootOrg: called", LoggerEnum.INFO.name()); + if (JsonKey.USER.equalsIgnoreCase(recipientType)) { + validateUserRootOrg(recipientId, badgeId); + } + } + + private static void validateUserRootOrg(String userId, String badgeId) { + String userRootOrg = getUserRootOrgId(userId); + String badgeRootOrg = getBadgeRootOrgId(badgeId); + ProjectLogger.log( + MessageFormat.format( + "BadgeAssertionValidator:validateUserRootOrg: user root org : {0} and org root org : {1}", + userRootOrg, badgeRootOrg), + LoggerEnum.INFO.name()); + if (!(StringUtils.equals(userRootOrg, badgeRootOrg))) { + ProjectLogger.log( + "BadgeAssertionValidator:validateUserRootOrg: root org mismatch " + userId, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.commonAttributeMismatch.getErrorCode(), + ResponseCode.commonAttributeMismatch.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + JsonKey.ROOT_ORG, + BadgingJsonKey.BADGE_TYPE_USER, + BadgingJsonKey.BADGE); + } + } + + private static String getUserRootOrgId(String userId) { + Response response = + cassandraOperation.getRecordById( + DbConstant.sunbirdKeyspaceName.getValue(), DbConstant.userTableName.getValue(), userId); + List> userResponse = + (List>) response.get(JsonKey.RESPONSE); + + if (CollectionUtils.isEmpty(userResponse)) { + ProjectLogger.log( + "BadgeAssertionValidator:getUserRootOrgId: user not found " + userId, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + Map userData = userResponse.get(0); + return (String) userData.get(JsonKey.ROOT_ORG_ID); + } + + private static String getBadgeRootOrgId(String badgeId) { + BadgeClassExtension badgeClassExtension = badgeClassExtensionService.get(badgeId); + return badgeClassExtension.getRootOrgId(); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgingMessage.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgingMessage.java new file mode 100644 index 0000000000..bde35e705e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgingMessage.java @@ -0,0 +1,16 @@ +package org.sunbird.badge.util; + +/** + * Messages used in badging module. Prefix error messages with "ERROR_" and success messages with + * "SUCCESS_". + * + * @author Manzarul + */ +public class BadgingMessage { + + public static final String ERROR_ISSUER_NOT_FOUND = "Issuer not found."; + public static final String ERROR_ASSERTION_NOT_FOUND = "Assertion not found."; + public static final String ERROR_BADGE_CLASS_NOT_FOUND = "Badge class not found."; + public static final String ERROR_USER_NOT_FOUND = "User not found."; + public static final String ERROR_CONTENT_NOT_FOUND = "Content not found."; +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgingUtil.java b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgingUtil.java new file mode 100644 index 0000000000..7a7eabff9e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/main/java/org/sunbird/badge/util/BadgingUtil.java @@ -0,0 +1,457 @@ +package org.sunbird.badge.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang.StringUtils; +import org.sunbird.badge.model.BadgeClassExtension; +import org.sunbird.badge.service.BadgingService; +import org.sunbird.badge.service.impl.BadgingFactory; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.MapperUtil; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +public class BadgingUtil { + + public static final String SUNBIRD_BADGR_SERVER_URL_DEFAULT = "http://localhost:8000"; + public static final String BADGING_AUTHORIZATION_FORMAT = "Token %s"; + public static final String SUNBIRD_BADGER_CREATE_ASSERTION_URL = + "/v1/issuer/issuers/{0}/badges/{1}/assertions"; + public static final String SUNBIRD_BADGER_GETASSERTION_URL = + "/v1/issuer/issuers/{0}/badges/{1}/assertions/{2}"; + public static final String SUNBIRD_BADGER_GETALLASSERTION_URL = + "/v1/issuer/issuers/{0}/badges/{1}/assertion"; + public static final String SUNBIRD_BADGER_REVOKE_URL = + "/v1/issuer/issuers/{0}/badges/{1}/assertion/{2}"; + private static final String DEFAULT_ISSUER_ID = "issuer-def"; + private static final String DEFAULT_BADGE_ID = "badge-def"; + private static PropertiesCache propertiesCache = PropertiesCache.getInstance(); + private static BadgingService service = BadgingFactory.getInstance(); + private static ObjectMapper mapper = new ObjectMapper(); + + public static String getBadgrBaseUrl() { + String badgerBaseUrl = SUNBIRD_BADGR_SERVER_URL_DEFAULT; + if (!StringUtils.isBlank(System.getenv(BadgingJsonKey.BADGER_BASE_URL))) { + badgerBaseUrl = System.getenv(BadgingJsonKey.BADGER_BASE_URL); + } else if (!StringUtils.isBlank(propertiesCache.readProperty(BadgingJsonKey.BADGER_BASE_URL))) { + badgerBaseUrl = propertiesCache.readProperty(BadgingJsonKey.BADGER_BASE_URL); + } + return badgerBaseUrl; + } + + public static String getBadgeClassUrl(String issuerSlug) { + return String.format("%s/v1/issuer/issuers/%s/badges", getBadgrBaseUrl(), issuerSlug); + } + + public static String getBadgeClassUrl(String issuerSlug, String badgeSlug) { + return String.format( + "%s/v1/issuer/issuers/%s/badges/%s", getBadgrBaseUrl(), issuerSlug, badgeSlug); + } + + public static Map getBadgrHeaders(boolean isContentTypeHeaderRequired) { + HashMap headers = new HashMap<>(); + + String authToken = System.getenv(BadgingJsonKey.BADGING_AUTHORIZATION_KEY); + if (StringUtils.isBlank(authToken)) { + authToken = propertiesCache.readProperty(BadgingJsonKey.BADGING_AUTHORIZATION_KEY); + } + if (!StringUtils.isBlank(authToken)) { + headers.put("Authorization", String.format(BADGING_AUTHORIZATION_FORMAT, authToken)); + } + headers.put("Accept", "application/json"); + + if (isContentTypeHeaderRequired) { + headers.put("Content-Type", "application/json"); + } + return headers; + } + + public static Map getBadgrHeaders() { + return getBadgrHeaders(true); + } + + public static String getLastSegment(String path) { + return path.substring(path.lastIndexOf('/') + 1); + } + + public static void prepareBadgeClassResponse( + Map inputMap, + BadgeClassExtension badgeClassExtension, + Map outputMap) + throws IOException { + MapperUtil.put(inputMap, BadgingJsonKey.CREATED_AT, outputMap, JsonKey.CREATED_DATE); + MapperUtil.put(inputMap, BadgingJsonKey.SLUG, outputMap, BadgingJsonKey.BADGE_ID); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_ID, outputMap, BadgingJsonKey.BADGE_ID_URL); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_ISSUER, outputMap, BadgingJsonKey.ISSUER_ID_URL); + + if (outputMap.containsKey(BadgingJsonKey.ISSUER_ID_URL)) { + outputMap.put( + BadgingJsonKey.ISSUER_ID, + getLastSegment((String) outputMap.get(BadgingJsonKey.ISSUER_ID_URL))); + } + + MapperUtil.put(inputMap, JsonKey.NAME, outputMap, JsonKey.NAME); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_DESCRIPTION, outputMap, JsonKey.DESCRIPTION); + MapperUtil.put(inputMap, JsonKey.IMAGE, outputMap, JsonKey.IMAGE); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_CRITERIA, outputMap, JsonKey.CRITERIA); + + MapperUtil.put(inputMap, BadgingJsonKey.RECIPIENT_COUNT, outputMap, JsonKey.RECIPIENT_COUNT); + + if (badgeClassExtension != null) { + outputMap.put(JsonKey.ROOT_ORG_ID, badgeClassExtension.getRootOrgId()); + outputMap.put(JsonKey.TYPE, badgeClassExtension.getType()); + outputMap.put(JsonKey.SUBTYPE, badgeClassExtension.getSubtype()); + outputMap.put(JsonKey.ROLES, badgeClassExtension.getRoles()); + } + } + + public static void prepareBadgeClassResponse( + String inputJson, BadgeClassExtension badgeClassExtension, Map outputMap) + throws IOException { + ObjectMapper mapper = new ObjectMapper(); + Map inputMap = mapper.readValue(inputJson, HashMap.class); + prepareBadgeClassResponse(inputMap, badgeClassExtension, outputMap); + } + + private static String createUri(Map map, String uri, int placeholderCount) { + if (placeholderCount == 0) { + return uri; + } else if (placeholderCount == 1) { + return MessageFormat.format(uri, (String) map.get(BadgingJsonKey.ISSUER_ID)); + } else if (placeholderCount == 2) { + return MessageFormat.format( + uri, map.get(BadgingJsonKey.ISSUER_ID), map.get(BadgingJsonKey.BADGE_ID)); + } else { + return MessageFormat.format( + uri, + map.get(BadgingJsonKey.ISSUER_ID) != null + ? map.get(BadgingJsonKey.ISSUER_ID) + : DEFAULT_ISSUER_ID, + map.get(BadgingJsonKey.BADGE_ID) != null + ? map.get(BadgingJsonKey.BADGE_ID) + : DEFAULT_BADGE_ID, + map.get(BadgingJsonKey.ASSERTION_ID)); + } + } + + /** + * This method will create url for badger server call. in badger url pattern is first placeholder + * is issuerSlug, 2nd badgeclass slug and 3rd badgeassertion slug + * + * @param map Map + * @param uri String + * @param placeholderCount int + * @return Stirng url + */ + public static String createBadgerUrl(Map map, String uri, int placeholderCount) { + String url = getBadgrBaseUrl() + createUri(map, uri, placeholderCount); + return url; + } + + /** + * This method will create assertion request data from requested map. + * + * @param map Map + * @return String + */ + public static String createAssertionReqData(Map map) { + + ObjectNode node = mapper.createObjectNode(); + ((ObjectNode) node) + .put(BadgingJsonKey.RECIPIENT_IDENTIFIER, (String) map.get(BadgingJsonKey.RECIPIENT_EMAIL)); + + if (!StringUtils.isBlank((String) map.get(BadgingJsonKey.EVIDENCE))) { + ((ObjectNode) node).put(BadgingJsonKey.EVIDENCE, (String) map.get(BadgingJsonKey.EVIDENCE)); + } + ((ObjectNode) node).put(BadgingJsonKey.CREATE_NOTIFICATION, false); + + try { + return mapper.writeValueAsString(node); + } catch (JsonProcessingException e) { + ProjectLogger.log( + "BadgingUtil :createAssertionReqData : JsonProcessingException " + e.getMessage(), e); + } + return null; + } + + public static void prepareBadgeIssuerResponse(String inputJson, Map outputMap) + throws IOException { + ObjectMapper mapper = new ObjectMapper(); + Map inputMap = mapper.readValue(inputJson, HashMap.class); + prepareBadgeIssuerResponse(inputMap, outputMap); + } + + public static void prepareBadgeIssuerResponse( + Map inputMap, Map outputMap) throws IOException { + MapperUtil.put(inputMap, BadgingJsonKey.CREATED_AT, outputMap, JsonKey.CREATED_DATE); + MapperUtil.put(inputMap, BadgingJsonKey.SLUG, outputMap, BadgingJsonKey.ISSUER_ID); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_ID, outputMap, BadgingJsonKey.ISSUER_ID_URL); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_URL, outputMap, BadgingJsonKey.ISSUER_URL); + MapperUtil.put(inputMap, JsonKey.NAME, outputMap, JsonKey.NAME); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_DESCRIPTION, outputMap, JsonKey.DESCRIPTION); + MapperUtil.put(inputMap, JsonKey.IMAGE, outputMap, JsonKey.IMAGE); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_EMAIL, outputMap, JsonKey.EMAIL); + } + + /** + * This method will create assertion revoke request data. + * + * @param map Map + * @return String + */ + public static String createAssertionRevokeData(Map map) { + + ObjectNode node = mapper.createObjectNode(); + ((ObjectNode) node) + .put("revocation_reason", (String) map.get(BadgingJsonKey.REVOCATION_REASON)); + try { + return mapper.writeValueAsString(node); + } catch (JsonProcessingException e) { + ProjectLogger.log( + "BadgingUtil :createAssertionRevokeData : JsonProcessingException ", LoggerEnum.ERROR); + } + return null; + } + + /** + * This method will create project common exception object for 400, 401, 403 , 404 and rest all + * will come under 500 server error. need to call this method incase of error only. + * + * @param statusCode int + * @return ProjectCommonException + */ + public static ProjectCommonException createExceptionForBadger(int statusCode) { + ProjectLogger.log("Badger is sending status code as " + statusCode, LoggerEnum.INFO.name()); + switch (statusCode) { + case 400: + return new ProjectCommonException( + ResponseCode.invalidData.getErrorCode(), + ResponseCode.invalidData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + case 401: + return new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ResponseCode.unAuthorized.getErrorMessage(), + ResponseCode.UNAUTHORIZED.getResponseCode()); + case 403: + return new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ResponseCode.unAuthorized.getErrorMessage(), + ResponseCode.UNAUTHORIZED.getResponseCode()); + case 404: + return new ProjectCommonException( + ResponseCode.resourceNotFound.getErrorCode(), + ResponseCode.resourceNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + default: + return new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + public static void throwBadgeClassExceptionOnErrorStatus( + int statusCode, String errorMsg, String objectType) throws ProjectCommonException { + ProjectLogger.log( + "throwBadgeClassExceptionOnErrorStatus called with statusCode = " + statusCode, + LoggerEnum.ERROR); + if (statusCode < 200 || statusCode > 300) { + ResponseCode customError; + String specificErrorMsg; + switch (statusCode) { + case 400: + customError = ResponseCode.customClientError; + specificErrorMsg = errorMsg != null ? errorMsg : ""; + break; + case 404: + customError = ResponseCode.customResourceNotFound; + errorMsg = createCustomMessageBasedOnObjectType(objectType); + specificErrorMsg = + StringUtils.isNotEmpty(errorMsg) + ? errorMsg + : ResponseCode.resourceNotFound.getErrorMessage(); + break; + default: + customError = ResponseCode.customServerError; + specificErrorMsg = + errorMsg != null ? errorMsg : ResponseCode.internalError.getErrorMessage(); + break; + } + + if (StringUtils.isNotBlank(specificErrorMsg)) { + // Remove start and end double quotes (if any) from error message + specificErrorMsg = specificErrorMsg.replaceAll("^\"|\"$", ""); + } + + throw new ProjectCommonException( + customError.getErrorCode(), customError.getErrorMessage(), statusCode, specificErrorMsg); + } + } + + private static String createCustomMessageBasedOnObjectType(String objectType) { + String message = ""; + if (StringUtils.isBlank(objectType)) { + return message; + } + switch (objectType) { + case BadgingJsonKey.ISSUER: + message = BadgingMessage.ERROR_ISSUER_NOT_FOUND; + break; + case BadgingJsonKey.BADGE_CLASS: + message = BadgingMessage.ERROR_BADGE_CLASS_NOT_FOUND; + break; + case BadgingJsonKey.BADGE_ASSERTION: + message = BadgingMessage.ERROR_ASSERTION_NOT_FOUND; + break; + case BadgingJsonKey.USER: + message = BadgingMessage.ERROR_USER_NOT_FOUND; + break; + case BadgingJsonKey.CONTENT: + message = BadgingMessage.ERROR_CONTENT_NOT_FOUND; + break; + } + return message; + } + + /** + * This method will get the response from badging server and create proper map (meta data) to + * store either with user or content. + * + * @param reqMap Map + * @return Map + */ + public static Map createBadgeNotifierMap(Map reqMap) { + Map outerMap = new HashMap<>(); + Map innerMap = new HashMap<>(); + innerMap.put(BadgingJsonKey.ASSERTION_ID, reqMap.get(BadgingJsonKey.ASSERTION_ID)); + innerMap.put(BadgingJsonKey.BADGE_CLASS_ID, reqMap.get(BadgingJsonKey.BADGE_CLASS_ID)); + innerMap.put(BadgingJsonKey.ISSUER_ID, reqMap.get(BadgingJsonKey.ISSUER_ID)); + innerMap.put(BadgingJsonKey.BADGE_CLASS_IMAGE, reqMap.get(BadgingJsonKey.ASSERTION_IMAGE_URL)); + innerMap.put(JsonKey.STATUS, BadgeStatus.active.name()); + innerMap.put( + BadgingJsonKey.CREATED_TS, + new java.sql.Timestamp(Calendar.getInstance().getTime().getTime())); + // now make a badgr call to collect badgeClassName + Request request = new Request(); + request.getRequest().put(BadgingJsonKey.ISSUER_ID, reqMap.get(BadgingJsonKey.ISSUER_ID)); + request + .getRequest() + .put(BadgingJsonKey.BADGE_CLASS_ID, reqMap.get(BadgingJsonKey.BADGE_CLASS_ID)); + try { + Response response = + service.getBadgeClassDetails((String) reqMap.get(BadgingJsonKey.BADGE_CLASS_ID)); + innerMap.put(BadgingJsonKey.BADGE_CLASS_NANE, response.getResult().get(JsonKey.NAME)); + } catch (ProjectCommonException e) { + ProjectLogger.log(e.getMessage(), e); + } + outerMap.put(BadgingJsonKey.BADGE_ASSERTION, innerMap); + return outerMap; + } + + /** + * This method will take response data from badger server as input map and then prepare a new map + * as outPut map by changing the key and some values. + * + * @param inputMap Map + * @param outPutMap Map + * @return Map + */ + public static Map prepareAssertionResponse( + Map inputMap, Map outPutMap) { + MapperUtil.put(inputMap, BadgingJsonKey.CREATED_AT, outPutMap, JsonKey.CREATED_DATE); + MapperUtil.put( + inputMap, BadgingJsonKey.JSON_ISSUED_ON, outPutMap, BadgingJsonKey.ASSERTION_DATE); + MapperUtil.put(inputMap, BadgingJsonKey.SLUG, outPutMap, BadgingJsonKey.ASSERTION_ID); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_ID, outPutMap, BadgingJsonKey.ASSERTION_ID_URL); + MapperUtil.put(inputMap, JsonKey.IMAGE, outPutMap, BadgingJsonKey.ASSERTION_IMAGE_URL); + MapperUtil.put(inputMap, BadgingJsonKey.BADGE_CLASS, outPutMap, BadgingJsonKey.BADGE_ID_URL); + if (outPutMap.containsKey(BadgingJsonKey.BADGE_ID_URL)) { + outPutMap.put( + BadgingJsonKey.BADGE_ID, + getLastSegment((String) outPutMap.get(BadgingJsonKey.BADGE_ID_URL))); + } + MapperUtil.put(inputMap, BadgingJsonKey.ISSUER, outPutMap, BadgingJsonKey.ISSUER_ID_URL); + if (outPutMap.containsKey(BadgingJsonKey.ISSUER_ID_URL)) { + outPutMap.put( + BadgingJsonKey.ISSUER_ID, + getLastSegment((String) outPutMap.get(BadgingJsonKey.ISSUER_ID_URL))); + } + MapperUtil.put(inputMap, BadgingJsonKey.JSON_RECIPIENT, outPutMap, BadgingJsonKey.RECIPIENT); + MapperUtil.put( + inputMap, BadgingJsonKey.RECIPIENT_IDENTIFIER, outPutMap, BadgingJsonKey.RECIPIENT_EMAIL); + MapperUtil.put(inputMap, BadgingJsonKey.JSON_VERIFY, outPutMap, BadgingJsonKey.VERIFY); + MapperUtil.put(inputMap, BadgingJsonKey.REVOKED, outPutMap, BadgingJsonKey.REVOKED); + MapperUtil.put( + inputMap, + BadgingJsonKey.REVOCATION_REASON_BADGE, + outPutMap, + BadgingJsonKey.REVOCATION_REASON); + return outPutMap; + } + + /** + * This method will get the response from badging server and create proper map (meta data) to + * remove badge assertion either from user or content. + * + * @param reqMap Map + * @return Map + */ + public static Map createRevokeBadgeNotifierMap(Map reqMap) { + Map outerMap = new HashMap<>(); + Map innerMap = new HashMap<>(); + innerMap.put(BadgingJsonKey.ASSERTION_ID, reqMap.get(BadgingJsonKey.ASSERTION_ID)); + innerMap.put(BadgingJsonKey.BADGE_CLASS_ID, reqMap.get(BadgingJsonKey.BADGE_CLASS_ID)); + innerMap.put(BadgingJsonKey.ISSUER_ID, reqMap.get(BadgingJsonKey.ISSUER_ID)); + outerMap.put(BadgingJsonKey.BADGE_ASSERTION, innerMap); + return outerMap; + } + + public enum BadgeStatus { + active, + revoked; + } + + /** + * Badger is having some issues , to get badge assertion data , badger required issuerId, badgeId, + * assertionId but internally it's checking only assertionId other's values can be any thing and + * it will provide the response. so to avoid this we have the check request issuerId, badgeId need + * to be same as response data. + * + * @param issuerId String + * @param badgeId String + * @param resp Map + * @return boolean + */ + public static boolean matchAssertionData( + String issuerId, String badgeId, Map resp) { + if (StringUtils.isBlank(issuerId) || StringUtils.isBlank(badgeId)) { + return false; + } + if (issuerId.equals(resp.get(BadgingJsonKey.ISSUER_ID)) + && badgeId.equals(resp.get(BadgingJsonKey.BADGE_CLASS_ID))) { + return true; + } + return false; + } + + public static String getBadgeIssuerUrl() { + return String.format("%s/v1/issuer/issuers", getBadgrBaseUrl()); + } + + public static String getBadgeIssuerUrl(String slug) { + return String.format("%s/v1/issuer/issuers/%s", getBadgrBaseUrl(), slug); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeAssertionActorTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeAssertionActorTest.java new file mode 100644 index 0000000000..b6e9d1857f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeAssertionActorTest.java @@ -0,0 +1,143 @@ +package org.sunbird.badge.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.HashMap; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.badge.BadgeOperations; +import org.sunbird.badge.service.BadgingService; +import org.sunbird.badge.service.impl.BadgingFactory; +import org.sunbird.badge.service.impl.BadgrServiceImpl; +import org.sunbird.badge.util.BadgeAssertionValidator; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author arvind */ +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +@PrepareForTest({BadgeAssertionValidator.class, BadgingFactory.class}) +public class BadgeAssertionActorTest { + + private static BadgrServiceImpl mockBadgingService; + private static BadgingService badgingService; + + private static String ASSERTION_ID = "badge_assertion_01"; + private static String BADGE_CLASS_ID = "badge_class_01"; + private static String ISSUER_ID = "badge_issuer_01"; + private static String ASSERTION_IMAGE_URL = "badge_image_url_01"; + private static String RECIPIENT_ID = "recipient_01"; + private static String RECIPIENT_TYPE = "user"; + private static String BADGE_ID = "badge_01"; + + private static ActorSystem system; + private static final Props props = Props.create(BadgeAssertionActor.class); + + @BeforeClass + public static void setUp() { + system = ActorSystem.create("system"); + + mockBadgingService = mock(BadgrServiceImpl.class); + badgingService = mock(BadgrServiceImpl.class); + + PowerMockito.mockStatic(BadgingFactory.class); + when(BadgingFactory.getInstance()).thenReturn(badgingService); + } + + @Before + public void beforeTest() { + PowerMockito.mockStatic(BadgeAssertionValidator.class); + } + + @Test + @Ignore + public void testCreateAssertionWithMatchRootOrgOfUserAndBadge() throws Exception { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Response response = new Response(); + when(badgingService.getBadgeClassDetails(Mockito.anyObject())).thenReturn(response); + when(badgingService.badgeAssertion(Mockito.anyObject())).thenReturn(response); + PowerMockito.doNothing() + .when( + BadgeAssertionValidator.class, + "validateRootOrg", + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString()); + + subject.tell(getBadgeAssertionRequest(), probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertNotNull(res); + } + + @Test + public void testCreateAssertionWithMismatchRootOrgOfUserAndBadge() throws Exception { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Response response = new Response(); + when(badgingService.getBadgeClassDetails(Mockito.anyObject())).thenReturn(response); + when(badgingService.badgeAssertion(Mockito.anyObject())).thenReturn(response); + + ProjectCommonException projectCommonException = + new ProjectCommonException( + ResponseCode.commonAttributeMismatch.getErrorCode(), + ResponseCode.commonAttributeMismatch.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + JsonKey.ROOT_ORG, + BadgingJsonKey.BADGE_TYPE_USER, + BadgingJsonKey.BADGE); + PowerMockito.doThrow(projectCommonException) + .when( + BadgeAssertionValidator.class, + "validateRootOrg", + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString()); + + subject.tell(getBadgeAssertionRequest(), probe.getRef()); + ProjectCommonException exception = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertNotNull(exception); + Assert.assertEquals(exception.getResponseCode(), ResponseCode.CLIENT_ERROR.getResponseCode()); + Assert.assertEquals(exception.getCode(), ResponseCode.commonAttributeMismatch.getErrorCode()); + } + + private Request getBadgeAssertionRequest() { + Request reqObj = new Request(); + reqObj.setOperation(BadgeOperations.createBadgeAssertion.name()); + HashMap innerMap = new HashMap<>(); + innerMap.put(BadgingJsonKey.ASSERTION_ID, ASSERTION_ID); + innerMap.put(BadgingJsonKey.BADGE_CLASS_ID, BADGE_CLASS_ID); + innerMap.put(BadgingJsonKey.ISSUER_ID, ISSUER_ID); + innerMap.put(BadgingJsonKey.ASSERTION_IMAGE_URL, ASSERTION_IMAGE_URL); + innerMap.put(BadgingJsonKey.RECIPIENT_ID, RECIPIENT_ID); + innerMap.put(BadgingJsonKey.RECIPIENT_TYPE, RECIPIENT_TYPE); + innerMap.put(BadgingJsonKey.BADGE_ID, BADGE_ID); + reqObj.getRequest().putAll(innerMap); + + return reqObj; + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeClassActorTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeClassActorTest.java new file mode 100644 index 0000000000..35e78ce822 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeClassActorTest.java @@ -0,0 +1,160 @@ +package org.sunbird.badge.actors; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.badge.service.impl.BadgrServiceImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingActorOperations; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import scala.concurrent.duration.FiniteDuration; + +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class BadgeClassActorTest { + private static final FiniteDuration ACTOR_MAX_WAIT_DURATION = duration("100 second"); + + private TestKit probe; + private ActorRef subject; + + private Request actorMessage; + + private BadgrServiceImpl mockBadgingService; + private ProjectCommonException resourceNotFoundException; + + @Before + public void setUp() { + ActorSystem system = ActorSystem.create("system"); + probe = new TestKit(system); + + mockBadgingService = PowerMockito.mock(BadgrServiceImpl.class); + + Props props = Props.create(BadgeClassActor.class, mockBadgingService); + subject = system.actorOf(props); + + actorMessage = new Request(); + + ResponseCode error = ResponseCode.resourceNotFound; + resourceNotFoundException = + new ProjectCommonException( + error.getErrorCode(), error.getErrorMessage(), error.getResponseCode()); + } + + @Test + public void testCreateBadgeClassSuccess() { + PowerMockito.when(mockBadgingService.createBadgeClass(actorMessage)).thenReturn(new Response()); + + actorMessage.setOperation(BadgingActorOperations.CREATE_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + Response response = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response); + } + + @Test + public void testCreateBadgeClassFailure() { + PowerMockito.when(mockBadgingService.createBadgeClass(actorMessage)) + .thenThrow(resourceNotFoundException); + + actorMessage.setOperation(BadgingActorOperations.CREATE_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + ProjectCommonException exception = + probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, ProjectCommonException.class); + Assert.assertTrue(null != exception); + } + + @Test + public void testGetBadgeClassSuccess() { + PowerMockito.when(mockBadgingService.getBadgeClassDetails(Mockito.anyString())) + .thenReturn(new Response()); + + actorMessage.setOperation(BadgingActorOperations.GET_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + Response response = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response); + } + + @Test + public void testGetBadgeClassFailure() { + PowerMockito.when(mockBadgingService.getBadgeClassDetails(Mockito.anyString())) + .thenThrow(resourceNotFoundException); + + actorMessage.setOperation(BadgingActorOperations.GET_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + ProjectCommonException exception = + probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, ProjectCommonException.class); + Assert.assertTrue(null != exception); + } + + @Test + public void testSearchBadgeClassSuccess() { + PowerMockito.when(mockBadgingService.searchBadgeClass(actorMessage)).thenReturn(new Response()); + + actorMessage.setOperation(BadgingActorOperations.SEARCH_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + Response response = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response); + } + + @Test + public void testSearchBadgeClassFailure() { + PowerMockito.when(mockBadgingService.searchBadgeClass(actorMessage)) + .thenThrow(resourceNotFoundException); + + actorMessage.setOperation(BadgingActorOperations.SEARCH_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + ProjectCommonException exception = + probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, ProjectCommonException.class); + Assert.assertTrue(null != exception); + } + + @Test + public void testDeleteBadgeClassSuccess() { + PowerMockito.when(mockBadgingService.removeBadgeClass(actorMessage)).thenReturn(new Response()); + + actorMessage.setOperation(BadgingActorOperations.DELETE_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + Response response = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response); + } + + @Test + public void testDeleteBadgeClassFailure() { + PowerMockito.when(mockBadgingService.removeBadgeClass(actorMessage)) + .thenThrow(resourceNotFoundException); + + actorMessage.setOperation(BadgingActorOperations.DELETE_BADGE_CLASS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + + ProjectCommonException exception = + probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, ProjectCommonException.class); + Assert.assertTrue(null != exception); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeIssuerActorTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeIssuerActorTest.java new file mode 100644 index 0000000000..bb75de16ab --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeIssuerActorTest.java @@ -0,0 +1,149 @@ +package org.sunbird.badge.actors; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.powermock.api.mockito.PowerMockito; +import org.sunbird.badge.BadgeOperations; +import org.sunbird.badge.service.impl.BadgrServiceImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.HttpUtilResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import scala.concurrent.duration.FiniteDuration; + +/** Created by arvind on 15/3/18. */ +public class BadgeIssuerActorTest { + + private static final FiniteDuration ACTOR_MAX_WAIT_DURATION = duration("100 second"); + + private ActorSystem system; + private Props props; + + private TestKit probe; + private ActorRef subject; + + private Request actorMessage; + + BadgrServiceImpl mockBadgingService; + ProjectCommonException resourceNotFoundException; + + @Before + public void setUp() { + system = ActorSystem.create("system"); + probe = new TestKit(system); + mockBadgingService = PowerMockito.mock(BadgrServiceImpl.class); + props = Props.create(BadgeIssuerActor.class, mockBadgingService); + subject = system.actorOf(props); + actorMessage = new Request(); + ResponseCode error = ResponseCode.resourceNotFound; + resourceNotFoundException = + new ProjectCommonException( + error.getErrorCode(), error.getErrorMessage(), error.getResponseCode()); + } + + @Test + public void testCreateBadgeIssuerSuccess() throws IOException { + Response response = new Response(); + + response.put(JsonKey.RESPONSE, createHttpUtilRes(200, mapToJson(createBadgeIssuerResponse()))); + + PowerMockito.when(mockBadgingService.createIssuer(actorMessage)).thenReturn(response); + actorMessage.setOperation(BadgeOperations.createBadgeIssuer.name()); + subject.tell(actorMessage, probe.getRef()); + Response resp = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != resp); + } + + @Test + public void testGetBadgeIssuer() throws IOException { + Response response = new Response(); + + response.put(JsonKey.RESPONSE, createHttpUtilRes(200, mapToJson(createBadgeIssuerResponse()))); + + PowerMockito.when(mockBadgingService.getIssuerDetails(actorMessage)).thenReturn(response); + actorMessage.setOperation(BadgeOperations.getBadgeIssuer.name()); + subject.tell(actorMessage, probe.getRef()); + Response resp = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != resp); + } + + @Test + public void testGetListBadgeIssuer() throws IOException { + Response response = new Response(); + + List> issuersList = new ArrayList<>(); + issuersList.add(createBadgeIssuerResponse()); + + response.put(JsonKey.RESPONSE, createHttpUtilRes(200, listOfMapToJson(issuersList))); + PowerMockito.when(mockBadgingService.getIssuerList(actorMessage)).thenReturn(response); + actorMessage.setOperation(BadgeOperations.getAllIssuer.name()); + subject.tell(actorMessage, probe.getRef()); + Response resp = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != resp); + } + + @Test + public void testDeleteBadgeIssuer() throws IOException { + Response response = new Response(); + response.put(JsonKey.RESPONSE, createHttpUtilRes(200, "Issuer slug_01 deleted successfully .")); + + PowerMockito.when(mockBadgingService.deleteIssuer(actorMessage)).thenReturn(response); + actorMessage.setOperation(BadgeOperations.deleteIssuer.name()); + subject.tell(actorMessage, probe.getRef()); + Response resp = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != resp); + } + + private static String mapToJson(Map map) { + ObjectMapper mapperObj = new ObjectMapper(); + String jsonResp = ""; + try { + jsonResp = mapperObj.writeValueAsString(map); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + return jsonResp; + } + + private static String listOfMapToJson(List list) { + ObjectMapper mapperObj = new ObjectMapper(); + String jsonResp = ""; + try { + jsonResp = mapperObj.writeValueAsString(list); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + return jsonResp; + } + + private static Map createBadgeIssuerResponse() { + Map bodyMap = new HashMap<>(); + bodyMap.put(BadgingJsonKey.SLUG, "slug_01"); + return bodyMap; + } + + private static HttpUtilResponse createHttpUtilRes(int statusCode, String body) { + + HttpUtilResponse httpUtilResponse = new HttpUtilResponse(); + httpUtilResponse.setStatusCode(statusCode); + httpUtilResponse.setBody(body); + return httpUtilResponse; + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeNotifierTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeNotifierTest.java new file mode 100644 index 0000000000..e56fd94fee --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/BadgeNotifierTest.java @@ -0,0 +1,122 @@ +package org.sunbird.badge.actors; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.badge.BadgeOperations; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.learner.util.Util; + +/** @author Mahesh Kumar Gangula */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({Util.class}) +@PowerMockIgnore("javax.management.*") +@Ignore +public class BadgeNotifierTest { + + private static ActorSystem system; + private static TestKit probe; + private static ActorRef actor; + + @BeforeClass + public static void setUp() throws Exception { + system = ActorSystem.create("system"); + probe = new TestKit(system); + actor = system.actorOf(Props.create(BadgeNotifier.class)); + } + + @Test + public void checkTelemetryKeyFailure() throws Exception { + + String telemetryEnvKey = "user"; + Request request = new Request(); + request.setOperation(BadgeOperations.assignBadgeMessage.name()); + + PowerMockito.mockStatic(Util.class); + PowerMockito.doNothing() + .when( + Util.class, + "initializeContext", + Mockito.any(Request.class), + Mockito.eq(telemetryEnvKey)); + + Map data = new HashMap(); + request.setRequest(data); + data.put(JsonKey.ID, "test_content"); + data.put(BadgingJsonKey.BADGE_ASSERTION, new HashMap<>()); + actor.tell(request, probe.getRef()); + probe.expectMsgClass(Response.class); + Assert.assertTrue(!(telemetryEnvKey.charAt(0) >= 65 && telemetryEnvKey.charAt(0) <= 90)); + } + + @Test + public void invalidOperation() { + Request request = new Request(); + request.setOperation("invalidOperation"); + actor.tell(request, probe.getRef()); + ProjectCommonException ex = probe.expectMsgClass(ProjectCommonException.class); + Assert.assertTrue(ResponseMessage.Message.INVALID_OPERATION_NAME.equals(ex.getMessage())); + Assert.assertTrue(ResponseMessage.Key.INVALID_OPERATION_NAME.equals(ex.getCode())); + } + + @Test + public void assignBadgeWithoutObjectType() { + Request request = new Request(); + request.setOperation(BadgeOperations.assignBadgeMessage.name()); + Map data = new HashMap(); + request.setRequest(data); + data.put(JsonKey.ID, "test_content"); + data.put(BadgingJsonKey.BADGE_ASSERTION, new HashMap<>()); + actor.tell(request, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + Object obj = res.getResult(); + // res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res); + } + + @Test + public void assignBadgeWithoutId() { + Request request = new Request(); + request.setOperation(BadgeOperations.assignBadgeMessage.name()); + Map data = new HashMap(); + request.setRequest(data); + data.put(JsonKey.OBJECT_TYPE, "Content"); + data.put(BadgingJsonKey.BADGE_ASSERTION, new HashMap<>()); + actor.tell(request, probe.getRef()); + ProjectCommonException ex = probe.expectMsgClass(ProjectCommonException.class); + Assert.assertTrue("Please provide content id.".equals(ex.getMessage())); + } + + @Test + public void assignBadgeWithout() { + Request request = new Request(); + request.setOperation(BadgeOperations.assignBadgeMessage.name()); + Map data = new HashMap(); + request.setRequest(data); + data.put(JsonKey.OBJECT_TYPE, "Content"); + data.put(JsonKey.ID, "test_content"); + actor.tell(request, probe.getRef()); + ProjectCommonException ex = probe.expectMsgClass(ProjectCommonException.class); + Assert.assertTrue("Please provide badge details.".equals(ex.getMessage())); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/UserBadgeAssertionTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/UserBadgeAssertionTest.java new file mode 100644 index 0000000000..72c2df672b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/actors/UserBadgeAssertionTest.java @@ -0,0 +1,227 @@ +package org.sunbird.badge.actors; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.badge.BadgeOperations; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.learner.util.Util.DbInfo; +import scala.concurrent.Promise; +import scala.concurrent.duration.FiniteDuration; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + EsClientFactory.class, + Util.class, + ElasticSearchHelper.class, + ElasticSearchRestHighImpl.class +}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class UserBadgeAssertionTest { + + @SuppressWarnings("deprecation") + private static final FiniteDuration ACTOR_MAX_WAIT_DURATION = duration("100 second"); + + private ActorSystem system; + private TestKit probe; + private ActorRef subject; + private Request actorMessage; + private CassandraOperation cassandraOperation; + private DbInfo dbInfo = Util.dbInfoMap.get(BadgingJsonKey.USER_BADGE_ASSERTION_DB); + private HashMap tempMap; + private Map result; + private Map badge; + private ElasticSearchService esService; + + @Before + public void setUp() { + system = ActorSystem.create("system"); + probe = new TestKit(system); + actorMessage = new Request(); + badge = new HashMap<>(); + badge.put(BadgingJsonKey.ASSERTION_ID, "aslug123"); + badge.put(BadgingJsonKey.BADGE_ID, "bslug123"); + badge.put(BadgingJsonKey.ISSUER_ID, "islug123"); + badge.put(BadgingJsonKey.BADGE_CLASS_NANE, "cert123"); + badge.put( + BadgingJsonKey.BADGE_CLASS_IMAGE, + "http://localhost:8000/public/badges/java-se-8-programmer/image"); + badge.put(BadgingJsonKey.CREATED_TS, "1520586333"); + + Map req = new HashMap<>(); + req.put(JsonKey.ID, "userId-123"); + req.put(BadgingJsonKey.BADGE_ASSERTION, badge); + actorMessage.setRequest(req); + tempMap = new HashMap<>(); + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + esService = PowerMockito.mock(ElasticSearchRestHighImpl.class); + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + PowerMockito.when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + Props props = Props.create(UserBadgeAssertion.class); + subject = system.actorOf(props); + } + + @Test + public void checkTelemetryKeyFailure() throws Exception { + result = new HashMap<>(); + String telemetryEnvKey = "user"; + Promise promise = Futures.promise(); + promise.success(true); + PowerMockito.when( + esService.update(ProjectUtil.EsType.user.getTypeName(), "userId-123", tempMap)) + .thenReturn(promise.future()); + + PowerMockito.mockStatic(Util.class); + PowerMockito.doNothing() + .when( + Util.class, + "initializeContext", + Mockito.any(Request.class), + Mockito.eq(telemetryEnvKey)); + List> badgeAssertionsList = new ArrayList<>(); + Map tempMap = new HashMap<>(); + tempMap.put(JsonKey.ID, getUserBadgeAssertionId(badge)); + badgeAssertionsList.add(tempMap); + result.put(BadgingJsonKey.BADGE_ASSERTIONS, badgeAssertionsList); + Promise> promise1 = Futures.promise(); + promise1.success(result); + PowerMockito.when( + esService.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), "userId-123")) + .thenReturn(promise1.future()); + PowerMockito.when( + cassandraOperation.insertRecord(dbInfo.getKeySpace(), dbInfo.getTableName(), tempMap)) + .thenReturn(new Response()); + + actorMessage.setOperation(BadgeOperations.assignBadgeToUser.name()); + + subject.tell(actorMessage, probe.getRef()); + + probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(!(telemetryEnvKey.charAt(0) >= 65 && telemetryEnvKey.charAt(0) <= 90)); + } + + @Test + public void testAssignBadgeToUser() { + result = new HashMap<>(); + Promise promise = Futures.promise(); + promise.success(false); + PowerMockito.when( + esService.update(ProjectUtil.EsType.user.getTypeName(), "userId-123", tempMap)) + .thenReturn(promise.future()); + List> badgeAssertionsList = new ArrayList<>(); + Map tempMap = new HashMap<>(); + tempMap.put(JsonKey.ID, getUserBadgeAssertionId(badge)); + badgeAssertionsList.add(tempMap); + result.put(BadgingJsonKey.BADGE_ASSERTIONS, badgeAssertionsList); + Promise> promise1 = Futures.promise(); + promise1.success(result); + PowerMockito.when( + esService.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), "userId-123")) + .thenReturn(promise1.future()); + PowerMockito.when( + cassandraOperation.insertRecord(dbInfo.getKeySpace(), dbInfo.getTableName(), tempMap)) + .thenReturn(new Response()); + + actorMessage.setOperation(BadgeOperations.assignBadgeToUser.name()); + + subject.tell(actorMessage, probe.getRef()); + + Response response = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response); + } + + @Test + public void testAssignBadgeToUser2() { + Promise promise = Futures.promise(); + promise.success(false); + PowerMockito.when( + esService.update(ProjectUtil.EsType.user.getTypeName(), "userId-123", tempMap)) + .thenReturn(promise.future()); + result = new HashMap<>(); + List> badgeAssertionsList = new ArrayList<>(); + Map tempMap = new HashMap<>(); + tempMap.put(JsonKey.ID, "132"); + badgeAssertionsList.add(tempMap); + result.put(BadgingJsonKey.BADGE_ASSERTIONS, badgeAssertionsList); + Promise> promise1 = Futures.promise(); + promise1.success(result); + PowerMockito.when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise1.future()); + + PowerMockito.when( + cassandraOperation.insertRecord(dbInfo.getKeySpace(), dbInfo.getTableName(), tempMap)) + .thenReturn(new Response()); + + actorMessage.setOperation(BadgeOperations.assignBadgeToUser.name()); + + subject.tell(actorMessage, probe.getRef()); + + Response response = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response); + } + + @Test + public void testRevokeBadgeToUser() { + Promise promise = Futures.promise(); + promise.success(true); + PowerMockito.when( + esService.update(ProjectUtil.EsType.user.getTypeName(), "userId-123", tempMap)) + .thenReturn(promise.future()); + + PowerMockito.when( + cassandraOperation.deleteRecord( + dbInfo.getKeySpace(), dbInfo.getTableName(), "userId-123")) + .thenReturn(new Response()); + + actorMessage.setOperation(BadgeOperations.revokeBadgeFromUser.name()); + + subject.tell(actorMessage, probe.getRef()); + + Response response = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response); + } + + /** + * @param badge + * @return String + */ + private String getUserBadgeAssertionId(Map badge) { + return ((String) badge.get(BadgingJsonKey.ASSERTION_ID) + + JsonKey.PRIMARY_KEY_DELIMETER + + (String) badge.get(BadgingJsonKey.ISSUER_ID) + + JsonKey.PRIMARY_KEY_DELIMETER + + (String) badge.get(BadgingJsonKey.BADGE_CLASS_ID)); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgeClassExtensionServiceImplTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgeClassExtensionServiceImplTest.java new file mode 100644 index 0000000000..20c1cd50ca --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgeClassExtensionServiceImplTest.java @@ -0,0 +1,206 @@ +package org.sunbird.badge.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.badge.model.BadgeClassExtension; +import org.sunbird.badge.service.BadgeClassExtensionService; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({CassandraOperationImpl.class}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class BadgeClassExtensionServiceImplTest { + private CassandraOperation mockDBService; + private BadgeClassExtensionService badgeClassExtensionServiceImpl; + + private static final String VALUE_BADGE_ID = "java-se-8-programmer"; + private static final String VALUE_ISSUER_ID = "oracle-university"; + private static final String VALUE_ROOT_ORG_ID = "AP"; + private static final String VALUE_TYPE = "user"; + private static final String VALUE_SUBTYPE = "award"; + private static final ArrayList VALUE_ROLES_LIST = + new ArrayList<>(Arrays.asList("roleId1")); + + @Before + public void setUp() { + mockDBService = PowerMockito.mock(CassandraOperationImpl.class); + badgeClassExtensionServiceImpl = new BadgeClassExtensionServiceImpl(mockDBService); + } + + @Test + public void testSaveSuccess() { + PowerMockito.when(mockDBService.upsertRecord(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(new Response()); + + boolean thrown = false; + + try { + BadgeClassExtension badgeClassExtension = + new BadgeClassExtension( + VALUE_BADGE_ID, + VALUE_ISSUER_ID, + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST); + badgeClassExtensionServiceImpl.save(badgeClassExtension); + } catch (Exception e) { + thrown = true; + } + + Assert.assertEquals(false, thrown); + } + + @Test + public void testGetSuccess() { + Response response = new Response(); + response.put( + JsonKey.RESPONSE, new ArrayList>(Arrays.asList(new HashMap<>()))); + + PowerMockito.when( + mockDBService.getRecordById(Mockito.any(), Mockito.any(), Mockito.anyString())) + .thenReturn(response); + + BadgeClassExtension badgeClassExtension = badgeClassExtensionServiceImpl.get(VALUE_BADGE_ID); + + Assert.assertTrue(null != badgeClassExtension); + } + + @Test + public void testSearchSuccessNonEmpty() { + HashMap badgeMap = new HashMap<>(); + badgeMap.put(JsonKey.ID, VALUE_BADGE_ID); + badgeMap.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + badgeMap.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + badgeMap.put(JsonKey.TYPE, VALUE_TYPE); + badgeMap.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + badgeMap.put(JsonKey.ROLES, VALUE_ROLES_LIST); + + Response response = new Response(); + response.put(JsonKey.RESPONSE, new ArrayList>(Arrays.asList(badgeMap))); + + PowerMockito.when( + mockDBService.getRecordsByProperties(Mockito.any(), Mockito.any(), Mockito.anyMap())) + .thenReturn(response); + + List badgeClassExtList = + badgeClassExtensionServiceImpl.search( + new ArrayList<>(), + new ArrayList<>(), + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST); + + Assert.assertTrue(null != badgeClassExtList); + Assert.assertEquals(1, badgeClassExtList.size()); + Assert.assertEquals(VALUE_BADGE_ID, badgeClassExtList.get(0).getBadgeId()); + Assert.assertEquals(VALUE_ROOT_ORG_ID, badgeClassExtList.get(0).getRootOrgId()); + Assert.assertEquals(VALUE_TYPE, badgeClassExtList.get(0).getType()); + Assert.assertEquals(VALUE_SUBTYPE, badgeClassExtList.get(0).getSubtype()); + Assert.assertEquals(VALUE_ROLES_LIST, badgeClassExtList.get(0).getRoles()); + } + + @Test + public void testSearchSuccessEmpty() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, new ArrayList>()); + + PowerMockito.when( + mockDBService.getRecordsByProperties(Mockito.any(), Mockito.any(), Mockito.anyMap())) + .thenReturn(response); + + List badgeClassExtList = + badgeClassExtensionServiceImpl.search( + new ArrayList<>(), + new ArrayList<>(), + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST); + + Assert.assertTrue(null != badgeClassExtList); + Assert.assertEquals(0, badgeClassExtList.size()); + } + + @Test + public void testGetFailureBadgeListNull() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, new ArrayList>()); + + PowerMockito.when( + mockDBService.getRecordById(Mockito.any(), Mockito.any(), Mockito.anyString())) + .thenReturn(new Response()); + + boolean thrown = false; + + try { + badgeClassExtensionServiceImpl.get(VALUE_BADGE_ID); + } catch (ProjectCommonException exception) { + thrown = true; + Assert.assertEquals( + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), exception.getResponseCode()); + } + + Assert.assertEquals(true, thrown); + } + + @Test + public void testGetFailureBadgeListEmpty() { + + Response response = new Response(); + response.put(JsonKey.RESPONSE, new ArrayList>()); + + PowerMockito.when( + mockDBService.getRecordById(Mockito.any(), Mockito.any(), Mockito.anyString())) + .thenReturn(response); + + boolean thrown = false; + + try { + badgeClassExtensionServiceImpl.get(VALUE_BADGE_ID); + } catch (ProjectCommonException exception) { + thrown = true; + Assert.assertEquals( + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), exception.getResponseCode()); + } + + Assert.assertEquals(true, thrown); + } + + @Test + public void testDeleteSuccess() { + PowerMockito.when( + mockDBService.deleteRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(new Response()); + + boolean thrown = false; + + try { + badgeClassExtensionServiceImpl.delete(VALUE_BADGE_ID); + } catch (Exception e) { + thrown = true; + } + + Assert.assertEquals(false, thrown); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeAssertionTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeAssertionTest.java new file mode 100644 index 0000000000..ce0a628e1e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeAssertionTest.java @@ -0,0 +1,95 @@ +package org.sunbird.badge.service.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.io.IOException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.HttpUtilResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.telemetry.util.TelemetryUtil; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({HttpUtil.class, TelemetryUtil.class, BadgrServiceImpl.class}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class BadgrServiceImplBadgeAssertionTest { + private BadgrServiceImpl badgrServiceImpl; + + private Request request; + + private static final String BADGE_ASSERTION_REVOKE_RESPONSE_FAILURE = + "Assertion is already revoked."; + + private static final String VALUE_ASSERTION_ID = "2093cf30-f82e-4975-88f8-35230832db14"; + private static final String VALUE_RECIPIENT_ID = "bf5c4aa7-7d70-4488-915e-6e6ba3f7099b"; + private static final String VALUE_RECIPIENT_TYPE_USER = "user"; + private static final String VALUE_REVOCATION_REASON = "some reason"; + private static final String VALUE_RECIPIENT_EMAIL = "someone@someorg.com"; + + @Before + public void setUp() throws Exception { + PowerMockito.mockStatic(HttpUtil.class); + + PowerMockito.mockStatic(TelemetryUtil.class); + PowerMockito.mockStatic(BadgrServiceImpl.class); + + badgrServiceImpl = new BadgrServiceImpl(); + request = new Request(); + } + + @Test + public void testRevokeAssertionSuccess() throws IOException { + PowerMockito.when( + HttpUtil.sendDeleteRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyString())) + .thenReturn(new HttpUtilResponse("", 200)); + PowerMockito.when(badgrServiceImpl.getEmail(Mockito.any(), Mockito.any())) + .thenReturn(VALUE_RECIPIENT_EMAIL); + + request.put(BadgingJsonKey.ASSERTION_ID, VALUE_ASSERTION_ID); + request.put(BadgingJsonKey.RECIPIENT_ID, VALUE_RECIPIENT_ID); + request.put(BadgingJsonKey.RECIPIENT_TYPE, VALUE_RECIPIENT_TYPE_USER); + request.put(BadgingJsonKey.REVOCATION_REASON, VALUE_REVOCATION_REASON); + + Response response = badgrServiceImpl.revokeAssertion(request); + + assertNotEquals(null, response); + assertEquals(ResponseCode.OK, response.getResponseCode()); + } + + @Test + public void testRevokeAssertionFailure() throws IOException { + PowerMockito.when( + HttpUtil.sendDeleteRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyString())) + .thenReturn(new HttpUtilResponse(BADGE_ASSERTION_REVOKE_RESPONSE_FAILURE, 400)); + PowerMockito.when(badgrServiceImpl.getEmail(Mockito.any(), Mockito.any())) + .thenReturn(VALUE_RECIPIENT_EMAIL); + + request.put(BadgingJsonKey.ASSERTION_ID, VALUE_ASSERTION_ID); + request.put(BadgingJsonKey.RECIPIENT_ID, VALUE_RECIPIENT_ID); + request.put(BadgingJsonKey.RECIPIENT_TYPE, VALUE_RECIPIENT_TYPE_USER); + request.put(BadgingJsonKey.REVOCATION_REASON, VALUE_REVOCATION_REASON); + + boolean thrown = false; + + try { + badgrServiceImpl.revokeAssertion(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeClassTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeClassTest.java new file mode 100644 index 0000000000..4c25fbd9c1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeClassTest.java @@ -0,0 +1,506 @@ +package org.sunbird.badge.service.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.badge.model.BadgeClassExtension; +import org.sunbird.badge.service.BadgeClassExtensionService; +import org.sunbird.badge.service.BadgingService; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.HttpUtilResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.telemetry.util.TelemetryUtil; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({HttpUtil.class, TelemetryUtil.class}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class BadgrServiceImplBadgeClassTest { + private BadgingService badgrServiceImpl; + + private Request request; + + private BadgeClassExtensionService mockBadgeClassExtensionService; + + private static final String BADGE_CLASS_COMMON_RESPONSE_SUCCESS = + "{\"created_at\":\"2018-03-05T09:35:33.722993Z\",\"id\":1,\"issuer\":\"http://localhost:8000/public/issuers/oracle-university\",\"json\":{\"name\":\"Java SE 8 Programmer\",\"image\":\"http://localhost:8000/public/badges/java-se-8-programmer/image\",\"criteria\":\"https://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=5001&get_params=p_exam_id:1Z0-808\",\"@context\":\"https://w3id.org/openbadges/v1\",\"issuer\":\"http://localhost:8000/public/issuers/oracle-university\",\"type\":\"BadgeClass\",\"id\":\"http://localhost:8000/public/badges/java-se-8-programmer\",\"description\":\"A basic Java SE 8 certification.\"},\"name\":\"Java SE 8 Programmer\",\"image\":\"http://localhost:8000/media/uploads/badges/issuer_badgeclass_76c4cb77-40c7-4694-bee2-de15bd45f6cb.png\",\"slug\":\"java-se-8-programmer\",\"recipient_count\":1,\"created_by\":\"http://localhost:8000/user/1\"}"; + private static final String BADGE_CLASS_SEARCH_RESPONSE_SUCCESS = + "[" + BADGE_CLASS_COMMON_RESPONSE_SUCCESS + "]"; + private static final String BADGE_CLASSS_DELETE_RESPONSE_SUCCESS = + "Badge java-se-8-programmer has been deleted."; + private static final String BADGE_CLASSS_DELETE_RESPONSE_FAILURE = + "Badge class could not be deleted. It has already been issued at least once."; + private static final String BADGE_CLASS_CREATE_RESPONSE_FAILURE_ISSUER_NOT_FOUND = + "\"Issuer invalid not found or inadequate permissions.\""; + private static final String BADGE_CLASS_GET_RESPONSE_FAILURE_BADGE_NOT_FOUND = + "\"BadgeClass invalid could not be found, or inadequate permissions.\""; + + private static final String VALUE_BADGE_ID = "java-se-8-programmer"; + private static final String VALUE_BADGE_ID_URL = + "http://localhost:8000/public/badges/java-se-8-programmer"; + private static final String VALUE_ISSUER_ID = "oracle-university"; + private static final String VALUE_ISSUER_ID_URL = + "http://localhost:8000/public/issuers/oracle-university"; + private static final String VALUE_NAME = "Java SE 8 Programmer"; + private static final String VALUE_DESCRIPTION = "A basic Java SE 8 certification."; + private static final String VALUE_BADGE_CRITERIA = + "https://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=5001&get_params=p_exam_id:1Z0-808"; + private static final String VALUE_IMAGE = + "http://localhost:8000/media/uploads/badges/issuer_badgeclass_76c4cb77-40c7-4694-bee2-de15bd45f6cb.png"; + private static final String VALUE_ROOT_ORG_ID = "AP"; + private static final String VALUE_TYPE = "user"; + private static final String VALUE_SUBTYPE = "award"; + private static final String VALUE_ROLES_JSON = "[ \"roleId1\" ]"; + private static final ArrayList VALUE_ROLES_LIST = + new ArrayList<>(Arrays.asList("roleId1")); + private static final String VALUE_CREATED_DATE = "2018-03-05T09:35:33.722993Z"; + + private static final String INVALID_VALUE = "invalid"; + + @Before + public void setUp() throws Exception { + PowerMockito.mockStatic(HttpUtil.class); + + PowerMockito.mockStatic(TelemetryUtil.class); + + mockBadgeClassExtensionService = PowerMockito.mock(BadgeClassExtensionServiceImpl.class); + + badgrServiceImpl = new BadgrServiceImpl(mockBadgeClassExtensionService); + request = new Request(); + Map roles = new HashMap<>(); + roles.put("roleId1", "roleId1"); + DataCacheHandler.setRoleMap(roles); + } + + private void validateSuccessResponse(ResponseCode responseCode, Map responseMap) { + assertEquals(ResponseCode.OK, responseCode); + + assertEquals(VALUE_BADGE_ID, responseMap.get(BadgingJsonKey.BADGE_ID)); + assertEquals(VALUE_BADGE_ID_URL, responseMap.get(BadgingJsonKey.BADGE_ID_URL)); + assertEquals(VALUE_ISSUER_ID, responseMap.get(BadgingJsonKey.ISSUER_ID)); + assertEquals(VALUE_ISSUER_ID_URL, responseMap.get(BadgingJsonKey.ISSUER_ID_URL)); + assertEquals(VALUE_NAME, responseMap.get(JsonKey.NAME)); + assertEquals(VALUE_DESCRIPTION, responseMap.get(JsonKey.DESCRIPTION)); + assertEquals(VALUE_BADGE_CRITERIA, responseMap.get(BadgingJsonKey.BADGE_CRITERIA)); + assertEquals(VALUE_IMAGE, responseMap.get(JsonKey.IMAGE)); + assertEquals(VALUE_ROOT_ORG_ID, responseMap.get(JsonKey.ROOT_ORG_ID)); + assertEquals(VALUE_TYPE, responseMap.get(JsonKey.TYPE)); + assertEquals(VALUE_SUBTYPE, responseMap.get(JsonKey.SUBTYPE)); + assertEquals(VALUE_ROLES_LIST.toString(), responseMap.get(JsonKey.ROLES).toString()); + assertEquals(VALUE_CREATED_DATE, responseMap.get(JsonKey.CREATED_DATE)); + } + + @Test + public void testCreateBadgeClassSuccess() throws IOException { + PowerMockito.when( + HttpUtil.postFormData(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_CLASS_COMMON_RESPONSE_SUCCESS, 200)); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).save(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_CRITERIA, VALUE_BADGE_CRITERIA); + request.put(JsonKey.NAME, VALUE_NAME); + request.put(JsonKey.DESCRIPTION, VALUE_DESCRIPTION); + request.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + request.put(JsonKey.TYPE, VALUE_TYPE); + request.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + request.put(JsonKey.ROLES, VALUE_ROLES_JSON); + request.put(JsonKey.IMAGE, VALUE_IMAGE.getBytes()); + + Response response = badgrServiceImpl.createBadgeClass(request); + validateSuccessResponse(response.getResponseCode(), response.getResult()); + Assert.assertTrue(null != response); + } + + @Test + public void testCreateBadgeClassFailureInvalidIssuer() throws IOException { + PowerMockito.when( + HttpUtil.postFormData(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn( + new HttpUtilResponse( + BADGE_CLASS_CREATE_RESPONSE_FAILURE_ISSUER_NOT_FOUND, + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode())); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).save(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, INVALID_VALUE); + + request.put(BadgingJsonKey.BADGE_CRITERIA, VALUE_BADGE_CRITERIA); + request.put(JsonKey.NAME, VALUE_NAME); + request.put(JsonKey.DESCRIPTION, VALUE_DESCRIPTION); + request.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + request.put(JsonKey.TYPE, VALUE_TYPE); + request.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + request.put(JsonKey.ROLES, VALUE_ROLES_JSON); + request.put(JsonKey.IMAGE, VALUE_IMAGE.getBytes()); + + boolean thrown = false; + + try { + badgrServiceImpl.createBadgeClass(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } + + @Test + public void testCreateBadgeClassFailureException() throws IOException { + PowerMockito.when( + HttpUtil.postFormData(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenThrow(new IOException()); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).save(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, INVALID_VALUE); + + request.put(BadgingJsonKey.BADGE_CRITERIA, VALUE_BADGE_CRITERIA); + request.put(JsonKey.NAME, VALUE_NAME); + request.put(JsonKey.DESCRIPTION, VALUE_DESCRIPTION); + request.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + request.put(JsonKey.TYPE, VALUE_TYPE); + request.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + request.put(JsonKey.ROLES, VALUE_ROLES_JSON); + request.put(JsonKey.IMAGE, VALUE_IMAGE.getBytes()); + + boolean thrown = false; + + try { + badgrServiceImpl.createBadgeClass(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.SERVER_ERROR.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } + + @Test + public void testGetBadgeClassSuccess() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_CLASS_COMMON_RESPONSE_SUCCESS, 200)); + PowerMockito.when(mockBadgeClassExtensionService.get(VALUE_BADGE_ID)) + .thenReturn( + new BadgeClassExtension( + VALUE_BADGE_ID, + VALUE_ISSUER_ID, + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST)); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_ID, VALUE_BADGE_ID); + + Response response = badgrServiceImpl.getBadgeClassDetails(VALUE_BADGE_ID); + validateSuccessResponse(response.getResponseCode(), response.getResult()); + Assert.assertTrue(null != response); + } + + @Test + public void testGetBadgeClassFailureInvalidBadgeId() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenReturn( + new HttpUtilResponse( + BADGE_CLASS_GET_RESPONSE_FAILURE_BADGE_NOT_FOUND, + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode())); + PowerMockito.when(mockBadgeClassExtensionService.get(VALUE_BADGE_ID)) + .thenReturn( + new BadgeClassExtension( + VALUE_BADGE_ID, + VALUE_ISSUER_ID, + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST)); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_ID, INVALID_VALUE); + + boolean thrown = false; + + try { + badgrServiceImpl.getBadgeClassDetails(INVALID_VALUE); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } + + @Test + public void testGetBadgeClassFailureException() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenThrow(new IOException()); + PowerMockito.when(mockBadgeClassExtensionService.get(VALUE_BADGE_ID)) + .thenReturn( + new BadgeClassExtension( + VALUE_BADGE_ID, + VALUE_ISSUER_ID, + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST)); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_ID, VALUE_BADGE_ID); + + boolean thrown = false; + + try { + badgrServiceImpl.getBadgeClassDetails(VALUE_BADGE_ID); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.SERVER_ERROR.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } + + @Test + public void testSearchBadgeClassSuccessNonEmpty() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_CLASS_SEARCH_RESPONSE_SUCCESS, 200)); + PowerMockito.when( + mockBadgeClassExtensionService.search( + Mockito.anyList(), + Mockito.anyList(), + Mockito.any(), + Mockito.any(), + Mockito.any(), + Mockito.anyList())) + .thenReturn( + new ArrayList<>( + Arrays.asList( + new BadgeClassExtension( + VALUE_BADGE_ID, + VALUE_ISSUER_ID, + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST)))); + + Map filtersMap = new HashMap<>(); + + filtersMap.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + filtersMap.put(JsonKey.TYPE, VALUE_TYPE); + filtersMap.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + filtersMap.put(JsonKey.ROLES, VALUE_ROLES_LIST); + filtersMap.put(BadgingJsonKey.ISSUER_LIST, new ArrayList()); + + request.put(JsonKey.FILTERS, filtersMap); + + Response response = badgrServiceImpl.searchBadgeClass(request); + + List> badges = + (List>) response.getResult().get(BadgingJsonKey.BADGES); + assertEquals(1, badges.size()); + + validateSuccessResponse(response.getResponseCode(), badges.get(0)); + } + + @Test + public void testSearchBadgeClassSuccessEmpty() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_CLASS_SEARCH_RESPONSE_SUCCESS, 200)); + PowerMockito.when( + mockBadgeClassExtensionService.search( + Mockito.anyList(), + Mockito.anyList(), + Mockito.any(), + Mockito.any(), + Mockito.any(), + Mockito.anyList())) + .thenReturn(new ArrayList<>()); + + Map filtersMap = new HashMap<>(); + + filtersMap.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + filtersMap.put(JsonKey.TYPE, VALUE_TYPE); + filtersMap.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + filtersMap.put(JsonKey.ROLES, VALUE_ROLES_LIST); + filtersMap.put(BadgingJsonKey.ISSUER_LIST, new ArrayList()); + + request.put(JsonKey.FILTERS, filtersMap); + + Response response = badgrServiceImpl.searchBadgeClass(request); + + List> badges = + (List>) response.getResult().get(BadgingJsonKey.BADGES); + assertEquals(0, badges.size()); + } + + @Test + public void testListBadgeClassFailureException() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenThrow(new IOException()); + PowerMockito.when( + mockBadgeClassExtensionService.search( + Mockito.anyList(), + Mockito.anyList(), + Mockito.any(), + Mockito.any(), + Mockito.any(), + Mockito.anyList())) + .thenReturn( + new ArrayList<>( + Arrays.asList( + new BadgeClassExtension( + VALUE_BADGE_ID, + VALUE_ISSUER_ID, + VALUE_ROOT_ORG_ID, + VALUE_TYPE, + VALUE_SUBTYPE, + VALUE_ROLES_LIST)))); + + Map filtersMap = new HashMap<>(); + + filtersMap.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + filtersMap.put(JsonKey.TYPE, VALUE_TYPE); + filtersMap.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + filtersMap.put(JsonKey.ROLES, VALUE_ROLES_LIST); + filtersMap.put(BadgingJsonKey.ISSUER_LIST, new ArrayList()); + + request.put(JsonKey.FILTERS, filtersMap); + + boolean thrown = false; + + try { + badgrServiceImpl.searchBadgeClass(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.SERVER_ERROR.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } + + @Test + public void testRemoveBadgeClassSuccess() throws IOException { + PowerMockito.when(HttpUtil.sendDeleteRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_CLASSS_DELETE_RESPONSE_SUCCESS, 200)); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).delete(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_ID, VALUE_BADGE_ID); + + Response response = badgrServiceImpl.removeBadgeClass(request); + + assertEquals(ResponseCode.OK, response.getResponseCode()); + assertEquals(BADGE_CLASSS_DELETE_RESPONSE_SUCCESS, response.getResult().get(JsonKey.MESSAGE)); + } + + @Test + public void testRemoveBadgeClassIssuedFailure() throws IOException { + PowerMockito.when(HttpUtil.sendDeleteRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_CLASSS_DELETE_RESPONSE_FAILURE, 400)); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).delete(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_ID, VALUE_BADGE_ID); + + boolean thrown = false; + + try { + badgrServiceImpl.removeBadgeClass(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals( + MessageFormat.format( + ResponseCode.customClientError.getErrorMessage(), + BADGE_CLASSS_DELETE_RESPONSE_FAILURE), + exception.getMessage()); + } + + assertEquals(true, thrown); + } + + @Test + public void testRemoveBadgeClassFailureInvalidBadgeId() throws IOException { + PowerMockito.when(HttpUtil.sendDeleteRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse("", ResponseCode.RESOURCE_NOT_FOUND.getResponseCode())); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).delete(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_ID, INVALID_VALUE); + + boolean thrown = false; + + try { + badgrServiceImpl.removeBadgeClass(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.RESOURCE_NOT_FOUND.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } + + @Test + public void testRemoveBadgeClassFailureException() throws IOException { + PowerMockito.when(HttpUtil.sendDeleteRequest(Mockito.any(), Mockito.any())) + .thenThrow(new IOException()); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).delete(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, VALUE_ISSUER_ID); + request.put(BadgingJsonKey.BADGE_ID, VALUE_BADGE_ID); + + boolean thrown = false; + + try { + badgrServiceImpl.removeBadgeClass(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.SERVER_ERROR.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } + + @Test + public void testCreateBadgeClassFailureExceptionInvalidRole() throws IOException { + PowerMockito.when( + HttpUtil.postFormData(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenThrow(new IOException()); + PowerMockito.doNothing().when(mockBadgeClassExtensionService).save(Mockito.any()); + + request.put(BadgingJsonKey.ISSUER_ID, INVALID_VALUE); + + request.put(BadgingJsonKey.BADGE_CRITERIA, VALUE_BADGE_CRITERIA); + request.put(JsonKey.NAME, VALUE_NAME); + request.put(JsonKey.DESCRIPTION, VALUE_DESCRIPTION); + request.put(JsonKey.ROOT_ORG_ID, VALUE_ROOT_ORG_ID); + request.put(JsonKey.TYPE, VALUE_TYPE); + request.put(JsonKey.SUBTYPE, VALUE_SUBTYPE); + request.put(JsonKey.ROLES, "[]"); + request.put(JsonKey.IMAGE, VALUE_IMAGE.getBytes()); + + boolean thrown = false; + + try { + badgrServiceImpl.createBadgeClass(request); + } catch (ProjectCommonException exception) { + thrown = true; + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), exception.getResponseCode()); + } + + assertEquals(true, thrown); + } +} diff --git a/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeIssuerTest.java b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeIssuerTest.java new file mode 100644 index 0000000000..5db5c8f327 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/badge/src/test/java/org/sunbird/badge/service/impl/BadgrServiceImplBadgeIssuerTest.java @@ -0,0 +1,89 @@ +package org.sunbird.badge.service.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.badge.service.BadgingService; +import org.sunbird.common.models.response.HttpUtilResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BadgingJsonKey; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; + +/** Created by arvind on 15/3/18. */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({HttpUtil.class}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class BadgrServiceImplBadgeIssuerTest { + + BadgingService badgrServiceImpl; + private Request request; + private static final String BADGE_ISSUER_CREATE_SUCCESS_RESPONSE = + "{ \"created_at\": \"2018-03-15T08:28:50.319695Z\", \"json\": { \"description\": \"Best certificate for teaching way and content\", \"url\": \"http://localhost:8000/abcdhe\", \"id\": \"http://localhost:8000/public/issuers/swarn-35\", \"@context\": \"https://w3id.org/openbadges/v1\", \"type\": \"Issuer\", \"email\": \"abc123.xyz@gmail.com\", \"name\": \"Swarn\" }, \"name\": \"Swarn\", \"slug\": \"swarn\", \"image\": null, \"created_by\": \"http://localhost:8000/user/1\", \"description\": \"Best certificate for teaching way and content\", \"owner\": \"http://localhost:8000/user/1\", \"editors\": [], \"staff\": []}"; + private static final String BADGE_ISSUER_LIST_SUCCESS_RESPONSE = + "[ { \"created_at\": \"2018-03-05T11:55:53.966947Z\", \"json\": { \"description\": \"Best certificate for teaching way and content\", \"url\": \"http://localhost:8000/v1/issuer/issuers\", \"id\": \"http://localhost:8000/public/issuers/swarn-2\", \"@context\": \"https://w3id.org/openbadges/v1\", \"type\": \"Issuer\", \"email\": \"abc123.glaitm@gmail.com\", \"name\": \"Swarn\" }, \"name\": \"Swarn\", \"slug\": \"swarn\", \"image\": null, \"created_by\": \"http://localhost:8000/user/1\", \"description\": \"Best certificate for teaching way and content\", \"owner\": \"http://localhost:8000/user/1\", \"editors\": [], \"staff\": [] }]"; + + @Before + public void setUp() { + PowerMockito.mockStatic(HttpUtil.class); + badgrServiceImpl = new BadgrServiceImpl(); + request = new Request(); + } + + @Test + public void testCreateBadgeIssuerSuccess() throws IOException { + PowerMockito.when( + HttpUtil.postFormData(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_ISSUER_CREATE_SUCCESS_RESPONSE, 200)); + + Map formParams = new HashMap<>(); + formParams.put(JsonKey.NAME, "Swarn"); + formParams.put(JsonKey.DESCRIPTION, "Best certificate for teaching way and content"); + formParams.put(JsonKey.EMAIL, "abc123.xyz@gmail.com"); + formParams.put(JsonKey.URL, "http://localhost:8000/abcdhe"); + + request.getRequest().putAll(formParams); + + Response response = badgrServiceImpl.createIssuer(request); + assertEquals(response.getResult().get(BadgingJsonKey.ISSUER_ID), "swarn"); + } + + @Test + public void testGetBadgeIssuerSuccess() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_ISSUER_CREATE_SUCCESS_RESPONSE, 200)); + + Map formParams = new HashMap<>(); + formParams.put(JsonKey.SLUG, "swarn"); + request.getRequest().putAll(formParams); + Response response = badgrServiceImpl.getIssuerDetails(request); + assertEquals(response.getResult().get(BadgingJsonKey.ISSUER_ID), "swarn"); + } + + @Test + public void testGetBadgeIssuersListSuccess() throws IOException { + PowerMockito.when(HttpUtil.doGetRequest(Mockito.any(), Mockito.any())) + .thenReturn(new HttpUtilResponse(BADGE_ISSUER_LIST_SUCCESS_RESPONSE, 200)); + + Map formParams = new HashMap<>(); + request.getRequest().putAll(formParams); + Response response = badgrServiceImpl.getIssuerList(request); + assertEquals( + (((List>) response.getResult().get(BadgingJsonKey.ISSUERS)) + .get(0) + .get(BadgingJsonKey.ISSUER_ID)), + "swarn"); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/.gitignore b/actors/sunbird-lms-mw/actors/common/.gitignore new file mode 100644 index 0000000000..3590c6b0e1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/.gitignore @@ -0,0 +1,7 @@ +/target/ +/.classpath +/.project +/.settings +/logs +/bin/ +velocity.log diff --git a/actors/sunbird-lms-mw/actors/common/pom.xml b/actors/sunbird-lms-mw/actors/common/pom.xml new file mode 100644 index 0000000000..fae7fc1c28 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/pom.xml @@ -0,0 +1,150 @@ + + 4.0.0 + + org.sunbird + mw-actors + 1.0-SNAPSHOT + ../pom.xml + + actor-common + Actors Common + + 2.3.1 + 1.8 + 1.8 + UTF-8 + UTF-8 + 1.1.1 + 1.6.1 + 1.0.7 + + + + org.sunbird + sunbird-commons + 1.0-SNAPSHOT + + + org.sunbird + sunbird-cassandra-utils + 1.0-SNAPSHOT + + + com.carrotsearch + hppc + + + slf4j-api + org.slf4j + + + + + org.sunbird + sunbird-notification + 1.0-SNAPSHOT + + + com.typesafe.akka + akka-testkit_2.11 + ${learner.akka.version} + test + + + + com.opencsv + opencsv + 4.1 + + + + + org.quartz-scheduler + quartz + 2.2.1 + + + + org.postgresql + postgresql + 42.1.4 + + + com.google.guava + guava + 18.0 + + + + + com.warrenstrange + googleauth + 1.1.2 + + + com.intuit.fuzzymatcher + fuzzy-matcher + 0.4.1 + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + org/sunbird/bean/* + org/sunbird/models/**/* + org/sunbird/learner/actors/url/action/**/* + org/sunbird/learner/actors/bulkupload/model/* + + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + **/*Spec.java + **/*Test.java + + + + + + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/actor/background/BackgroundOperations.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/actor/background/BackgroundOperations.java new file mode 100644 index 0000000000..40f0cfe931 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/actor/background/BackgroundOperations.java @@ -0,0 +1,8 @@ +package org.sunbird.actor.background; + +/** @author Mahesh Kumar Gangula */ +public enum BackgroundOperations { + registerChannel, + updateUserCountToLocationID, + emailService; +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/actor/background/ChannelRegistrationActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/actor/background/ChannelRegistrationActor.java new file mode 100644 index 0000000000..3da276d653 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/actor/background/ChannelRegistrationActor.java @@ -0,0 +1,157 @@ +package org.sunbird.actor.background; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONArray; +import org.json.JSONObject; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import scala.concurrent.Future; + +/** @author Amit Kumar */ +@ActorConfig( + tasks = {}, + asyncTasks = {"registerChannel"} +) +public class ChannelRegistrationActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + if (request.getOperation().equalsIgnoreCase(BackgroundOperations.registerChannel.name())) { + registerChannel(); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void registerChannel() { + List ekstepChannelList = getEkstepChannelList(); + List> sunbirdChannelList = null; + if (null != ekstepChannelList) { + ProjectLogger.log("channel list size from ekstep : " + ekstepChannelList.size()); + sunbirdChannelList = getSunbirdChannelList(); + ProjectLogger.log("channel list size from sunbird : " + sunbirdChannelList.size()); + if (!ekstepChannelList.isEmpty()) { + processChannelReg(ekstepChannelList, sunbirdChannelList); + } + } + } + + private void processChannelReg( + List ekstepChannelList, List> sunbirdChannelList) { + Boolean bool = true; + for (Map map : sunbirdChannelList) { + ProjectLogger.log("processing start for hashTagId " + map.get(JsonKey.HASHTAGID)); + if (!StringUtils.isBlank((String) map.get(JsonKey.HASHTAGID)) + && (!ekstepChannelList.contains(map.get(JsonKey.HASHTAGID))) + && (!Util.registerChannel(map))) { + bool = false; + } + } + if (bool) { + updateSystemSettingTable(bool); + } + } + + private void updateSystemSettingTable(Boolean bool) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, JsonKey.CHANNEL_REG_STATUS_ID); + map.put(JsonKey.FIELD, JsonKey.CHANNEL_REG_STATUS); + map.put(JsonKey.VALUE, String.valueOf(bool)); + Response response = cassandraOperation.upsertRecord("sunbird", JsonKey.SYSTEM_SETTINGS_DB, map); + ProjectLogger.log( + "Upsert operation result for channel reg status = " + + response.getResult().get(JsonKey.RESPONSE)); + } + + private List> getSunbirdChannelList() { + ProjectLogger.log("start call for getting List of channel from sunbird ES"); + SearchDTO searchDto = new SearchDTO(); + List list = new ArrayList<>(); + list.add(JsonKey.HASHTAGID); + list.add(JsonKey.DESCRIPTION); + list.add(JsonKey.CHANNEL); + searchDto.setFields(list); + Map filter = new HashMap<>(); + filter.put(JsonKey.IS_ROOT_ORG, true); + searchDto.getAdditionalProperties().put(JsonKey.FILTERS, filter); + Future> esResponseF = + esService.search(searchDto, ProjectUtil.EsType.organisation.getTypeName()); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponseF); + List> orgList = (List>) esResponse.get(JsonKey.CONTENT); + ProjectLogger.log("End call for getting List of channel from sunbird ES"); + return orgList; + } + + private List getEkstepChannelList() { + List channelList = new ArrayList<>(); + Map headerMap = new HashMap<>(); + String header = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(header)) { + header = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } else { + header = JsonKey.BEARER + header; + } + headerMap.put(JsonKey.AUTHORIZATION, header); + headerMap.put("Content-Type", "application/json"); + headerMap.put("user-id", ""); + String reqString = ""; + String response = ""; + JSONObject data; + JSONObject jObject; + Object[] result = null; + try { + ProjectLogger.log("start call for getting List of channel from Ekstep"); + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(ekStepBaseUrl)) { + ekStepBaseUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + Map map = new HashMap<>(); + Map reqMap = new HashMap<>(); + map.put(JsonKey.REQUEST, reqMap); + + ObjectMapper mapper = new ObjectMapper(); + reqString = mapper.writeValueAsString(map); + response = + HttpUtil.sendPostRequest( + (ekStepBaseUrl + + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_GET_CHANNEL_LIST)), + reqString, + headerMap); + jObject = new JSONObject(response); + data = jObject.getJSONObject(JsonKey.RESULT); + ProjectLogger.log( + "Total number of content fetched from Ekstep while getting List of channel : " + + data.get("count")); + JSONArray contentArray = data.getJSONArray(JsonKey.CHANNELS); + result = mapper.readValue(contentArray.toString(), Object[].class); + for (Object object : result) { + Map tempMap = (Map) object; + channelList.add((String) tempMap.get(JsonKey.CODE)); + } + ProjectLogger.log("end call for getting List of channel from Ekstep"); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + channelList = null; + } + return channelList; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ClaimStatus.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ClaimStatus.java new file mode 100644 index 0000000000..a67b859035 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ClaimStatus.java @@ -0,0 +1,26 @@ +package org.sunbird.bean; + +/** + * this class will have user action performed on the shadow user record. + * + * @author anmolgupta + */ +public enum ClaimStatus { + CLAIMED(1), + UNCLAIMED(0), + REJECTED(2), + FAILED(3), + MULTIMATCH(4), + ORGEXTERNALIDMISMATCH(5), + ELIGIBLE(6); + + private int value; + + ClaimStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ContentResponse.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ContentResponse.java new file mode 100644 index 0000000000..cb609b9f90 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ContentResponse.java @@ -0,0 +1,17 @@ +/** */ +package org.sunbird.bean; + +import java.util.Map; + +/** @author Manzarul */ +public class ContentResponse { + private Map result; + + public Map getResult() { + return result; + } + + public void setResult(Map result) { + this.result = result; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/MigrationUser.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/MigrationUser.java new file mode 100644 index 0000000000..2a3d2bf05b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/MigrationUser.java @@ -0,0 +1,98 @@ +package org.sunbird.bean; + +import java.io.Serializable; + +public class MigrationUser implements Serializable { + + private String email; + private String phone; + private String name; + private String userExternalId; + private String orgExternalId; + private String channel; + private String inputStatus; + + public void setEmail(String email) { + this.email = email; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public void setName(String name) { + this.name = name; + } + + public void setUserExternalId(String userExternalId) { + this.userExternalId = userExternalId; + } + + public void setOrgExternalId(String orgExternalId) { + this.orgExternalId = orgExternalId; + } + + public void setChannel(String state) { + this.channel = state; + } + + public void setInputStatus(String inputStatus) { + this.inputStatus = inputStatus; + } + + public MigrationUser() {} + + public String getEmail() { + return email; + } + + public String getPhone() { + return phone; + } + + public String getName() { + return name; + } + + public String getUserExternalId() { + return userExternalId; + } + + public String getOrgExternalId() { + return orgExternalId; + } + + public String getChannel() { + return channel; + } + + public String getInputStatus() { + return inputStatus; + } + + @Override + public String toString() { + return "MigrationUser{" + + "email='" + + email + + '\'' + + ", phone='" + + phone + + '\'' + + ", name='" + + name + + '\'' + + ", userExternalId='" + + userExternalId + + '\'' + + ", orgExternalId='" + + orgExternalId + + '\'' + + ", state='" + + channel + + '\'' + + ", inputStatus=" + + inputStatus + + '}'; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/Organization.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/Organization.java new file mode 100644 index 0000000000..bd0a88245f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/Organization.java @@ -0,0 +1,334 @@ +package org.sunbird.bean; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class Organization implements Serializable { + + private static final long serialVersionUID = 3617862727235741692L; + private String id; + private String addressId; + private String approvedBy; + private String approvedDate; + private String channel; + private String communityId; + private String contactDetail; + private String createdBy; + private String createdDate; + private Timestamp dateTime; + private String description; + private String externalId; + private String hashTagId; + private String homeUrl; + private String imgUrl; + private Boolean isApproved; + private Boolean isDefault; + private Boolean isRootOrg; + private String locationId; + private Integer noOfMembers; + private String orgCode; + private String orgName; + private String orgType; + private String orgTypeId; + private String parentOrgId; + private String preferredLanguage; + private String provider; + private String rootOrgId; + private String slug; + private Integer status; + private String theme; + private String thumbnail; + private String updatedBy; + private String updatedDate; + private List locationIds; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAddressId() { + return addressId; + } + + public void setAddressId(String addressId) { + this.addressId = addressId; + } + + public String getApprovedBy() { + return approvedBy; + } + + public void setApprovedBy(String approvedBy) { + this.approvedBy = approvedBy; + } + + public String getApprovedDate() { + return approvedDate; + } + + public void setApprovedDate(String approvedDate) { + this.approvedDate = approvedDate; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getCommunityId() { + return communityId; + } + + public void setCommunityId(String communityId) { + this.communityId = communityId; + } + + public String getContactDetail() { + return contactDetail; + } + + public void setContactDetail(String contactDetail) { + this.contactDetail = contactDetail; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public String getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(String createdDate) { + this.createdDate = createdDate; + } + + public Timestamp getDateTime() { + return dateTime; + } + + public void setDateTime(Timestamp dateTime) { + this.dateTime = dateTime; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getHashTagId() { + return hashTagId; + } + + public void setHashTagId(String hashTagId) { + this.hashTagId = hashTagId; + } + + public String getHomeUrl() { + return homeUrl; + } + + public void setHomeUrl(String homeUrl) { + this.homeUrl = homeUrl; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getLocationId() { + return locationId; + } + + public void setLocationId(String locationId) { + this.locationId = locationId; + } + + public Integer getNoOfMembers() { + return noOfMembers; + } + + public void setNoOfMembers(Integer noOfMembers) { + this.noOfMembers = noOfMembers; + } + + public String getOrgCode() { + return orgCode; + } + + public void setOrgCode(String orgCode) { + this.orgCode = orgCode; + } + + public String getOrgName() { + return orgName; + } + + public void setOrgName(String orgName) { + this.orgName = orgName; + } + + public String getOrgType() { + return orgType; + } + + public void setOrgType(String orgType) { + this.orgType = orgType; + } + + public String getOrgTypeId() { + return orgTypeId; + } + + public void setOrgTypeId(String orgTypeId) { + this.orgTypeId = orgTypeId; + } + + public String getParentOrgId() { + return parentOrgId; + } + + public void setParentOrgId(String parentOrgId) { + this.parentOrgId = parentOrgId; + } + + public String getPreferredLanguage() { + return preferredLanguage; + } + + public void setPreferredLanguage(String preferredLanguage) { + this.preferredLanguage = preferredLanguage; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getRootOrgId() { + return rootOrgId; + } + + public void setRootOrgId(String rootOrgId) { + this.rootOrgId = rootOrgId; + } + + public String getSlug() { + return slug; + } + + public void setSlug(String slug) { + this.slug = slug; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getTheme() { + return theme; + } + + public void setTheme(String theme) { + this.theme = theme; + } + + public String getThumbnail() { + return thumbnail; + } + + public void setThumbnail(String thumbnail) { + this.thumbnail = thumbnail; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(String updatedDate) { + this.updatedDate = updatedDate; + } + + public List getLocationIds() { + return locationIds; + } + + public void setLocationIds(List locationIds) { + this.locationIds = locationIds; + } + + @JsonProperty(value = "isApproved") + public Boolean isApproved() { + return isApproved; + } + + public void setApproved(Boolean isApproved) { + this.isApproved = isApproved; + } + + @JsonProperty(value = "isDefault") + public Boolean isDefault() { + return isDefault; + } + + public void setDefault(Boolean isDefault) { + this.isDefault = isDefault; + } + + @JsonProperty(value = "isRootOrg") + public Boolean isRootOrg() { + return isRootOrg; + } + + public void setRootOrg(Boolean isRootOrg) { + this.isRootOrg = isRootOrg; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ShadowUser.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ShadowUser.java new file mode 100644 index 0000000000..0513efe24a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ShadowUser.java @@ -0,0 +1,265 @@ +package org.sunbird.bean; + +import java.sql.Timestamp; +import java.util.List; + +/** + * this is POJO class for the shadow user in the shadow_user table + * + * @author anmolgupta + */ +public class ShadowUser { + private Timestamp claimedOn; + private int claimStatus; + private Timestamp createdOn; + private String email; + private String name; + private String orgExtId; + private String phone; + private String processId; + private Timestamp updatedOn; + private String userExtId; + private String userId; + private int userStatus; + private List userIds; + private String channel; + private String addedBy; + private int attemptedCount; + + public ShadowUser() {} + + public ShadowUser(ShadowUserBuilder shadowUserBuilder) { + this.claimedOn = shadowUserBuilder.claimedOn; + this.claimStatus = shadowUserBuilder.claimStatus; + this.createdOn = shadowUserBuilder.createdOn; + this.email = shadowUserBuilder.email; + this.name = shadowUserBuilder.name; + this.orgExtId = shadowUserBuilder.orgExtId; + this.phone = shadowUserBuilder.phone; + this.processId = shadowUserBuilder.processId; + this.updatedOn = shadowUserBuilder.updatedOn; + this.userExtId = shadowUserBuilder.userExtId; + this.userId = shadowUserBuilder.userId; + this.userStatus = shadowUserBuilder.userStatus; + this.channel = shadowUserBuilder.channel; + this.addedBy = shadowUserBuilder.addedBy; + this.userIds = shadowUserBuilder.userIds; + this.attemptedCount = shadowUserBuilder.attemptedCount; + } + + public int getAttemptedCount() { + return attemptedCount; + } + + public Timestamp getClaimedOn() { + return claimedOn; + } + + public String getAddedBy() { + return addedBy; + } + + public List getUserIds() { + return userIds; + } + + public int getClaimStatus() { + return claimStatus; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public String getEmail() { + return email; + } + + public String getName() { + return name; + } + + public String getOrgExtId() { + return orgExtId; + } + + public String getPhone() { + return phone; + } + + public String getProcessId() { + return processId; + } + + public Timestamp getUpdatedOn() { + return updatedOn; + } + + public String getUserExtId() { + return userExtId; + } + + public String getUserId() { + return userId; + } + + public int getUserStatus() { + return userStatus; + } + + public String getChannel() { + return channel; + } + + @Override + public String toString() { + return "ShadowUser{" + + "claimedOn=" + + claimedOn + + ", claimStatus=" + + claimStatus + + ", createdOn=" + + createdOn + + ", email='" + + email + + '\'' + + ", name='" + + name + + '\'' + + ", orgExtId='" + + orgExtId + + '\'' + + ", phone='" + + phone + + '\'' + + ", processId='" + + processId + + '\'' + + ", updatedOn=" + + updatedOn + + ", userExtId='" + + userExtId + + '\'' + + ", userId='" + + userId + + '\'' + + ", userStatus=" + + userStatus + + ", userIds=" + + userIds + + ", channel='" + + channel + + '\'' + + ", addedBy='" + + addedBy + + '\'' + + ", attemptedCount=" + + attemptedCount + + '}'; + } + + public static class ShadowUserBuilder { + + private Timestamp claimedOn; + private int claimStatus; + private Timestamp createdOn; + private String email; + private String name; + private String orgExtId; + private String phone; + private String processId; + private Timestamp updatedOn; + private String userExtId; + private String userId; + private int userStatus; + private String channel; + private String addedBy; + private List userIds; + private int attemptedCount; + + public ShadowUserBuilder setAttemptedCount(int attemptedCount) { + this.attemptedCount = attemptedCount; + return this; + } + + public ShadowUserBuilder setUserIds(List userIds) { + this.userIds = userIds; + return this; + } + + public ShadowUserBuilder setAddedBy(String addedBy) { + this.addedBy = addedBy; + return this; + } + + public ShadowUserBuilder setChannel(String channel) { + this.channel = channel; + return this; + } + + public ShadowUserBuilder setClaimedOn(Timestamp claimedOn) { + this.claimedOn = claimedOn; + return this; + } + + public ShadowUserBuilder setClaimStatus(int claimStatus) { + this.claimStatus = claimStatus; + return this; + } + + public ShadowUserBuilder setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + return this; + } + + public ShadowUserBuilder setEmail(String email) { + this.email = email; + return this; + } + + public ShadowUserBuilder setName(String name) { + this.name = name; + return this; + } + + public ShadowUserBuilder setOrgExtId(String orgExternalId) { + this.orgExtId = orgExternalId; + return this; + } + + public ShadowUserBuilder setPhone(String phone) { + this.phone = phone; + return this; + } + + public ShadowUserBuilder setProcessId(String processId) { + this.processId = processId; + return this; + } + + public ShadowUserBuilder setUpdatedOn(Timestamp updatedOn) { + this.updatedOn = updatedOn; + return this; + } + + public ShadowUserBuilder setUserExtId(String userExtId) { + this.userExtId = userExtId; + return this; + } + + public ShadowUserBuilder setUserId(String userId) { + this.userId = userId; + return this; + } + + public ShadowUserBuilder setUserStatus(int userStatus) { + this.userStatus = userStatus; + return this; + } + + public ShadowUser build() { + ShadowUser shadowUser = new ShadowUser(this); + return shadowUser; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ShadowUserUpload.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ShadowUserUpload.java new file mode 100644 index 0000000000..7adc7436f8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/bean/ShadowUserUpload.java @@ -0,0 +1,150 @@ +package org.sunbird.bean; + +import java.util.Arrays; +import java.util.List; +import org.sunbird.validator.user.UserBulkMigrationRequestValidator; + +public class ShadowUserUpload { + + private String fileSize; + private List headers; + private List mappedHeaders; + private byte[] fileData; + private List mandatoryFields; + private List supportedFields; + private String processId; + private List values; + + private ShadowUserUpload(ShadowUserUploadBuilder migrationBuilder) { + this.fileSize = migrationBuilder.fileSize; + this.headers = migrationBuilder.headers; + this.fileData = migrationBuilder.fileData; + this.mandatoryFields = migrationBuilder.mandatoryFields; + this.supportedFields = migrationBuilder.supportedFields; + this.processId = migrationBuilder.processId; + this.values = migrationBuilder.values; + this.mappedHeaders = migrationBuilder.mappedHeaders; + } + + public String getFileSize() { + return fileSize; + } + + public List getHeaders() { + return headers; + } + + public byte[] getFileData() { + return fileData; + } + + public List getMandatoryFields() { + return mandatoryFields; + } + + public List getSupportedFields() { + return supportedFields; + } + + public List getValues() { + return values; + } + + public List getMappedHeaders() { + return mappedHeaders; + } + + @Override + public String toString() { + return "ShadowUserUpload{" + + "fileSize='" + + fileSize + + '\'' + + ", headers=" + + headers + + ", mappedHeaders=" + + mappedHeaders + + ", fileData=" + + Arrays.toString(fileData) + + ", mandatoryFields=" + + mandatoryFields + + ", supportedFields=" + + supportedFields + + ", processId='" + + processId + + '\'' + + ", values=" + + values + + '}'; + } + + public String getProcessId() { + return processId; + } + + public static class ShadowUserUploadBuilder { + + private String fileSize; + private List headers; + private byte[] fileData; + private List mandatoryFields; + private List supportedFields; + private String processId; + private List values; + private List mappedHeaders; + + public ShadowUserUploadBuilder() {} + + public ShadowUserUploadBuilder setFileSize(String fileSize) { + this.fileSize = fileSize; + return this; + } + + public ShadowUserUploadBuilder setHeaders(List headers) { + this.headers = headers; + return this; + } + + public ShadowUserUploadBuilder setFileData(byte[] fileData) { + this.fileData = fileData; + return this; + } + + public ShadowUserUploadBuilder setMandatoryFields(List mandatoryFields) { + mandatoryFields.replaceAll(String::toLowerCase); + this.mandatoryFields = mandatoryFields; + return this; + } + + public ShadowUserUploadBuilder setSupportedFields(List supportedFields) { + supportedFields.replaceAll(String::toLowerCase); + this.supportedFields = supportedFields; + return this; + } + + public ShadowUserUploadBuilder setProcessId(String processId) { + this.processId = processId; + return this; + } + + public ShadowUserUploadBuilder setValues(List values) { + this.values = values; + return this; + } + + public ShadowUserUploadBuilder setMappedHeaders(List mappedHeaders) { + this.mappedHeaders = mappedHeaders; + return this; + } + + public ShadowUserUpload validate() { + ShadowUserUpload migration = new ShadowUserUpload(this); + validate(migration); + return migration; + } + + private void validate(ShadowUserUpload migration) { + UserBulkMigrationRequestValidator.getInstance(migration).validate(); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/ShadowUserProcessor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/ShadowUserProcessor.java new file mode 100644 index 0000000000..09afe27937 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/ShadowUserProcessor.java @@ -0,0 +1,677 @@ +package org.sunbird.common; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.util.concurrent.FutureCallback; +import java.util.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.bean.ClaimStatus; +import org.sunbird.bean.ShadowUser; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.feed.FeedUtil; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.UserFlagEnum; +import org.sunbird.learner.util.UserFlagUtil; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.UserType; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.telemetry.util.TelemetryUtil; +import scala.concurrent.Future; + +public class ShadowUserProcessor { + private Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ObjectMapper mapper = new ObjectMapper(); + private Map hashTagIdMap = new HashMap<>(); + private Util.DbInfo bulkUploadDbInfo = Util.dbInfoMap.get(JsonKey.BULK_OP_DB); + private Map extOrgIdMap = new HashMap<>(); + private String custodianOrgId; + private SSOManager keyCloakService = SSOServiceFactory.getInstance(); + private Map> processIdtelemetryCtxMap = new HashMap<>(); + private ElasticSearchService elasticSearchService = EsClientFactory.getInstance(JsonKey.REST); + + public void process() { + processAllUnclaimedUser(); + ProjectLogger.log( + "ShadowUserProcessor:process:successfully processed shadow user Stage3 ended", + LoggerEnum.INFO.name()); + } + + private void processSingleShadowUser(ShadowUser shadowUser) { + ProjectLogger.log( + "ShadowUserProcessor:processSingleShadowUser:started claiming shadow user with processId: " + + shadowUser.getProcessId(), + LoggerEnum.INFO.name()); + updateUser(shadowUser); + } + + /** + * this method will be called when the user is already claimed need to update the user + * + * @param shadowUser + */ + public void processClaimedUser(ShadowUser shadowUser) { + ProjectLogger.log( + "ShadowUserProcessor:processClaimedUser:started claming shadow user with processId: " + + shadowUser.getProcessId(), + LoggerEnum.INFO.name()); + String orgId = getOrgId(shadowUser); + Map esUser = + (Map) + ElasticSearchHelper.getResponseFromFuture( + elasticSearchService.getDataByIdentifier( + ProjectUtil.EsType.user.getTypeName(), shadowUser.getUserId())); + String userId = (String) esUser.get(JsonKey.ID); + String rootOrgId = (String) esUser.get(JsonKey.ROOT_ORG_ID); + ProjectLogger.log( + "ShadowUserProcessor:processClaimedUser:started: flag value got from es " + + esUser.get(JsonKey.FLAGS_VALUE), + LoggerEnum.INFO.name()); + int flagsValue = + null != esUser.get(JsonKey.FLAGS_VALUE) + ? (int) esUser.get(JsonKey.FLAGS_VALUE) + : 0; // since we are migrating the user from custodian org to non custodian org. + ProjectLogger.log( + "ShadowUserProcessor:processClaimedUser:Got Flag Value " + flagsValue, + LoggerEnum.INFO.name()); + if (!((String) esUser.get(JsonKey.FIRST_NAME)).equalsIgnoreCase(shadowUser.getName()) + || ((int) esUser.get(JsonKey.STATUS)) != shadowUser.getUserStatus()) { + updateUserInUserTable(flagsValue, shadowUser.getUserId(), rootOrgId, shadowUser); + if (shadowUser.getUserStatus() == ProjectUtil.Status.INACTIVE.getValue()) { + deactivateUserFromKC(userId); + } + } + deleteUserFromOrganisations( + shadowUser, rootOrgId, (List>) esUser.get(JsonKey.ORGANISATIONS)); + if (StringUtils.isNotBlank(orgId) && !getOrganisationIds(esUser).contains(orgId)) { + registerUserToOrg(userId, orgId); + } + syncUserToES(userId); + updateUserInShadowDb(userId, shadowUser, ClaimStatus.CLAIMED.getValue(), null); + } + + private void deactivateUserFromKC(String userId) { + Map userMap = new HashMap<>(); + userMap.put(JsonKey.USER_ID, userId); + try { + ProjectLogger.log( + "ShadowUserProcessor:processClaimedUse:request Got to deactivate user account from KC:" + + userMap, + LoggerEnum.INFO.name()); + String status = keyCloakService.deactivateUser(userMap); + ProjectLogger.log( + "ShadowUserProcessor:processClaimedUse:deactivate user account from KC:" + status, + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log( + "ShadowUserProcessor:processClaimedUse:Error occurred while deactivate user account from KC:" + + userId, + LoggerEnum.ERROR.name()); + } + } + + private boolean isRootOrgMatchedWithOrgId(String rootOrgId, String orgId) { + if (StringUtils.equalsIgnoreCase(rootOrgId, orgId)) { + return true; + } + return false; + } + + private void deleteUserFromOrganisations( + ShadowUser shadowUser, String rootOrgId, List> organisations) { + organisations + .stream() + .forEach( + organisation -> { + String orgId = (String) organisation.get(JsonKey.ORGANISATION_ID); + if (!isRootOrgMatchedWithOrgId(rootOrgId, orgId)) { + String id = (String) organisation.get(JsonKey.ID); + updateStatusInUserOrg(shadowUser, id); + } + }); + } + + private void updateStatusInUserOrg(ShadowUser shadowUser, String id) { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.ID, id); + propertiesMap.put(JsonKey.IS_DELETED, true); + propertiesMap.put(JsonKey.UPDATED_BY, shadowUser.getAddedBy()); + propertiesMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + Response response = + cassandraOperation.updateRecord(JsonKey.SUNBIRD, JsonKey.USER_ORG, propertiesMap); + ProjectLogger.log( + "ShadowUserProcessor:updateStatusInUserOrg:response from cassandra in updating user org " + .concat(response + ""), + LoggerEnum.INFO.name()); + } + + private List> getUserMatchedIdentifierFromES(ShadowUser shadowUser) { + Map request = new WeakHashMap<>(); + Map filters = new WeakHashMap<>(); + Map or = new WeakHashMap<>(); + if (StringUtils.isNotBlank(shadowUser.getEmail())) { + or.put(JsonKey.EMAIL, shadowUser.getEmail()); + } + if (StringUtils.isNotBlank(shadowUser.getPhone())) { + or.put(JsonKey.PHONE, shadowUser.getPhone()); + } + filters.put(JsonKey.ES_OR_OPERATION, or); + filters.put(JsonKey.ROOT_ORG_ID, getCustodianOrgId()); + request.put(JsonKey.FILTERS, filters); + ProjectLogger.log( + "ShadowUserProcessor:getUserMatchedIdentifierFromES:the filter prepared for elastic search with processId: " + + shadowUser.getProcessId() + + " :filters are:" + + filters, + LoggerEnum.INFO.name()); + SearchDTO searchDTO = ElasticSearchHelper.createSearchDTO(request); + searchDTO.setFields( + new ArrayList( + Arrays.asList( + JsonKey.ID, + JsonKey.CHANNEL, + JsonKey.EMAIL, + JsonKey.PHONE, + JsonKey.ROOT_ORG_ID, + JsonKey.FLAGS_VALUE, + JsonKey.ORGANISATIONS, + JsonKey.IS_DELETED, + JsonKey.STATUS))); + Map response = + (Map) + ElasticSearchHelper.getResponseFromFuture( + elasticSearchService.search(searchDTO, JsonKey.USER)); + ProjectLogger.log( + "ShadowUserProcessor:getUserMatchedIdentifierFromES:response got from elasticSearch is with processId: " + + shadowUser.getProcessId() + + " :response is" + + response, + LoggerEnum.INFO.name()); + return (List>) response.get(JsonKey.CONTENT); + } + + /** + * this method will search in ES with phone/email, if multiple user's found(cond: if a user + * provide email of himself and phone of other user) it will mark user claimStatus to multimatch. + * else it will get the user_id from ES response and then it will fetch all the record from + * shadow_user table who are not claimed, rejected and failed with same user_id. if found multiple + * records after removing the users of same channel from multiMatchRecords (cond: to avoid + * changing of claimStatus to MULTIMATCH if respective user update happened )then will update + * respective and rest of the user's claimStatus to MULTIMATCH. else if filterRecords is empty + * then the respective user claimStatus will be marked as ELIGIBLE IN shadow_user table + * + * @param shadowUser + */ + private void updateUser(ShadowUser shadowUser) { + List> esUser = getUserMatchedIdentifierFromES(shadowUser); + ProjectLogger.log( + "ShadowUserProcessor:updateUser:GOT ES RESPONSE FOR USER WITH SIZE " + esUser.size(), + LoggerEnum.INFO.name()); + if (CollectionUtils.isNotEmpty(esUser)) { + if (esUser.size() == 1) { + ProjectLogger.log( + "ShadowUserProcessor:updateUser:Got single user:" + + esUser + + " :with processId" + + shadowUser.getProcessId(), + LoggerEnum.INFO.name()); + Map userMap = esUser.get(0); + if (!isSame(shadowUser, userMap)) { + ProjectLogger.log( + "ShadowUserProcessor:updateUser: provided user details doesn't match with existing user details with processId" + + shadowUser.getProcessId() + + userMap, + LoggerEnum.INFO.name()); + List userIds = new ArrayList<>(); + userIds.add((String) userMap.get(JsonKey.ID)); + updateUserInShadowDb(null, shadowUser, ClaimStatus.ELIGIBLE.getValue(), userIds); + ProjectLogger.log( + "ShadowUserProcessor:updateUser: calling FeedUtil.saveFeed method for user id " + + userIds.get(0), + LoggerEnum.INFO.name()); + FeedUtil.saveFeed(shadowUser, userIds); + } + } else if (esUser.size() > 1) { + ProjectLogger.log( + "ShadowUserProcessor:updateUser:GOT response from ES :" + esUser, + LoggerEnum.INFO.name()); + updateUserInShadowDb( + null, shadowUser, ClaimStatus.MULTIMATCH.getValue(), getMatchingUserIds(esUser)); + } + } else { + ProjectLogger.log( + "ShadowUserProcessor:updateUser:SKIPPING SHADOW USER:" + shadowUser.toString(), + LoggerEnum.INFO.name()); + } + esUser.clear(); + } + + private void generateTelemetry(String userId, String rootOrgId, ShadowUser shadowUser) { + // ExecutionContext.getCurrent() + // .setRequestContext(getTelemetryContextByProcessId((String) shadowUser.getProcessId())); + ProjectLogger.log( + "ShadowUserProcessor:generateTelemetry:generate telemetry:" + shadowUser.toString(), + LoggerEnum.INFO.name()); + Map targetObject = new HashMap<>(); + Map rollUp = new HashMap<>(); + rollUp.put("l1", rootOrgId); + List> correlatedObject = new ArrayList<>(); + // ExecutionContext.getCurrent().getRequestContext().put(JsonKey.ROLLUP, rollUp); + TelemetryUtil.generateCorrelatedObject( + shadowUser.getProcessId(), JsonKey.PROCESS_ID, null, correlatedObject); + targetObject = + TelemetryUtil.generateTargetObject( + userId, StringUtils.capitalize(JsonKey.USER), JsonKey.MIGRATION_USER_OBJECT, null); + // TelemetryUtil.telemetryProcessingCall( + // mapper.convertValue(shadowUser, Map.class), targetObject, correlatedObject); + } + + /** + * this method will be used to get all the userIds got from ES response by searching with + * phone/email + custoRootOrgId + * + * @param esUser + * @return + */ + private List getMatchingUserIds(List> esUser) { + ProjectLogger.log( + "ShadowUserProcessor:getMatchingUserIds:GOT response from counting matchingUserIds:" + + esUser.size(), + LoggerEnum.INFO.name()); + List matchingUserIds = new ArrayList<>(); + esUser + .stream() + .forEach( + singleEsUser -> { + matchingUserIds.add((String) singleEsUser.get(JsonKey.ID)); + }); + return matchingUserIds; + } + + private void updateUserInUserTable( + int flagValue, String userId, String rootOrgId, ShadowUser shadowUser) { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.FIRST_NAME, shadowUser.getName()); + propertiesMap.put(JsonKey.ID, userId); + if (!(UserFlagUtil.assignUserFlagValues(flagValue).get(JsonKey.STATE_VALIDATED))) { + ProjectLogger.log( + "ShadowUserProcessor:updateUserInUserTable: updating Flag Value", LoggerEnum.INFO.name()); + propertiesMap.put( + JsonKey.FLAGS_VALUE, flagValue + UserFlagEnum.STATE_VALIDATED.getUserFlagValue()); + } + propertiesMap.put(JsonKey.UPDATED_BY, shadowUser.getAddedBy()); + propertiesMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + if (shadowUser.getUserStatus() == ProjectUtil.Status.ACTIVE.getValue()) { + propertiesMap.put(JsonKey.IS_DELETED, false); + propertiesMap.put(JsonKey.STATUS, ProjectUtil.Status.ACTIVE.getValue()); + } else { + propertiesMap.put(JsonKey.IS_DELETED, true); + propertiesMap.put(JsonKey.STATUS, ProjectUtil.Status.INACTIVE.getValue()); + } + propertiesMap.put(JsonKey.USER_TYPE, UserType.TEACHER.getTypeName()); + propertiesMap.put(JsonKey.CHANNEL, shadowUser.getChannel()); + propertiesMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + ProjectLogger.log( + "ShadowUserProcessor:updateUserInUserTable: properties map formed for user update: " + + propertiesMap, + LoggerEnum.INFO.name()); + Response response = + cassandraOperation.updateRecord( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), propertiesMap); + ProjectLogger.log( + "ShadowUserProcessor:updateUserInUserTable:user is updated with shadow user:RESPONSE FROM CASSANDRA IS:" + + response.getResult(), + LoggerEnum.INFO.name()); + generateTelemetry(userId, rootOrgId, shadowUser); + } + + /** + * this method + * + * @return + */ + private String getCustodianOrgId() { + if (StringUtils.isNotBlank(custodianOrgId)) { + ProjectLogger.log( + "ShadowUserProcessor:getCustodianOrgId:CUSTODIAN ORD ID FOUND in cache:" + custodianOrgId, + LoggerEnum.INFO.name()); + return custodianOrgId; + } + Response response = + cassandraOperation.getRecordById( + JsonKey.SUNBIRD, JsonKey.SYSTEM_SETTINGS_DB, JsonKey.CUSTODIAN_ORG_ID); + List> result = new ArrayList<>(); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + result = ((List) response.getResult().get(JsonKey.RESPONSE)); + Map resultMap = result.get(0); + custodianOrgId = (String) resultMap.get(JsonKey.VALUE); + ProjectLogger.log( + "ShadowUserProcessor:getCustodianOrgId:CUSTODIAN ORD ID FOUND in DB:" + custodianOrgId, + LoggerEnum.INFO.name()); + } + + if (StringUtils.isBlank(custodianOrgId)) { + ProjectLogger.log( + "ShadowUserProcessor:getCustodianOrgId:No CUSTODIAN ORD ID FOUND PLEASE HAVE THAT IN YOUR ENVIRONMENT", + LoggerEnum.ERROR.name()); + System.exit(-1); + } + return custodianOrgId; + } + + private FutureCallback getSyncCallback() { + return new FutureCallback() { + @Override + public void onSuccess(ResultSet result) { + Map columnMap = CassandraUtil.fetchColumnsMapping(result); + try { + Iterator resultIterator = result.iterator(); + while (resultIterator.hasNext()) { + Row row = resultIterator.next(); + Map doc = syncDataForEachRow(row, columnMap); + ShadowUser singleShadowUser = mapper.convertValue(doc, ShadowUser.class); + processSingleShadowUser(singleShadowUser); + ProjectLogger.log( + "ShadowUserProcessor:getSyncCallback:SUCCESS:SYNC CALLBACK SUCCESSFULLY PROCESSED for Shadow user: " + + singleShadowUser.toString(), + LoggerEnum.INFO.name()); + } + ProjectLogger.log( + "ShadowUserProcessor:getSyncCallback:SUCCESS:SYNC CALLBACK SUCCESSFULLY MIGRATED ALL Shadow user", + LoggerEnum.INFO.name()); + + } catch (Exception e) { + ProjectLogger.log( + "ShadowUserProcessor:getSyncCallback:SUCCESS:ERROR OCCURRED WHILE GETTING SYNC CALLBACKS" + + e, + LoggerEnum.ERROR.name()); + } + } + + @Override + public void onFailure(Throwable t) { + ProjectLogger.log( + "ShadowUserProcessor:getSyncCallback:FAILURE:ERROR OCCURRED WHILE GETTING SYNC CALLBACKS" + + t, + LoggerEnum.ERROR.name()); + } + }; + } + + private Map syncDataForEachRow(Row row, Map columnMap) { + Map rowMap = new HashMap<>(); + columnMap + .entrySet() + .forEach( + entry -> { + Object value = row.getObject(entry.getValue()); + rowMap.put(entry.getKey(), value); + }); + ProjectLogger.log( + "ShadowUserProcessor:syncDataForEachRow:row map returned " + rowMap, + LoggerEnum.INFO.name()); + return rowMap; + } + + private void processAllUnclaimedUser() { + + ProjectLogger.log( + "ShadowUserProcessor:processAllUnclaimedUser:started processing all unclaimed user", + LoggerEnum.INFO.name()); + getUnclaimedRowsFromShadowUserDb(); + } + + private void getUnclaimedRowsFromShadowUserDb() { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.CLAIM_STATUS, ClaimStatus.UNCLAIMED.getValue()); + cassandraOperation.applyOperationOnRecordsAsync( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, propertiesMap, null, getSyncCallback()); + propertiesMap.clear(); + } + + private boolean isSame(ShadowUser shadowUser, Map esUserMap) { + String orgId = getOrgId(shadowUser); + if (!shadowUser.getName().equalsIgnoreCase((String) esUserMap.get(JsonKey.FIRST_NAME))) { + return false; + } + if (StringUtils.isNotBlank(orgId) && !getOrganisationIds(esUserMap).contains(orgId)) { + return false; + } + if (shadowUser.getUserStatus() != (int) (esUserMap.get(JsonKey.STATUS))) { + return false; + } + if (StringUtils.isBlank(orgId)) { + return false; + } + return true; + } + + private void updateUserInShadowDb( + String userId, ShadowUser shadowUser, int claimStatus, List matchingUserIds) { + Map propertiesMap = new HashMap<>(); + propertiesMap.put(JsonKey.CLAIM_STATUS, claimStatus); + propertiesMap.put(JsonKey.PROCESS_ID, shadowUser.getProcessId()); + propertiesMap.put(JsonKey.USER_ID, userId); + propertiesMap.put(JsonKey.USER_IDs, matchingUserIds); + Map compositeKeysMap = new HashMap<>(); + compositeKeysMap.put(JsonKey.CHANNEL, shadowUser.getChannel()); + compositeKeysMap.put(JsonKey.USER_EXT_ID, shadowUser.getUserExtId()); + Response response = + cassandraOperation.updateRecord( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, propertiesMap, compositeKeysMap); + ProjectLogger.log( + "ShadowUserProcessor:updateUserInShadowDb:update:with processId: " + + shadowUser.getProcessId() + + " :and response is:" + + response, + LoggerEnum.INFO.name()); + } + + private String getOrgId(ShadowUser shadowUser) { + if (StringUtils.isNotBlank(shadowUser.getOrgExtId())) { + String orgId = + extOrgIdMap.get(shadowUser.getChannel().concat(":").concat(shadowUser.getOrgExtId())); + if (StringUtils.isNotBlank(orgId)) { + return orgId; + } + Map request = new HashMap<>(); + Map filters = new HashMap<>(); + filters.put(JsonKey.EXTERNAL_ID, shadowUser.getOrgExtId().toLowerCase()); + filters.put(JsonKey.CHANNEL, shadowUser.getChannel()); + request.put(JsonKey.FILTERS, filters); + ProjectLogger.log( + "ShadowUserProcessor:getOrgId: request map prepared to query elasticsearch for org id :" + + filters + + "with processId" + + shadowUser.getProcessId(), + LoggerEnum.INFO.name()); + SearchDTO searchDTO = ElasticSearchHelper.createSearchDTO(request); + Map response = + (Map) + ElasticSearchHelper.getResponseFromFuture( + elasticSearchService.search( + searchDTO, ProjectUtil.EsType.organisation.getTypeName())); + List> orgData = + ((List>) response.get(JsonKey.CONTENT)); + if (CollectionUtils.isNotEmpty(orgData)) { + Map orgMap = orgData.get(0); + extOrgIdMap.put( + shadowUser.getChannel().concat(":").concat(shadowUser.getOrgExtId()), + (String) orgMap.get(JsonKey.ID)); + return (String) orgMap.get(JsonKey.ID); + } + } + return StringUtils.EMPTY; + } + + private List getOrganisationIds(Map dbUser) { + List organisationsIds = new ArrayList<>(); + ((List>) dbUser.get(JsonKey.ORGANISATIONS)) + .stream() + .forEach( + organisation -> { + organisationsIds.add((String) organisation.get(JsonKey.ORGANISATION_ID)); + }); + return organisationsIds; + } + + private void syncUserToES(String userId) { + Map fullUserDetails = Util.getUserDetails(userId, null); + try { + Future future = elasticSearchService.update(JsonKey.USER, userId, fullUserDetails); + if ((boolean) ElasticSearchHelper.getResponseFromFuture(future)) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:updateUserStatus: data successfully updated to elastic search with userId:" + .concat(userId + ""), + LoggerEnum.INFO.name()); + } + } catch (Exception e) { + e.printStackTrace(); + ProjectLogger.log( + "ShadowUserMigrationScheduler:syncUserToES: data failed to updates in elastic search with userId:" + .concat(userId + ""), + LoggerEnum.ERROR.name()); + } + } + + private void registerUserToOrg(String userId, String organisationId) { + Map reqMap = new WeakHashMap<>(); + List roles = new ArrayList<>(); + roles.add(ProjectUtil.UserRole.PUBLIC.getValue()); + reqMap.put(JsonKey.ROLES, roles); + String hashTagId = hashTagIdMap.get(organisationId); + if (StringUtils.isBlank(hashTagId)) { + hashTagId = Util.getHashTagIdFromOrgId(organisationId); + hashTagIdMap.put(organisationId, hashTagId); + } + reqMap.put(JsonKey.HASHTAGID, hashTagId); + reqMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(1)); + reqMap.put(JsonKey.USER_ID, userId); + reqMap.put(JsonKey.ORGANISATION_ID, organisationId); + reqMap.put(JsonKey.ORG_JOIN_DATE, ProjectUtil.getFormattedDate()); + reqMap.put(JsonKey.IS_DELETED, false); + Util.DbInfo usrOrgDb = Util.dbInfoMap.get(JsonKey.USR_ORG_DB); + try { + Response response = + cassandraOperation.insertRecord(usrOrgDb.getKeySpace(), usrOrgDb.getTableName(), reqMap); + ProjectLogger.log( + "ShadowUserProcessor:registerUserToOrg:user status while registration with org is:" + + response.getResult(), + LoggerEnum.INFO.name()); + + } catch (Exception e) { + ProjectLogger.log( + "ShadowUserProcessor:registerUserToOrg:user is failed to register with org" + userId, + LoggerEnum.ERROR.name()); + } + } + + private Map getTelemetryContextByProcessId(String processId) { + + if (MapUtils.isNotEmpty(processIdtelemetryCtxMap.get(processId))) { + return processIdtelemetryCtxMap.get(processId); + } + Map contextMap = new HashMap<>(); + Map telemetryContext = new HashMap<>(); + Response response = + cassandraOperation.getRecordById( + bulkUploadDbInfo.getKeySpace(), bulkUploadDbInfo.getTableName(), processId); + List> result = new ArrayList<>(); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + result = ((List) response.getResult().get(JsonKey.RESPONSE)); + Map responseMap = result.get(0); + contextMap = (Map) responseMap.get(JsonKey.CONTEXT_TELEMETRY); + telemetryContext.putAll(contextMap); + processIdtelemetryCtxMap.put(processId, telemetryContext); + } + ProjectLogger.log( + "ShadowUserMigrationScheduler:getFullRecordFromProcessId:got single row data from bulk_upload_process with processId:" + + processId, + LoggerEnum.INFO.name()); + return telemetryContext; + } + + /** + * METHOD WILL RETURN THE LIST OF SHADOW USER WHICH IS PRE EXISTING WITH USERID this method will + * give all the record which are not claimed failed and rejected i.e will update the claim status + * of the user who are ELIGIBLE. + * + * @param userId + * @return + */ + public List getMultiMatchRecords(String userId) { + List shadowUsersList = new ArrayList<>(); + Response response = + cassandraOperation.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USERIDS, userId, null); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + ((List) response.getResult().get(JsonKey.RESPONSE)) + .stream() + .forEach( + shadowMap -> { + ShadowUser shadowUser = mapper.convertValue(shadowMap, ShadowUser.class); + if (shadowUser.getClaimStatus() != ClaimStatus.CLAIMED.getValue() + && shadowUser.getClaimStatus() != ClaimStatus.REJECTED.getValue() + && shadowUser.getClaimStatus() != ClaimStatus.FAILED.getValue()) { + shadowUsersList.add(shadowUser); + } + }); + } + return shadowUsersList; + } + + /** + * userExtId, channel , userIds, claimStatus all the user found with same id in shadow_user table + * there claim status will be updated to multimatch + * + * @param shadowUserList + */ + private void changeStatusToMultiMatch(List shadowUserList) { + shadowUserList + .stream() + .forEach( + shadowUser -> { + if (shadowUser.getClaimStatus() != ClaimStatus.CLAIMED.getValue()) { + updateUserInShadowDb( + null, shadowUser, ClaimStatus.MULTIMATCH.getValue(), shadowUser.getUserIds()); + // TODO DELETE ENTRY FROM ALERTS TABLE + } + }); + } + + /** + * this method will return all the user who doesn't belong to the same provided channel This + * filtering will be needed to avoid update of claimStatus to MULTIMATCH of same user while + * updating. + * + * @param channel + * @param shadowUserList + */ + private List getDiffChannelUsers(String channel, List shadowUserList) { + + List filterShadowUser = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(shadowUserList)) { + shadowUserList + .stream() + .forEach( + singleShadowUser -> { + if (!StringUtils.equalsIgnoreCase(singleShadowUser.getChannel(), channel)) { + filterShadowUser.add(singleShadowUser); + } + }); + } + return filterShadowUser; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/BaseJob.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/BaseJob.java new file mode 100644 index 0000000000..bcd143840b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/BaseJob.java @@ -0,0 +1,36 @@ +package org.sunbird.common.quartz.scheduler; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashSet; +import org.quartz.Job; +import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +/** @author Mahesh Kumar Gangula */ +public abstract class BaseJob implements Job { + + protected Util.DbInfo bulkUploadDbInfo = Util.dbInfoMap.get(JsonKey.BULK_OP_DB); + protected CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + protected ObjectMapper mapper = new ObjectMapper(); + protected HashSet verifiedChannelOrgExternalIdSet = new HashSet<>(); + protected ElasticSearchService elasticSearchService = EsClientFactory.getInstance(JsonKey.REST); + protected DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + protected EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + + public void tellToBGRouter(Request request) { + SunbirdMWService.tellToBGRouter(request, ActorRef.noSender()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/ChannelRegistrationScheduler.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/ChannelRegistrationScheduler.java new file mode 100644 index 0000000000..6669dcfc3b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/ChannelRegistrationScheduler.java @@ -0,0 +1,50 @@ +package org.sunbird.common.quartz.scheduler; + +import java.util.Calendar; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.quartz.JobExecutionContext; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; + +public class ChannelRegistrationScheduler extends BaseJob { + + @Override + public void execute(JobExecutionContext ctx) { + ProjectLogger.log( + "ChannelRegistrationScheduler:execute: Running channel registration Scheduler Job at: " + + Calendar.getInstance().getTime() + + " triggered by: " + + ctx.getJobDetail().toString(), + LoggerEnum.INFO.name()); + Request request = new Request(); + request.setOperation(BackgroundOperations.registerChannel.name()); + Response response = + cassandraOperation.getRecordById( + JsonKey.SUNBIRD, JsonKey.SYSTEM_SETTINGS_DB, JsonKey.CHANNEL_REG_STATUS_ID); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (null != responseList && !responseList.isEmpty()) { + Map resultMap = responseList.get(0); + ProjectLogger.log( + "value for CHANNEL_REG_STATUS_ID (003) from SYSTEM_SETTINGS_DB is : " + + (String) resultMap.get(JsonKey.VALUE)); + if (StringUtils.isBlank((String) resultMap.get(JsonKey.VALUE)) + && !Boolean.parseBoolean((String) resultMap.get(JsonKey.VALUE))) { + ProjectLogger.log( + "calling ChannelRegistrationActor from ChannelRegistrationScheduler execute method."); + tellToBGRouter(request); + } + } else { + ProjectLogger.log( + "calling ChannelRegistrationActor from ChannelRegistrationScheduler execute method, " + + "entry for CHANNEL_REG_STATUS_ID (003) is null."); + tellToBGRouter(request); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/OnDemandSchedulerManager.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/OnDemandSchedulerManager.java new file mode 100644 index 0000000000..cba9a8bdfe --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/OnDemandSchedulerManager.java @@ -0,0 +1,90 @@ +package org.sunbird.common.quartz.scheduler; + +import static org.quartz.SimpleScheduleBuilder.simpleSchedule; + +import java.util.HashMap; +import java.util.Map; +import org.quartz.*; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; + +public class OnDemandSchedulerManager extends SchedulerManager { + + private static OnDemandSchedulerManager onDemandSchedulerManager = null; + private static final String BULK_UPLOAD = "bulkupload"; + private static final String SHADOW_USER = "shadowuser"; + + public static Map schedulerMap = new HashMap<>(); + + public OnDemandSchedulerManager() { + if (schedulerMap.isEmpty()) { + schedulerMap.put(BULK_UPLOAD, "uploadVerify"); + schedulerMap.put(SHADOW_USER, "migrateShadowUser"); + } + } + + public void scheduleOnDemand(String identifier, String job) { + ProjectLogger.log( + "onDemandSchedulerManager:scheduleOnDemand:" + job + " started", LoggerEnum.INFO.name()); + JobDetail jobDetail = null; + JobBuilder jobBuilder = null; + String jobName = schedulerMap.get(job); + if (job.equals(SHADOW_USER)) { + jobBuilder = JobBuilder.newJob(ShadowUserMigrationScheduler.class); + } else if (job.equals(BULK_UPLOAD)) { + jobBuilder = JobBuilder.newJob(UploadLookUpScheduler.class); + } + jobDetail = + jobBuilder + .requestRecovery(true) + .withDescription("Scheduler for migrating shadow user ") + .withIdentity(jobName + "Scheduler", identifier) + .build(); + Trigger trigger = + TriggerBuilder.newTrigger() + .withIdentity(jobName + "Trigger", identifier) + .startNow() + .withSchedule(simpleSchedule().withIntervalInSeconds(1).withRepeatCount(0)) + .build(); + try { + if (scheduler.checkExists(jobDetail.getKey())) { + scheduler.deleteJob(jobDetail.getKey()); + } + scheduler.scheduleJob(jobDetail, trigger); + scheduler.start(); + ProjectLogger.log( + "onDemandSchedulerManager:scheduleOnDemand:scheduler ended", LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log( + "onDemandSchedulerManager:scheduleOnDemand Error occurred " + e.getMessage(), + LoggerEnum.ERROR.name()); + } + } + + public static OnDemandSchedulerManager getInstance() { + if (onDemandSchedulerManager == null) { + synchronized (OnDemandSchedulerManager.class) { + if (onDemandSchedulerManager == null) { + onDemandSchedulerManager = new OnDemandSchedulerManager(); + } + } + } + return onDemandSchedulerManager; + } + + public void triggerScheduler(String[] jobs) { + String identifier = "NetOps-PC1502295457753"; + for (String job : jobs) { + switch (job) { + case BULK_UPLOAD: + case SHADOW_USER: + scheduleOnDemand(identifier, job); + break; + default: + ProjectLogger.log( + "OnDemandSchedulerManager:triggerScheduler: There is no such job", + LoggerEnum.INFO.name()); + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/SchedulerManager.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/SchedulerManager.java new file mode 100644 index 0000000000..20ec5cbca1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/SchedulerManager.java @@ -0,0 +1,311 @@ +/** */ +package org.sunbird.common.quartz.scheduler; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.apache.commons.lang3.StringUtils; +import org.quartz.CronScheduleBuilder; +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SimpleScheduleBuilder; +import org.quartz.Trigger; +import org.quartz.TriggerBuilder; +import org.quartz.impl.StdSchedulerFactory; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +/** + * This class will manage all the Quartz scheduler. We need to call the schedule method at one time. + * we are calling this method from Util.java class. + * + * @author Manzarul + */ +public class SchedulerManager { + + private static final String FILE = "quartz.properties"; + public static Scheduler scheduler = null; + private static SchedulerManager schedulerManager = null; + + public SchedulerManager() { + schedule(); + } + + /** This method will register the quartz scheduler job. */ + public void schedule() { + ProjectLogger.log( + "SchedulerManager:schedule: Call to start scheduler jobs - org.sunbird.common.quartz.scheduler.SchedulerManager", + LoggerEnum.INFO.name()); + + try { + Thread.sleep(240000); + boolean isEmbedded = false; + Properties configProp = null; + String embeddVal = System.getenv(JsonKey.SUNBIRD_QUARTZ_MODE); + if (JsonKey.EMBEDDED.equalsIgnoreCase(embeddVal)) { + isEmbedded = true; + } else { + configProp = setUpClusterMode(); + } + if (!isEmbedded && configProp != null) { + + StdSchedulerFactory schedulerFactory = new StdSchedulerFactory(configProp); + ProjectLogger.log("Quartz scheduler is running in cluster mode.", LoggerEnum.INFO.name()); + scheduler = schedulerFactory.getScheduler("MyScheduler"); + + if (null == scheduler) { + Thread.sleep(5000); + scheduler = schedulerFactory.getScheduler(); + } + + String schedulerName = scheduler.getSchedulerName(); + ProjectLogger.log( + "Quartz scheduler is running in cluster mode. scheduler Name is: " + schedulerName, + LoggerEnum.INFO.name()); + } else { + ProjectLogger.log("Quartz scheduler is running in embedded mode.", LoggerEnum.INFO.name()); + scheduler = new StdSchedulerFactory().getScheduler(); + } + String identifier = "NetOps-PC1502295457753"; + + scheduleBulkUploadJob(identifier); + scheduleUpdateUserCountJob(identifier); + scheduleChannelReg(identifier); + scheduleShadowUser(identifier); + + } catch (Exception e) { + ProjectLogger.log( + "SchedulerManager:schedule: Error in starting scheduler jobs - org.sunbird.common.quartz.scheduler.SchedulerManager " + + e.getMessage(), + LoggerEnum.ERROR.name()); + } finally { + registerShutDownHook(); + } + ProjectLogger.log( + "SchedulerManager:schedule: started scheduler jobs - org.sunbird.common.quartz.scheduler.SchedulerManager", + LoggerEnum.INFO.name()); + } + + public static void scheduleChannelReg(String identifier) { + // add another job for registering channel to ekstep. + // 1- create a job and bind with class which is implementing Job + // interface. + JobDetail channelRegistrationJob = + JobBuilder.newJob(ChannelRegistrationScheduler.class) + .requestRecovery(true) + .withDescription("Scheduler for channel registration") + .withIdentity("channelRegistrationScheduler", identifier) + .build(); + + // 2- Create a trigger object that will define frequency of run. + // It will run only once after server startup + Trigger channelRegistrationTrigger = + TriggerBuilder.newTrigger() + .withIdentity("channelRegistrationScheduler", identifier) + .withSchedule(SimpleScheduleBuilder.repeatMinutelyForTotalCount(1)) + .build(); + try { + if (scheduler.checkExists(channelRegistrationJob.getKey())) { + scheduler.deleteJob(channelRegistrationJob.getKey()); + } + scheduler.scheduleJob(channelRegistrationJob, channelRegistrationTrigger); + scheduler.start(); + ProjectLogger.log( + "SchedulerManager:scheduleChannelReg: channelRegistration schedular started", + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + private void scheduleUpdateUserCountJob(String identifier) { + // add another job for updating user count to Location Table. + // 1- create a job and bind with class which is implementing Job + // interface. + JobDetail updateUserCountJob = + JobBuilder.newJob(UpdateUserCountScheduler.class) + .requestRecovery(true) + .withDescription("Scheduler for updating user count for each geo location") + .withIdentity("updateUserCountScheduler", identifier) + .build(); + + // 2- Create a trigger object that will define frequency of run. + // This will run every day 2:00 AM + Trigger updateUserCountTrigger = + TriggerBuilder.newTrigger() + .withIdentity("updateUserCountTrigger", identifier) + .withSchedule( + CronScheduleBuilder.cronSchedule( + PropertiesCache.getInstance().getProperty("quartz_update_user_count_timer"))) + .build(); + try { + if (scheduler.checkExists(updateUserCountJob.getKey())) { + scheduler.deleteJob(updateUserCountJob.getKey()); + } + scheduler.scheduleJob(updateUserCountJob, updateUserCountTrigger); + scheduler.start(); + ProjectLogger.log( + "SchedulerManager:scheduleUpdateUserCountJob: UpdateUserCount schedular started", + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + private void scheduleBulkUploadJob(String identifier) { + // add another job for verifying the bulk upload part. + // 1- create a job and bind with class which is implementing Job + // interface. + JobDetail uploadVerifyJob = + JobBuilder.newJob(UploadLookUpScheduler.class) + .requestRecovery(true) + .withDescription("Scheduler for bulk upload retry") + .withIdentity("uploadVerifyScheduler", identifier) + .build(); + + // 2- Create a trigger object that will define frequency of run. + // This will run every day 4:30 AM and in UTC 11 PM + Trigger uploadTrigger = + TriggerBuilder.newTrigger() + .withIdentity("uploadVerifyTrigger", identifier) + .withSchedule( + CronScheduleBuilder.cronSchedule( + PropertiesCache.getInstance().getProperty("quartz_upload_timer"))) + .build(); + try { + if (scheduler.checkExists(uploadVerifyJob.getKey())) { + scheduler.deleteJob(uploadVerifyJob.getKey()); + } + scheduler.scheduleJob(uploadVerifyJob, uploadTrigger); + scheduler.start(); + ProjectLogger.log( + "SchedulerManager:scheduleBulkUploadJob: UploadLookUpScheduler schedular started", + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + /** + * This method will do the Quartz scheduler set up in cluster mode. + * + * @return Properties + * @throws IOException + */ + public Properties setUpClusterMode() throws IOException { + Properties configProp = new Properties(); + InputStream in = this.getClass().getClassLoader().getResourceAsStream(FILE); + String host = System.getenv(JsonKey.SUNBIRD_PG_HOST); + String port = System.getenv(JsonKey.SUNBIRD_PG_PORT); + String db = System.getenv(JsonKey.SUNBIRD_PG_DB); + String username = System.getenv(JsonKey.SUNBIRD_PG_USER); + String password = System.getenv(JsonKey.SUNBIRD_PG_PASSWORD); + if (!StringUtils.isBlank(host) + && !StringUtils.isBlank(port) + && !StringUtils.isBlank(db) + && !StringUtils.isBlank(username) + && !StringUtils.isBlank(password)) { + ProjectLogger.log( + "Taking Postgres value from Environment variable...", LoggerEnum.INFO.name()); + configProp.load(in); + configProp.put( + "org.quartz.dataSource.MySqlDS.URL", "jdbc:postgresql://" + host + ":" + port + "/" + db); + configProp.put("org.quartz.dataSource.MySqlDS.user", username); + configProp.put("org.quartz.dataSource.MySqlDS.password", password); + configProp.put("org.quartz.scheduler.instanceName", "MyScheduler"); + ProjectLogger.log( + "SchedulerManager:setUpClusterMode: Connection is established from environment variable", + LoggerEnum.INFO); + } else { + ProjectLogger.log( + "SchedulerManager:setUpClusterMode: Environment variable is not set for postgres SQl.", + LoggerEnum.INFO.name()); + configProp = null; + } + return configProp; + } + + public static SchedulerManager getInstance() { + if (schedulerManager != null) { + return schedulerManager; + } else { + schedulerManager = new SchedulerManager(); + } + return schedulerManager; + } + + /** + * This class will be called by registerShutDownHook to register the call inside jvm , when jvm + * terminate it will call the run method to clean up the resource. + * + * @author Manzarul + */ + static class ResourceCleanUp extends Thread { + @Override + public void run() { + ProjectLogger.log( + "SchedulerManager:ResourceCleanUp: started resource cleanup for Quartz job.", + LoggerEnum.INFO); + try { + scheduler.shutdown(); + } catch (SchedulerException e) { + ProjectLogger.log(e.getMessage(), e); + } + ProjectLogger.log( + "SchedulerManager:ResourceCleanUp: completed resource cleanup Quartz job.", + LoggerEnum.INFO); + } + } + + /** Register the hook for resource clean up. this will be called when jvm shut down. */ + public static void registerShutDownHook() { + Runtime runtime = Runtime.getRuntime(); + runtime.addShutdownHook(new ResourceCleanUp()); + ProjectLogger.log( + "SchedulerManager:registerShutDownHook: ShutDownHook registered for Quartz scheduler.", + LoggerEnum.INFO); + } + + private void scheduleShadowUser(String identifier) { + ProjectLogger.log( + "SchedulerManager:scheduleShadowUser:scheduleShadowUser scheduler started", + LoggerEnum.INFO.name()); + ProjectLogger.log( + "SchedulerManager:scheduleShadowUser:scheduleShadowUser scheduler started seconde log", + LoggerEnum.INFO.name()); + JobDetail migrateShadowUserJob = + JobBuilder.newJob(ShadowUserMigrationScheduler.class) + .requestRecovery(true) + .withDescription("Scheduler for migrating shadow user ") + .withIdentity("migrateShadowUserScheduler", identifier) + .build(); + String shadowUserTime = + PropertiesCache.getInstance().getProperty("quartz_shadow_user_migration_timer"); + ProjectLogger.log( + "SchedulerManager:scheduleShadowUser: schedule time is : " + shadowUserTime, + LoggerEnum.INFO.name()); + Trigger migrateShadowUserTrigger = + TriggerBuilder.newTrigger() + .withIdentity("migrateShadowUserTrigger", identifier) + .withSchedule(CronScheduleBuilder.cronSchedule(shadowUserTime)) + .build(); + try { + if (scheduler.checkExists(migrateShadowUserJob.getKey())) { + scheduler.deleteJob(migrateShadowUserJob.getKey()); + } + scheduler.scheduleJob(migrateShadowUserJob, migrateShadowUserTrigger); + scheduler.start(); + ProjectLogger.log( + "SchedulerManager:scheduleShadowUser:scheduleShadowUser scheduler ended", + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log( + "SchedulerManager:scheduleShadowUser Error occurred " + e.getMessage(), + LoggerEnum.ERROR.name()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/ShadowUserMigrationScheduler.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/ShadowUserMigrationScheduler.java new file mode 100644 index 0000000000..28a3545a11 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/ShadowUserMigrationScheduler.java @@ -0,0 +1,496 @@ +package org.sunbird.common.quartz.scheduler; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.sql.Timestamp; +import java.util.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.quartz.JobExecutionContext; +import org.sunbird.bean.ClaimStatus; +import org.sunbird.bean.MigrationUser; +import org.sunbird.bean.ShadowUser; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ShadowUserProcessor; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.learner.actors.bulkupload.model.BulkMigrationUser; + +public class ShadowUserMigrationScheduler extends BaseJob { + + @Override + public void execute(JobExecutionContext jobExecutionContext) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:execute:Running Shadow User Upload Scheduler Job at: " + + Calendar.getInstance().getTime() + + " triggered by: " + + jobExecutionContext.getJobDetail().toString(), + LoggerEnum.INFO.name()); + startMigration(); + } + + public void startMigration() { + List unprocessedRecordIds = getUnprocessedRecordIds(); + ProjectLogger.log( + "ShadowUserMigrationScheduler:startMigration:Got Bulk Upload Db unprocessed and failed records size is:" + + unprocessedRecordIds.size(), + LoggerEnum.INFO.name()); + processRecords(unprocessedRecordIds); + ShadowUserProcessor processorObject = new ShadowUserProcessor(); + processorObject.process(); + unprocessedRecordIds.clear(); + ProjectLogger.log( + "ShadowUserMigrationScheduler:execute:Scheduler Job ended for shadow user migration", + LoggerEnum.INFO.name()); + } + + /** + * - fetch rows from bulk upload table whose status is less than 2 - update the bulk upload table + * row status to processing - encrypting email and phone - start processing single row - fetch the + * single row data - Get List of Migration(csv) user from the row - process each Migration(csv) + * user - update the bulk upload table row status to completed and add message to success - if + * fails update the bulk upload row status to failed and add failureResult + */ + private void processRecords(List unprocessedRecordIds) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:processRecords:Scheduler Job Started for ShadowUser Migration", + LoggerEnum.INFO.name()); + unprocessedRecordIds + .stream() + .forEach( + id -> { + Map row = getFullRecordFromProcessId(id); + BulkMigrationUser bulkMigrationUser = convertRowToObject(row); + row.clear(); + try { + updateStatusInUserBulkTable( + bulkMigrationUser.getId(), + ProjectUtil.BulkProcessStatus.IN_PROGRESS.getValue()); + List migrationUserList = getMigrationUserAsList(bulkMigrationUser); + migrationUserList + .parallelStream() + .forEach( + singleMigrationUser -> { + encryptEmailAndPhone(singleMigrationUser); + processSingleMigUser( + bulkMigrationUser.getCreatedBy(), + bulkMigrationUser.getId(), + singleMigrationUser); + }); + updateMessageInBulkUserTable( + bulkMigrationUser.getId(), JsonKey.SUCCESS_RESULT, JsonKey.SUCCESS); + } catch (Exception e) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:processRecords:error occurred ".concat(e + ""), + LoggerEnum.ERROR.name()); + updateMessageInBulkUserTable( + bulkMigrationUser.getId(), JsonKey.FAILURE_RESULT, e.getMessage()); + } + }); + ProjectLogger.log( + "ShadowUserMigrationScheduler:processRecords:started stage3__________________________-", + LoggerEnum.INFO.name()); + } + + private void processSingleMigUser( + String createdBy, String processId, MigrationUser singleMigrationUser) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:processSingleMigUser:Single migration User Started processing with processId:" + + processId, + LoggerEnum.INFO.name()); + Map existingUserDetails = + getShadowExistingUserDetails( + singleMigrationUser.getChannel(), singleMigrationUser.getUserExternalId()); + if (MapUtils.isEmpty(existingUserDetails)) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:processSingleMigUser:existing user not found with processId:" + + processId, + LoggerEnum.INFO.name()); + insertShadowUserToDb(createdBy, processId, singleMigrationUser); + } else { + ProjectLogger.log( + "ShadowUserMigrationScheduler:processSingleMigUser:existing user found with processId:" + + processId, + LoggerEnum.INFO.name()); + ShadowUser shadowUser = mapper.convertValue(existingUserDetails, ShadowUser.class); + updateUser(processId, singleMigrationUser, shadowUser); + } + } + + /** + * this method will read rows from the bulk_upload_process table who has status less than 2 + * + * @return list + */ + private List getUnprocessedRecordIds() { + Response response = + cassandraOperation.getRecordByObjectType( + bulkUploadDbInfo.getKeySpace(), + bulkUploadDbInfo.getTableName(), + JsonKey.ID, + JsonKey.STATUS, + ProjectUtil.BulkProcessStatus.INTERRUPT.getValue(), + JsonKey.MIGRATION_USER_OBJECT); + List> result = new ArrayList<>(); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + result = ((List) response.getResult().get(JsonKey.RESPONSE)); + } + List processIds = new ArrayList<>(); + result + .stream() + .forEach( + rowMap -> { + processIds.add((String) rowMap.get(JsonKey.ID)); + }); + ProjectLogger.log( + "ShadowUserMigrationScheduler:getUnprocessedRecordIds:got rows from Bulk user table is:" + .concat(result.size() + ""), + LoggerEnum.INFO.name()); + return processIds; + } + + private Map getFullRecordFromProcessId(String processId) { + + int FIRST_RECORD = 0; + Response response = + cassandraOperation.getRecordById( + bulkUploadDbInfo.getKeySpace(), bulkUploadDbInfo.getTableName(), processId); + List> result = new ArrayList<>(); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + result = ((List) response.getResult().get(JsonKey.RESPONSE)); + } + ProjectLogger.log( + "ShadowUserMigrationScheduler:getFullRecordFromProcessId:got single row data from bulk_upload_process with processId:" + + processId, + LoggerEnum.INFO.name()); + return result.get(FIRST_RECORD); + } + + private BulkMigrationUser convertRowToObject(Map row) { + BulkMigrationUser bulkMigrationUser = null; + try { + bulkMigrationUser = mapper.convertValue(row, BulkMigrationUser.class); + } catch (Exception e) { + e.printStackTrace(); + ProjectLogger.log( + "ShadowUserMigrationScheduler:convertMapToMigrationObject:error occurred while converting map to pojo" + .concat(e.getMessage() + ""), + LoggerEnum.ERROR.name()); + } + return bulkMigrationUser; + } + + private List getMigrationUserAsList(BulkMigrationUser bulkMigrationUser) { + List migrationUserList = new ArrayList<>(); + try { + String decryptedData = decryptionService.decryptData(bulkMigrationUser.getData()); + migrationUserList = + mapper.readValue(decryptedData, new TypeReference>() {}); + } catch (Exception e) { + e.printStackTrace(); + ProjectLogger.log( + "ShadowUserMigrationScheduler:getMigrationUserAsList:error occurred while converting map to POJO: " + + e, + LoggerEnum.ERROR.name()); + } + return migrationUserList; + } + + private Map getShadowExistingUserDetails(String channel, String userExtId) { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.CHANNEL, channel); + propertiesMap.put("userExtId", userExtId); + Map result = new HashMap<>(); + Response response = + cassandraOperation.getRecordsByProperties( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, propertiesMap); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + result = ((Map) ((List) response.getResult().get(JsonKey.RESPONSE)).get(0)); + } + return result; + } + + /** + * this method will prepare the shawdow user object and insert the record into shawdow_user table + * + * @param createdBy + * @param processId + * @param migrationUser + */ + private void insertShadowUserToDb( + String createdBy, String processId, MigrationUser migrationUser) { + Map dbMap = new WeakHashMap<>(); + dbMap.put(JsonKey.USER_EXT_ID, migrationUser.getUserExternalId()); + dbMap.put(JsonKey.ORG_EXT_ID, migrationUser.getOrgExternalId()); + ProjectLogger.log( + "ShadowUserMigrationScheduler:insertShadowUser: email got " + + migrationUser.getEmail() + + " " + + migrationUser.getPhone(), + LoggerEnum.INFO.name()); + dbMap.put(JsonKey.EMAIL, migrationUser.getEmail()); + dbMap.put(JsonKey.PHONE, migrationUser.getPhone()); + dbMap.put(JsonKey.ADDED_BY, createdBy); + dbMap.put(JsonKey.CHANNEL, migrationUser.getChannel()); + dbMap.put(JsonKey.NAME, migrationUser.getName()); + dbMap.put(JsonKey.PROCESS_ID, processId); + dbMap.put(JsonKey.ATTEMPTED_COUNT, 0); + dbMap.put(JsonKey.CLAIM_STATUS, ClaimStatus.UNCLAIMED.getValue()); + dbMap.put(JsonKey.USER_STATUS, getInputStatus(migrationUser.getInputStatus())); + dbMap.put(JsonKey.CREATED_ON, new Timestamp(System.currentTimeMillis())); + if (!isOrgExternalIdValid(migrationUser)) { + dbMap.put(JsonKey.CLAIM_STATUS, ClaimStatus.ORGEXTERNALIDMISMATCH.getValue()); + } + Response response = + cassandraOperation.insertRecord(JsonKey.SUNBIRD, JsonKey.SHADOW_USER, dbMap); + dbMap.clear(); + ProjectLogger.log( + "ShadowUserMigrationScheduler:insertShadowUser: record status in cassandra " + .concat(response + ""), + LoggerEnum.INFO.name()); + } + + private int getInputStatus(String inputStatus) { + if (inputStatus.equalsIgnoreCase(JsonKey.ACTIVE)) { + return ProjectUtil.Status.ACTIVE.getValue(); + } + return ProjectUtil.Status.INACTIVE.getValue(); + } + + private void updateUser(String processId, MigrationUser migrationUser, ShadowUser shadowUser) { + updateUserInShadowDb(processId, migrationUser, shadowUser); + } + + /** + * @param processId + * @param migrationUser + * @param existingShadowUser + */ + private void updateUserInShadowDb( + String processId, MigrationUser migrationUser, ShadowUser existingShadowUser) { + int currentClaimStatus = existingShadowUser.getClaimStatus(); + int newClaimStatus = currentClaimStatus; + boolean isClaimed = (currentClaimStatus == ClaimStatus.CLAIMED.getValue()); + boolean isNotSame = !isSame(existingShadowUser, migrationUser); + + if (isNotSame && !isOrgExternalIdValid(migrationUser)) { + newClaimStatus = ClaimStatus.ORGEXTERNALIDMISMATCH.getValue(); + } else if (!isClaimed) { + // Allow all non-claimed users another chance + newClaimStatus = ClaimStatus.UNCLAIMED.getValue(); + } + + if (isNotSame || (currentClaimStatus != newClaimStatus)) { + Map propertiesMap = populateUserMap(processId, migrationUser); + + propertiesMap.put(JsonKey.CLAIM_STATUS, newClaimStatus); + propertiesMap.put( + JsonKey.ATTEMPTED_COUNT, + 0); // we wanted to reset the attempted count for the failed records + + Map compositeKeysMap = new HashMap<>(); + compositeKeysMap.put(JsonKey.CHANNEL, migrationUser.getChannel()); + compositeKeysMap.put(JsonKey.USER_EXT_ID, migrationUser.getUserExternalId()); + + cassandraOperation.updateRecord( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, propertiesMap, compositeKeysMap); + + if (isClaimed) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:updateUserInShadowDb: isClaimed ", + LoggerEnum.INFO.name()); + ShadowUser newShadowUser = getUpdatedShadowUser(compositeKeysMap); + new ShadowUserProcessor().processClaimedUser(newShadowUser); + } + } + + ProjectLogger.log( + "ShadowUserMigrationScheduler:updateUserInShadowDb channel:" + + migrationUser.getChannel() + + " userExternalId: " + + migrationUser.getUserExternalId() + + " isNotSame: " + + isNotSame + + " newClaimStatus:" + + newClaimStatus, + LoggerEnum.INFO.name()); + } + + private Map populateUserMap(String processId, MigrationUser migrationUser) { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.EMAIL, migrationUser.getEmail()); + propertiesMap.put(JsonKey.PHONE, migrationUser.getPhone()); + propertiesMap.put(JsonKey.PROCESS_ID, processId); + propertiesMap.put(JsonKey.NAME, migrationUser.getName()); + propertiesMap.put(JsonKey.ORG_EXT_ID, migrationUser.getOrgExternalId()); + propertiesMap.put(JsonKey.UPDATED_ON, new Timestamp(System.currentTimeMillis())); + propertiesMap.put(JsonKey.USER_STATUS, getInputStatus(migrationUser.getInputStatus())); + return propertiesMap; + } + + /** + * this method will return the updated shadow user object when new orgExtId , name is been passed + * + * @param compositeKeysMap + * @return shawdow user + */ + private ShadowUser getUpdatedShadowUser(Map compositeKeysMap) { + Response response = + cassandraOperation.getRecordsByCompositeKey( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, compositeKeysMap); + ProjectLogger.log( + "ShadowUserMigrationScheduler:getUpdatedShadowUser: record status in cassandra for getting the updated shawdow user object " + .concat(response.getResult() + ""), + LoggerEnum.INFO.name()); + Map resultmap = + ((List>) response.getResult().get(JsonKey.RESPONSE)).get(0); + ShadowUser shadowUser = mapper.convertValue(resultmap, ShadowUser.class); + return shadowUser; + } + + private void updateStatusInUserBulkTable(String processId, int statusVal) { + try { + ProjectLogger.log( + "ShadowUserMigrationScheduler:updateStatusInUserBulkTable: got status to change in bulk upload table" + .concat(statusVal + "") + + "with processId" + + processId, + LoggerEnum.INFO.name()); + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.ID, processId); + propertiesMap.put(JsonKey.STATUS, statusVal); + updateBulkUserTable(propertiesMap); + } catch (Exception e) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:updateStatusInUserBulkTable: status update failed" + .concat(e + "") + + "with processId" + + processId, + LoggerEnum.ERROR.name()); + } + } + + private void updateBulkUserTable(Map propertiesMap) { + Response response = + cassandraOperation.updateRecord( + bulkUploadDbInfo.getKeySpace(), bulkUploadDbInfo.getTableName(), propertiesMap); + ProjectLogger.log( + "ShadowUserMigrationScheduler:updateBulkUserTable: status update result" + .concat(response + ""), + LoggerEnum.INFO.name()); + } + + private void updateMessageInBulkUserTable(String processId, String key, String value) { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.ID, processId); + propertiesMap.put(key, value); + if (StringUtils.equalsIgnoreCase(value, JsonKey.SUCCESS)) { + propertiesMap.put(JsonKey.STATUS, ProjectUtil.BulkProcessStatus.COMPLETED.getValue()); + propertiesMap.put(JsonKey.FAILURE_RESULT, ""); + } else { + propertiesMap.put(JsonKey.SUCCESS_RESULT, ""); + propertiesMap.put(JsonKey.STATUS, ProjectUtil.BulkProcessStatus.FAILED.getValue()); + } + updateBulkUserTable(propertiesMap); + propertiesMap.clear(); + } + + /** + * this method will take descision wheather to update the record or not. + * + * @param shadowUser + * @param migrationUser + * @return boolean + */ + private boolean isSame(ShadowUser shadowUser, MigrationUser migrationUser) { + + if (StringUtils.isBlank(migrationUser.getOrgExternalId())) { + return false; + } + if (!shadowUser.getName().equalsIgnoreCase(migrationUser.getName())) { + return false; + } + if (!StringUtils.equalsIgnoreCase(shadowUser.getEmail(), migrationUser.getEmail())) { + return false; + } + if (!StringUtils.equalsIgnoreCase(shadowUser.getOrgExtId(), migrationUser.getOrgExternalId())) { + return false; + } + if (!StringUtils.equalsIgnoreCase(shadowUser.getPhone(), migrationUser.getPhone())) { + return false; + } + if ((getInputStatus(migrationUser.getInputStatus()) != shadowUser.getUserStatus())) { + return false; + } + + if (!migrationUser.getName().equalsIgnoreCase(shadowUser.getName())) { + return false; + } + return true; + } + + /** + * this method will check weather the provided orgExternalId is correct or not + * + * @param migrationUser + * @return true if correct else false + */ + private boolean isOrgExternalIdValid(MigrationUser migrationUser) { + if (StringUtils.isBlank(migrationUser.getOrgExternalId())) { + return true; + } else if (verifiedChannelOrgExternalIdSet.contains( + migrationUser.getChannel() + ":" + migrationUser.getOrgExternalId())) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:isOrgExternalIdValid: found orgexternalid in cache:" + + migrationUser.getOrgExternalId(), + LoggerEnum.INFO.name()); + return true; + } + Map request = new WeakHashMap<>(); + Map filters = new WeakHashMap<>(); + filters.put(JsonKey.EXTERNAL_ID, migrationUser.getOrgExternalId()); + filters.put(JsonKey.CHANNEL, migrationUser.getChannel()); + request.put(JsonKey.FILTERS, filters); + SearchDTO searchDTO = ElasticSearchHelper.createSearchDTO(request); + searchDTO.setFields(new ArrayList<>(Arrays.asList(JsonKey.ID))); + Map response = + (Map) + ElasticSearchHelper.getResponseFromFuture( + elasticSearchService.search( + searchDTO, ProjectUtil.EsType.organisation.getTypeName())); + if (CollectionUtils.isNotEmpty((List>) response.get(JsonKey.CONTENT))) { + verifiedChannelOrgExternalIdSet.add( + migrationUser.getChannel() + ":" + migrationUser.getOrgExternalId()); + response.clear(); + return true; + } + response.clear(); + return false; + } + + private String encryptValue(String key) { + try { + return encryptionService.encryptData(key); + } catch (Exception e) { + ProjectLogger.log( + "ShadowUserMigrationScheduler:getEncryptedValue: error occurred in encrypting value " + + key, + LoggerEnum.ERROR.name()); + return key; + } + } + + private void encryptEmailAndPhone(MigrationUser migrationUser) { + + if (StringUtils.isNotBlank(migrationUser.getEmail())) { + migrationUser.setEmail(encryptValue(migrationUser.getEmail().toLowerCase())); + } + if (StringUtils.isNotBlank(migrationUser.getPhone())) { + migrationUser.setPhone(encryptValue(migrationUser.getPhone())); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/UpdateUserCountScheduler.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/UpdateUserCountScheduler.java new file mode 100644 index 0000000000..31675fbdcd --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/UpdateUserCountScheduler.java @@ -0,0 +1,48 @@ +package org.sunbird.common.quartz.scheduler; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Map; +import org.quartz.JobExecutionContext; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.Util; + +/** @author Amit Kumar */ +public class UpdateUserCountScheduler extends BaseJob { + + @Override + public void execute(JobExecutionContext ctx) { + ProjectLogger.log( + "UpdateUserCountScheduler:execute: Triggered Update user count Scheduler Job at: " + + Calendar.getInstance().getTime() + + " triggered by: " + + ctx.getJobDetail().toString(), + LoggerEnum.INFO.name()); + List locIdList = new ArrayList<>(); + Util.DbInfo geoLocationDbInfo = Util.dbInfoMap.get(JsonKey.GEO_LOCATION_DB); + Response response = + cassandraOperation.getAllRecords( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName()); + List> list = (List>) response.get(JsonKey.RESPONSE); + for (Map map : list) { + if (null == map.get(JsonKey.USER_COUNT) || 0 == ((int) map.get(JsonKey.USER_COUNT))) { + locIdList.add(map.get(JsonKey.ID)); + } + } + ProjectLogger.log( + "UpdateUserCountScheduler:execute: size of total locId to processed = " + locIdList.size()); + Request request = new Request(); + request.setOperation(BackgroundOperations.updateUserCountToLocationID.name()); + request.getRequest().put(JsonKey.LOCATION_IDS, locIdList); + request.getRequest().put(JsonKey.OPERATION, "UpdateUserCountScheduler"); + ProjectLogger.log( + "UpdateUserCountScheduler:execute: calling BackgroundService actor from scheduler"); + tellToBGRouter(request); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/UploadLookUpScheduler.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/UploadLookUpScheduler.java new file mode 100644 index 0000000000..eae5ca501b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/common/quartz/scheduler/UploadLookUpScheduler.java @@ -0,0 +1,114 @@ +/** */ +package org.sunbird.common.quartz.scheduler; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.Util; + +/** + * This class will lookup into bulk process table. if process type is new or in progress (more than + * x hours) then take the process id and do the re-process of job. + * + * @author Manzarul + */ +public class UploadLookUpScheduler extends BaseJob { + private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSZ"); + + public void execute(JobExecutionContext ctx) throws JobExecutionException { + ProjectLogger.log( + "Running Upload Scheduler Job at: " + + Calendar.getInstance().getTime() + + " triggered by: " + + ctx.getJobDetail().toString(), + LoggerEnum.INFO.name()); + Util.DbInfo bulkDb = Util.dbInfoMap.get(JsonKey.BULK_OP_DB); + List> result = null; + // get List of process with status as New + Response res = + cassandraOperation.getRecordsByProperty( + bulkDb.getKeySpace(), + bulkDb.getTableName(), + JsonKey.STATUS, + ProjectUtil.BulkProcessStatus.NEW.getValue()); + result = ((List>) res.get(JsonKey.RESPONSE)); + ProjectLogger.log( + "Total No. of record in Bulk_upload_process table with status as NEW are : :" + + result.size(), + LoggerEnum.INFO.name()); + if (!result.isEmpty()) { + process(result); + } + // get List of Process with status as InProgress + res = + cassandraOperation.getRecordsByProperty( + bulkDb.getKeySpace(), + bulkDb.getTableName(), + JsonKey.STATUS, + ProjectUtil.BulkProcessStatus.IN_PROGRESS.getValue()); + result = ((List>) res.get(JsonKey.RESPONSE)); + ProjectLogger.log( + "Total No. of record in Bulk_upload_process table with status as IN_PROGRESS are : :" + + result.size(), + LoggerEnum.INFO.name()); + if (null != result) { + Iterator> itr = result.iterator(); + while (itr.hasNext()) { + Map map = itr.next(); + try { + Date startTime = format.parse((String) map.get(JsonKey.PROCESS_START_TIME)); + Date currentTime = format.parse(format.format(new Date())); + long difference = currentTime.getTime() - startTime.getTime(); + int hourDiff = (int) (difference / (1000 * 3600)); + // if diff is more than 5Hr then only process it. + if (hourDiff < 5) { + itr.remove(); + } + } catch (ParseException ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + } + if (!result.isEmpty()) { + ProjectLogger.log( + "Total No. of record in Bulk_upload_process table with status as IN_PROGRESS " + + "with diff bw start time and current time greater than 5Hr are : :" + + result.size(), + LoggerEnum.INFO.name()); + process(result); + } + } + } + + private void process(List> result) { + Request request = new Request(); + request.put(JsonKey.DATA, result); + request.setOperation(ActorOperations.SCHEDULE_BULK_UPLOAD.getValue()); + tellToBGRouter(request); + } + + private Map genarateLogInfo(String logType, String message) { + + Map info = new HashMap<>(); + info.put(JsonKey.LOG_TYPE, logType); + long startTime = System.currentTimeMillis(); + info.put(JsonKey.START_TIME, startTime); + info.put(JsonKey.MESSAGE, message); + info.put(JsonKey.LOG_LEVEL, JsonKey.INFO); + + return info; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvError.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvError.java new file mode 100644 index 0000000000..baa0b3d10d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvError.java @@ -0,0 +1,23 @@ +package org.sunbird.error; + +import java.util.ArrayList; +import java.util.List; + +public class CsvError { + + private List errorsList = new ArrayList<>(); + + public CsvError() {} + + public List getErrorsList() { + return errorsList; + } + + public void setErrorsList(List errorsList) { + this.errorsList = errorsList; + } + + public void setError(CsvRowErrorDetails errorDetails) { + errorsList.add(errorDetails); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvErrorDispatcher.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvErrorDispatcher.java new file mode 100644 index 0000000000..43e0c80fde --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvErrorDispatcher.java @@ -0,0 +1,30 @@ +package org.sunbird.error; + +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * this class will dispatch the errors in the csv format + * + * @author anmolgupta + */ +public class CsvErrorDispatcher implements IErrorDispatcher { + + private CsvError error; + + private CsvErrorDispatcher(CsvError error) { + this.error = error; + } + + public static CsvErrorDispatcher getInstance(CsvError error) { + return new CsvErrorDispatcher(error); + } + + @Override + public void dispatchError() { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + error.getErrorsList().toString(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvRowErrorDetails.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvRowErrorDetails.java new file mode 100644 index 0000000000..bdd407b0a2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/CsvRowErrorDetails.java @@ -0,0 +1,53 @@ +package org.sunbird.error; + +public class CsvRowErrorDetails { + + int rowId; + private String header; + private ErrorEnum errorEnum; + + public CsvRowErrorDetails(int rowId, String header, ErrorEnum errorEnum) { + this.rowId = rowId; + this.header = header; + this.errorEnum = errorEnum; + } + + public CsvRowErrorDetails() {} + + public int getRowId() { + return rowId; + } + + public void setRowId(int rowId) { + this.rowId = rowId; + } + + public String getHeader() { + return header; + } + + public void setHeader(String header) { + this.header = header; + } + + public ErrorEnum getErrorEnum() { + return errorEnum; + } + + public void setErrorEnum(ErrorEnum errorEnum) { + this.errorEnum = errorEnum; + } + + @Override + public String toString() { + return "ErrorDetails{" + + "rowId=" + + rowId + + ", header='" + + header + + '\'' + + ", errorEnum=" + + errorEnum + + '}'; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/ErrorEnum.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/ErrorEnum.java new file mode 100644 index 0000000000..552accb011 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/ErrorEnum.java @@ -0,0 +1,16 @@ +package org.sunbird.error; + +public enum ErrorEnum { + invalid("invalid"), + duplicate("duplicate"), + missing("missing"); + private String value; + + ErrorEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/IErrorDispatcher.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/IErrorDispatcher.java new file mode 100644 index 0000000000..6d067c29f3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/IErrorDispatcher.java @@ -0,0 +1,12 @@ +package org.sunbird.error; + +/** + * this is an interface class for the error dispatcher + * + * @author anmolgupta + */ +public interface IErrorDispatcher { + + /** this method will prepare the error and will throw ProjectCommonException. */ + void dispatchError(); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/ListErrorDispatcher.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/ListErrorDispatcher.java new file mode 100644 index 0000000000..b8349921c6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/ListErrorDispatcher.java @@ -0,0 +1,48 @@ +package org.sunbird.error; + +import com.mchange.v1.util.ArrayUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * this class will dispatch error in list format + * + * @author anmolgupta + */ +public class ListErrorDispatcher implements IErrorDispatcher { + + private CsvError error; + + private ListErrorDispatcher(CsvError error) { + this.error = error; + } + + public static ListErrorDispatcher getInstance(CsvError error) { + return new ListErrorDispatcher(error); + } + + @Override + public void dispatchError() { + Collections.sort(error.getErrorsList(), new RowComparator()); + List errors = new ArrayList<>(); + error + .getErrorsList() + .stream() + .forEach( + errorDetails -> { + errors.add( + String.format( + "In Row %s:the Column %s:is %s", + errorDetails.getRowId() + 1, + errorDetails.getHeader(), + errorDetails.getErrorEnum().getValue())); + }); + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ArrayUtils.stringifyContents(errors.toArray()), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/RowComparator.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/RowComparator.java new file mode 100644 index 0000000000..f468942721 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/RowComparator.java @@ -0,0 +1,10 @@ +package org.sunbird.error; + +import java.util.Comparator; + +public class RowComparator implements Comparator { + @Override + public int compare(CsvRowErrorDetails o1, CsvRowErrorDetails o2) { + return o1.rowId - o2.rowId; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/factory/ErrorDispatcherFactory.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/factory/ErrorDispatcherFactory.java new file mode 100644 index 0000000000..aff2862d68 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/error/factory/ErrorDispatcherFactory.java @@ -0,0 +1,49 @@ +package org.sunbird.error.factory; + +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.error.CsvError; +import org.sunbird.error.CsvErrorDispatcher; +import org.sunbird.error.IErrorDispatcher; +import org.sunbird.error.ListErrorDispatcher; + +/** + * this is error dispatcher factory class which will judge type of error need to show on the basis + * of error count. + * + * @author anmolgupta + */ +public class ErrorDispatcherFactory { + + /** this ERROR_VISUALIZATION_THRESHOLD will decide in which need to show errors */ + public static final int ERROR_VISUALIZATION_THRESHOLD = getErrorVisualizationThreshold(); + + /** + * this method will return the required error dispatcher class object + * + * @param error + * @return IErrorDispatcher + */ + public static IErrorDispatcher getErrorDispatcher(CsvError error) { + if (error.getErrorsList().size() > ERROR_VISUALIZATION_THRESHOLD) { + return CsvErrorDispatcher.getInstance(error); + } + return ListErrorDispatcher.getInstance(error); + } + + /** + * this method will return the ERROR_VISUALIZATION_THRESHOLD value + * + * @return int + */ + private static int getErrorVisualizationThreshold() { + String value = + PropertiesCache.getInstance().readProperty(JsonKey.ERROR_VISUALIZATION_THRESHOLD); + ProjectLogger.log( + "ErrorDispatcherFactory:getErrorVisualizationThreshold:threshold got ".concat(value + ""), + LoggerEnum.INFO.name()); + return Integer.parseInt(value); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/FeedUtil.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/FeedUtil.java new file mode 100644 index 0000000000..602cdd5788 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/FeedUtil.java @@ -0,0 +1,109 @@ +package org.sunbird.feed; + +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.IntStream; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.actorutil.org.impl.OrganisationClientImpl; +import org.sunbird.bean.ShadowUser; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.feed.impl.FeedFactory; +import org.sunbird.models.organisation.Organisation; +import org.sunbird.models.user.Feed; +import org.sunbird.models.user.FeedAction; +import org.sunbird.models.user.FeedStatus; + +/** this class will be used as a Util for inserting Feed in table */ +public class FeedUtil { + private static IFeedService feedService = FeedFactory.getInstance(); + private static OrganisationClient organisationClient = OrganisationClientImpl.getInstance(); + private static Map orgIdMap = new HashMap<>(); + + public static Response saveFeed(ShadowUser shadowUser, List userIds) { + return saveFeed(shadowUser, userIds.get(0)); + } + + public static Response saveFeed(ShadowUser shadowUser, String userId) { + ProjectLogger.log("FeedUtil:saveFeed method called.", LoggerEnum.INFO.name()); + Response response = null; + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + reqMap.put(JsonKey.CATEGORY, FeedAction.ORG_MIGRATION_ACTION.getfeedAction()); + ProjectLogger.log( + "FeedUtil:saveFeed:fetching feed for userId ." + userId, LoggerEnum.INFO.name()); + List feedList = feedService.getRecordsByProperties(reqMap); + ProjectLogger.log( + "FeedUtil:saveFeed total no. of feed fetched for user id ." + + userId + + " ,feed count = " + + feedList.size(), + LoggerEnum.INFO.name()); + int index = getIndexOfMatchingFeed(feedList); + if (index == -1) { + response = feedService.insert(createFeedObj(shadowUser, userId)); + } else { + Map data = feedList.get(index).getData(); + List channelList = (List) data.get(JsonKey.PROSPECT_CHANNELS); + if (!channelList.contains(shadowUser.getChannel())) { + channelList.add(shadowUser.getChannel()); + List> orgList = + (ArrayList>) data.get(JsonKey.PROSPECT_CHANNELS_IDS); + orgList.addAll(getOrgDetails(shadowUser.getChannel())); + } + response = feedService.update(feedList.get(index)); + } + return response; + } + + private static Feed createFeedObj(ShadowUser shadowUser, String userId) { + Feed feed = new Feed(); + feed.setPriority(1); + feed.setCreatedBy(shadowUser.getAddedBy()); + feed.setStatus(FeedStatus.UNREAD.getfeedStatus()); + feed.setCategory(FeedAction.ORG_MIGRATION_ACTION.getfeedAction()); + Map prospectsChannel = new HashMap<>(); + List channelList = new ArrayList<>(); + channelList.add(shadowUser.getChannel()); + prospectsChannel.put(JsonKey.PROSPECT_CHANNELS, channelList); + prospectsChannel.put(JsonKey.PROSPECT_CHANNELS_IDS, getOrgDetails(shadowUser.getChannel())); + feed.setData(prospectsChannel); + feed.setUserId(userId); + return feed; + } + + private static List> getOrgDetails(String channel) { + Map filters = new HashMap<>(); + List> orgList = new CopyOnWriteArrayList<>(); + Map orgMap = new HashMap<>(); + filters.put(JsonKey.CHANNEL, channel); + filters.put(JsonKey.IS_ROOT_ORG, true); + if (!orgIdMap.isEmpty() && orgIdMap.containsKey(channel)) { + orgMap = (Map) orgIdMap.get(channel); + } else { + Organisation org = organisationClient.esSearchOrgByFilter(filters).get(0); + orgMap.put("id", org.getRootOrgId()); + orgMap.put("name", org.getChannel()); + orgIdMap.put(channel, orgMap); + } + orgList.add(orgMap); + return orgList; + } + + private static int getIndexOfMatchingFeed(List feedList) { + int index = + IntStream.range(0, feedList.size()) + .filter(i -> Objects.nonNull(feedList.get(i))) + .filter( + i -> + StringUtils.equalsIgnoreCase( + FeedAction.ORG_MIGRATION_ACTION.getfeedAction(), + feedList.get(i).getCategory())) + .findFirst() + .orElse(-1); + return index; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/IFeedService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/IFeedService.java new file mode 100644 index 0000000000..b812f6e6cf --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/IFeedService.java @@ -0,0 +1,52 @@ +package org.sunbird.feed; + +import java.util.List; +import java.util.Map; +import org.sunbird.common.models.response.Response; +import org.sunbird.dto.SearchDTO; +import org.sunbird.models.user.Feed; + +/** @author anmolgupta this is an interface class for the user feeds */ +public interface IFeedService { + + /** + * this method will be responsible to insert the feed in the user_feed table and sync the data + * with the ES + * + * @param feed + * @return response + */ + Response insert(Feed feed); + + /** + * this method will be responsible to update the feed in the user_feed table and sync the data + * with the ES + * + * @param feed + * @return response + */ + Response update(Feed feed); + + /** + * this method will be responsible to get the records by properties from the user_feed table + * + * @param properties + * @return List + */ + List getRecordsByProperties(Map properties); + + /** + * this method will be holding responsibility to get and search the feed. + * + * @param searchDTO + * @return response + */ + Response search(SearchDTO searchDTO); + + /** + * this method will be holding responsibility to delete the feed from DB and ES. + * + * @param id + */ + void delete(String id); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/impl/FeedFactory.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/impl/FeedFactory.java new file mode 100644 index 0000000000..fa674b4e24 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/impl/FeedFactory.java @@ -0,0 +1,17 @@ +package org.sunbird.feed.impl; + +import org.sunbird.feed.IFeedService; + +/** This class will create instance of FeedService */ +public class FeedFactory { + private static IFeedService instance; + + public static IFeedService getInstance() { + if (instance == null) { + synchronized (FeedFactory.class) { + if (instance == null) instance = new FeedServiceImpl(); + } + } + return instance; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/impl/FeedServiceImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/impl/FeedServiceImpl.java new file mode 100644 index 0000000000..6ac6dc21ae --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/feed/impl/FeedServiceImpl.java @@ -0,0 +1,144 @@ +package org.sunbird.feed.impl; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.sql.Timestamp; +import java.util.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.feed.IFeedService; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.Feed; +import scala.concurrent.Future; + +public class FeedServiceImpl implements IFeedService { + private Util.DbInfo usrFeedDbInfo = Util.dbInfoMap.get(JsonKey.USER_FEED_DB); + private ObjectMapper mapper = new ObjectMapper(); + + public static CassandraOperation getCassandraInstance() { + return ServiceFactory.getInstance(); + } + + public static ElasticSearchService getESInstance() { + return EsClientFactory.getInstance(JsonKey.REST); + } + + @Override + public Response insert(Feed feed) { + ProjectLogger.log("FeedServiceImpl:insert method called : ", LoggerEnum.INFO.name()); + Map feedData = feed.getData(); + Map dbMap = mapper.convertValue(feed, Map.class); + String feedId = ProjectUtil.generateUniqueId(); + dbMap.put(JsonKey.ID, feedId); + dbMap.put(JsonKey.CREATED_ON, new Timestamp(Calendar.getInstance().getTimeInMillis())); + try { + if (MapUtils.isNotEmpty(feed.getData())) { + dbMap.put(JsonKey.FEED_DATA, mapper.writeValueAsString(feed.getData())); + } + } catch (Exception ex) { + ProjectLogger.log("FeedServiceImpl:insert Exception occurred while mapping.", ex); + } + Response response = saveFeed(dbMap); + // save data to ES + dbMap.put(JsonKey.FEED_DATA, feedData); + dbMap.put(JsonKey.CREATED_ON, Calendar.getInstance().getTimeInMillis()); + getESInstance().save(ProjectUtil.EsType.userfeed.getTypeName(), feedId, dbMap); + return response; + } + + @Override + public Response update(Feed feed) { + ProjectLogger.log("FeedServiceImpl:update method called : ", LoggerEnum.INFO.name()); + Map feedData = feed.getData(); + Map dbMap = mapper.convertValue(feed, Map.class); + try { + if (MapUtils.isNotEmpty(feed.getData())) { + dbMap.put(JsonKey.FEED_DATA, mapper.writeValueAsString(feed.getData())); + } + } catch (Exception ex) { + ProjectLogger.log("FeedServiceImpl:update Exception occurred while mapping.", ex); + } + dbMap.remove(JsonKey.CREATED_ON); + dbMap.put(JsonKey.UPDATED_ON, new Timestamp(Calendar.getInstance().getTimeInMillis())); + Response response = saveFeed(dbMap); + // update data to ES + dbMap.put(JsonKey.FEED_DATA, feedData); + dbMap.put(JsonKey.UPDATED_ON, Calendar.getInstance().getTimeInMillis()); + getESInstance().update(ProjectUtil.EsType.userfeed.getTypeName(), feed.getId(), dbMap); + return response; + } + + @Override + public List getRecordsByProperties(Map properties) { + ProjectLogger.log( + "FeedServiceImpl:getRecordsByProperties method called : ", LoggerEnum.INFO.name()); + Response dbResponse = + getCassandraInstance() + .getRecordsByProperties( + usrFeedDbInfo.getKeySpace(), usrFeedDbInfo.getTableName(), properties); + List> responseList = null; + List feedList = new ArrayList<>(); + if (null != dbResponse && null != dbResponse.getResult()) { + responseList = (List>) dbResponse.getResult().get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(responseList)) { + responseList.forEach( + s -> { + try { + String data = (String) s.get(JsonKey.FEED_DATA); + if (StringUtils.isNotBlank(data)) { + s.put( + JsonKey.FEED_DATA, + mapper.readValue(data, new TypeReference>() {})); + } else { + s.put(JsonKey.FEED_DATA, Collections.emptyMap()); + } + feedList.add(mapper.convertValue(s, Feed.class)); + } catch (Exception ex) { + ProjectLogger.log( + "FeedServiceImpl:getRecordsByProperties :Exception occurred while mapping feed data.", + ex); + } + }); + } + } + return feedList; + } + + @Override + public Response search(SearchDTO searchDTO) { + ProjectLogger.log("FeedServiceImpl:search method called : ", LoggerEnum.INFO.name()); + Future> resultF = + getESInstance().search(searchDTO, ProjectUtil.EsType.userfeed.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + Response response = new Response(); + response.put(JsonKey.RESPONSE, result); + return response; + } + + @Override + public void delete(String id) { + ProjectLogger.log( + "FeedServiceImpl:delete method called for feedId : " + id, LoggerEnum.INFO.name()); + getCassandraInstance() + .deleteRecord(usrFeedDbInfo.getKeySpace(), usrFeedDbInfo.getTableName(), id); + getESInstance().delete(ProjectUtil.EsType.userfeed.getTypeName(), id); + } + + private Response saveFeed(Map feed) { + return getCassandraInstance() + .upsertRecord(usrFeedDbInfo.getKeySpace(), usrFeedDbInfo.getTableName(), feed); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/BackGroundServiceActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/BackGroundServiceActor.java new file mode 100644 index 0000000000..9493cbcf5c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/BackGroundServiceActor.java @@ -0,0 +1,150 @@ +package org.sunbird.learner.actors; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {}, + asyncTasks = {"updateUserCountToLocationID"} +) +public class BackGroundServiceActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + if (request + .getOperation() + .equalsIgnoreCase(BackgroundOperations.updateUserCountToLocationID.name())) { + updateUserCount(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void updateUserCount(Request actorMessage) { + ProjectLogger.log("In BackgroundService actor in updateUserCount method."); + Util.DbInfo locDbInfo = Util.dbInfoMap.get(JsonKey.GEO_LOCATION_DB); + List locationIds = (List) actorMessage.getRequest().get(JsonKey.LOCATION_IDS); + String operation = (String) actorMessage.getRequest().get(JsonKey.OPERATION); + ProjectLogger.log("operation for updating UserCount" + operation); + Response response = + cassandraOperation.getRecordsByProperty( + locDbInfo.getKeySpace(), locDbInfo.getTableName(), JsonKey.ID, locationIds); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (null != list && !list.isEmpty()) { + for (Map map : list) { + String locationId = (String) map.get(JsonKey.ID); + ProjectLogger.log("Processing start for LocationId " + locationId); + Long userCountTTL = 0L; + int userCount = + (map.get(JsonKey.USER_COUNT) == null) ? 0 : (int) (map.get(JsonKey.USER_COUNT)); + ProjectLogger.log("userCount is " + userCount + "for location id " + locationId); + if (userCount == 0 + && !StringUtils.isBlank(operation) + && operation.equalsIgnoreCase("UpdateUserCountScheduler")) { + ProjectLogger.log("Processing start for LocationId for Scheduler " + locationId); + int count = getUserCount(locationId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.ID, locationId); + reqMap.put(JsonKey.USER_COUNT, count); + reqMap.put(JsonKey.USER_COUNT_TTL, String.valueOf(System.currentTimeMillis())); + cassandraOperation.updateRecord( + locDbInfo.getKeySpace(), locDbInfo.getTableName(), reqMap); + } else if (!StringUtils.isBlank(operation) + && operation.equalsIgnoreCase("GeoLocationManagementActor")) { + ProjectLogger.log( + "Processing start for LocationId for GeoLocationManagementActor " + locationId); + try { + if (!StringUtils.isBlank((String) map.get(JsonKey.USER_COUNT_TTL))) { + userCountTTL = Long.valueOf((String) map.get(JsonKey.USER_COUNT_TTL)); + } + } catch (Exception ex) { + ProjectLogger.log( + "Exception occurred while converting string to long " + + (String) map.get(JsonKey.USER_COUNT_TTL)); + userCountTTL = 0L; + } + ProjectLogger.log("userCountTTL == " + userCountTTL); + Long currentTime = System.currentTimeMillis(); + Long diff = currentTime - userCountTTL; + int hours = (int) (diff / (1000 * 60 * 60)); + if (hours >= 24) { + ProjectLogger.log("Updating user count for LocnId " + locationId); + int usrCount = getUserCount(locationId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.ID, locationId); + reqMap.put(JsonKey.USER_COUNT, usrCount); + reqMap.put(JsonKey.USER_COUNT_TTL, String.valueOf(System.currentTimeMillis())); + cassandraOperation.updateRecord( + locDbInfo.getKeySpace(), locDbInfo.getTableName(), reqMap); + } + } + } + ProjectLogger.log("Processing end user count update "); + } + } + + private static int getUserCount(String locationId) { + ProjectLogger.log("fetching user count start "); + SearchDTO searchDto = new SearchDTO(); + List list = new ArrayList<>(); + list.add(JsonKey.ID); + searchDto.setFields(list); + Map filter = new HashMap<>(); + filter.put(JsonKey.LOCATION_ID, locationId); + searchDto.getAdditionalProperties().put(JsonKey.FILTERS, filter); + Future> esResponseF = + esService.search(searchDto, ProjectUtil.EsType.organisation.getTypeName()); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponseF); + List> orgList = (List>) esResponse.get(JsonKey.CONTENT); + + List orgIdList = new ArrayList<>(); + for (Map map : orgList) { + orgIdList.add((String) map.get(JsonKey.ID)); + } + ProjectLogger.log( + "Total No of Organisation for Location Id " + locationId + " , " + orgIdList.size()); + if (!orgIdList.isEmpty()) { + searchDto = new SearchDTO(); + List list2 = new ArrayList<>(); + list2.add(JsonKey.ID); + searchDto.setFields(list2); + searchDto.setLimit(0); + Map filter2 = new HashMap<>(); + filter2.put(JsonKey.ORGANISATIONS + "." + JsonKey.ORGANISATION_ID, orgIdList); + ProjectLogger.log("filter2.get(JsonKey.ORGANISATIONS.JsonKey.ORGANISATION_ID) " + orgIdList); + searchDto.getAdditionalProperties().put(JsonKey.FILTERS, filter2); + Future> esResponse2F = + esService.search(searchDto, ProjectUtil.EsType.user.getTypeName()); + Map esResponse2 = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponse2F); + long userCount = (long) esResponse2.get(JsonKey.COUNT); + ProjectLogger.log("Total No of User for Location Id " + locationId + " , " + userCount); + return (int) userCount; + } else { + return 0; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/BackgroundJobManager.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/BackgroundJobManager.java new file mode 100644 index 0000000000..2f6a3848c6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/BackgroundJobManager.java @@ -0,0 +1,410 @@ +package org.sunbird.learner.actors; + +import java.util.*; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.learner.util.Util.DbInfo; +import scala.concurrent.Future; + +/** + * This class will handle all the background job. + * + * @author Manzarul + * @author Amit Kumar + */ +@ActorConfig( + tasks = {}, + asyncTasks = { + "mergeUserToElastic", + "updateUserInfoToElastic", + "updateUserRoles", + "addUserBadgebackground", + "insertOrgInfoToElastic", + "updateOrgInfoToElastic", + "updateUserOrgES", + "removeUserOrgES", + "insertUserNotesToElastic", + "updateUserNotesToElastic", + } +) +public class BackgroundJobManager extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + ProjectLogger.log( + "BackgroundJobManager received action: " + request.getOperation(), LoggerEnum.INFO.name()); + ProjectLogger.log("BackgroundJobManager onReceive called"); + String operation = request.getOperation(); + ProjectLogger.log("Operation name is ==" + operation); + if (operation.equalsIgnoreCase(ActorOperations.UPDATE_USER_INFO_ELASTIC.getValue())) { + ProjectLogger.log("Update user info to ES called.", LoggerEnum.INFO.name()); + updateUserInfoToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.UPDATE_ORG_INFO_ELASTIC.getValue())) { + updateOrgInfoToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.INSERT_ORG_INFO_ELASTIC.getValue())) { + insertOrgInfoToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.UPDATE_USER_ORG_ES.getValue())) { + updateUserOrgInfoToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.REMOVE_USER_ORG_ES.getValue())) { + removeUserOrgInfoToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.UPDATE_USER_ROLES_ES.getValue())) { + updateUserRoleToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.ADD_USER_BADGE_BKG.getValue())) { + addBadgeToUserprofile(request); + } else if (operation.equalsIgnoreCase(ActorOperations.INSERT_USER_NOTES_ES.getValue())) { + insertUserNotesToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.UPDATE_USER_NOTES_ES.getValue())) { + updateUserNotesToEs(request); + } else if (operation.equalsIgnoreCase(ActorOperations.MERGE_USER_TO_ELASTIC.getValue())) { + mergeUserDetailsToEs(request); + } else { + ProjectLogger.log("UNSUPPORTED OPERATION"); + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOperationName.getErrorCode(), + ResponseCode.invalidOperationName.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + ProjectLogger.log("UnSupported operation in Background Job Manager", exception); + } + } + + /** @param actorMessage */ + private void addBadgeToUserprofile(Request actorMessage) { + Map userBadgeMap = actorMessage.getRequest(); + userBadgeMap.remove(JsonKey.OPERATION); + DbInfo userbadge = Util.dbInfoMap.get(JsonKey.USER_BADGES_DB); + Response response = + cassandraOperation.getRecordsByProperties( + userbadge.getKeySpace(), userbadge.getTableName(), userBadgeMap); + if (response != null && response.get(JsonKey.RESPONSE) != null) { + @SuppressWarnings("unchecked") + List> badgesList = + (List>) response.get(JsonKey.RESPONSE); + if (badgesList != null && !badgesList.isEmpty()) { + badgesList = removeDataFromMap(badgesList); + Map map = new HashMap<>(); + map.put(JsonKey.BADGES, badgesList); + boolean updateResponse = + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) userBadgeMap.get(JsonKey.RECEIVER_ID), + map); + ProjectLogger.log("User badge update response==" + updateResponse); + } + } else { + ProjectLogger.log("No data found user badges to sync with user===", LoggerEnum.INFO.name()); + } + } + + public static List> removeDataFromMap(List> listOfMap) { + List> list = new ArrayList<>(); + for (Map map : listOfMap) { + Map innermap = new HashMap<>(); + innermap.put(JsonKey.ID, map.get(JsonKey.ID)); + innermap.put(JsonKey.BADGE_TYPE_ID, map.get(JsonKey.BADGE_TYPE_ID)); + innermap.put(JsonKey.RECEIVER_ID, map.get(JsonKey.RECEIVER_ID)); + innermap.put(JsonKey.CREATED_DATE, map.get(JsonKey.CREATED_DATE)); + innermap.put(JsonKey.CREATED_BY, map.get(JsonKey.CREATED_BY)); + list.add(innermap); + } + return list; + } + + @SuppressWarnings("unchecked") + private void updateUserRoleToEs(Request actorMessage) { + List roles = (List) actorMessage.getRequest().get(JsonKey.ROLES); + String type = (String) actorMessage.get(JsonKey.TYPE); + String orgId = (String) actorMessage.get(JsonKey.ORGANISATION_ID); + Future> resultF = + esService.getDataByIdentifier( + ProjectUtil.EsType.user.getTypeName(), (String) actorMessage.get(JsonKey.USER_ID)); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (type.equals(JsonKey.USER)) { + result.put(JsonKey.ROLES, roles); + } else if (type.equals(JsonKey.ORGANISATION)) { + List> roleMapList = + (List>) result.get(JsonKey.ORGANISATIONS); + if (null != roleMapList) { + for (Map map : roleMapList) { + if ((orgId.equalsIgnoreCase((String) map.get(JsonKey.ORGANISATION_ID)))) { + map.put(JsonKey.ROLES, roles); + } + } + } + } + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) result.get(JsonKey.IDENTIFIER), + result); + } + + @SuppressWarnings("unchecked") + private void removeUserOrgInfoToEs(Request actorMessage) { + Map orgMap = (Map) actorMessage.getRequest().get(JsonKey.USER); + Future> resultF = + esService.getDataByIdentifier( + ProjectUtil.EsType.user.getTypeName(), (String) orgMap.get(JsonKey.USER_ID)); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (result.containsKey(JsonKey.ORGANISATIONS) && null != result.get(JsonKey.ORGANISATIONS)) { + List> orgMapList = + (List>) result.get(JsonKey.ORGANISATIONS); + if (null != orgMapList) { + Iterator> itr = orgMapList.iterator(); + while (itr.hasNext()) { + Map map = itr.next(); + if ((((String) map.get(JsonKey.USER_ID)) + .equalsIgnoreCase((String) orgMap.get(JsonKey.USER_ID))) + && (((String) map.get(JsonKey.ORGANISATION_ID)) + .equalsIgnoreCase((String) orgMap.get(JsonKey.ORGANISATION_ID)))) { + itr.remove(); + } + } + } + } + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) result.get(JsonKey.IDENTIFIER), + result); + } + + @SuppressWarnings("unchecked") + private void updateUserOrgInfoToEs(Request actorMessage) { + Map orgMap = (Map) actorMessage.getRequest().get(JsonKey.USER); + Future> resultF = + esService.getDataByIdentifier( + ProjectUtil.EsType.user.getTypeName(), (String) orgMap.get(JsonKey.USER_ID)); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (result.containsKey(JsonKey.ORGANISATIONS) && null != result.get(JsonKey.ORGANISATIONS)) { + List> orgMapList = + (List>) result.get(JsonKey.ORGANISATIONS); + orgMapList.add(orgMap); + } else { + List> mapList = new ArrayList<>(); + mapList.add(orgMap); + result.put(JsonKey.ORGANISATIONS, mapList); + } + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) result.get(JsonKey.IDENTIFIER), + result); + } + + @SuppressWarnings("unchecked") + private void insertOrgInfoToEs(Request actorMessage) { + Map headerMap = new HashMap<>(); + String header = ProjectUtil.getConfigValue(JsonKey.EKSTEP_AUTHORIZATION); + header = JsonKey.BEARER + header; + headerMap.put(JsonKey.AUTHORIZATION, header); + headerMap.put("Content-Type", "application/json"); + ProjectLogger.log("Calling method to save inside Es=="); + Map orgMap = + (Map) actorMessage.getRequest().get(JsonKey.ORGANISATION); + if (ProjectUtil.isNotNull(orgMap)) { + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + String id = (String) orgMap.get(JsonKey.ID); + Response orgResponse = + cassandraOperation.getRecordById(orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), id); + List> orgList = + (List>) orgResponse.getResult().get(JsonKey.RESPONSE); + Map esMap = new HashMap<>(); + if (!(orgList.isEmpty())) { + esMap = orgList.get(0); + esMap.remove(JsonKey.CONTACT_DETAILS); + + if (MapUtils.isNotEmpty((Map) orgMap.get(JsonKey.ADDRESS))) { + esMap.put(JsonKey.ADDRESS, orgMap.get(JsonKey.ADDRESS)); + } else { + esMap.put(JsonKey.ADDRESS, new HashMap<>()); + } + } + // Register the org into EKStep. + String hashOrgId = (String) esMap.getOrDefault(JsonKey.HASH_TAG_ID, ""); + ProjectLogger.log("hashOrgId value is ==" + hashOrgId); + // Just check it if hashOrgId is null or empty then replace with org id. + if (StringUtils.isBlank(hashOrgId)) { + hashOrgId = id; + } + // making call to register tag + registertag(hashOrgId, "{}", headerMap); + insertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.organisation.getTypeName(), + id, + esMap); + } + } + + @SuppressWarnings("unchecked") + private void updateOrgInfoToEs(Request actorMessage) { + Map orgMap = + (Map) actorMessage.getRequest().get(JsonKey.ORGANISATION); + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.organisation.getTypeName(), + (String) orgMap.get(JsonKey.ID), + orgMap); + } + + private boolean updateDataToElastic( + String indexName, String typeName, String identifier, Map data) { + Future responseF = esService.update(typeName, identifier, data); + boolean response = (boolean) ElasticSearchHelper.getResponseFromFuture(responseF); + if (response) { + return true; + } + ProjectLogger.log( + "unbale to save the data inside ES with identifier " + identifier, LoggerEnum.INFO.name()); + return false; + } + + private void updateUserInfoToEs(Request actorMessage) { + String userId = (String) actorMessage.getRequest().get(JsonKey.ID); + Map userDetails = + Util.getUserDetails(userId, getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue())); + ProjectLogger.log( + "BackGroundJobManager:updateUserInfoToEs userRootOrgId " + + userDetails.get(JsonKey.ROOT_ORG_ID), + LoggerEnum.INFO.name()); + insertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + userId, + userDetails); + } + + /** + * Method to cache the course data . + * + * @param index String + * @param type String + * @param identifier String + * @param data Map + * @return boolean + */ + private boolean insertDataToElastic( + String index, String type, String identifier, Map data) { + ProjectLogger.log( + "BackgroundJobManager:insertDataToElastic: type = " + type + " identifier = " + identifier, + LoggerEnum.INFO.name()); + /* + * if (type.equalsIgnoreCase(ProjectUtil.EsType.user.getTypeName())) { // now + * calculate profile completeness and error filed and store it in ES + * ProfileCompletenessService service = + * ProfileCompletenessFactory.getInstance(); Map responsemap = + * service.computeProfile(data); data.putAll(responsemap); } + */ + Future responseF = esService.save(type, identifier, data); + String response = (String) ElasticSearchHelper.getResponseFromFuture(responseF); + ProjectLogger.log( + "Getting ********** ES save response for type , identiofier==" + + type + + " " + + identifier + + " " + + response, + LoggerEnum.INFO.name()); + if (!StringUtils.isBlank(response)) { + ProjectLogger.log("User Data is saved successfully ES ." + type + " " + identifier); + return true; + } + ProjectLogger.log( + "unbale to save the data inside ES with identifier " + identifier, LoggerEnum.INFO.name()); + return false; + } + + /** + * This method will make EkStep api call register the tag. + * + * @param tagId String unique tag id. + * @param body String requested body + * @param header Map + * @return String + */ + private String registertag(String tagId, String body, Map header) { + String tagStatus = ""; + try { + ProjectLogger.log( + "BackgroundJobManager:registertag register tag call started with tagid = " + tagId, + LoggerEnum.INFO.name()); + tagStatus = ProjectUtil.registertag(tagId, body, header); + ProjectLogger.log( + "BackgroundJobManager:registertag register tag call end with id and status = " + + tagId + + ", " + + tagStatus, + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log( + "BackgroundJobManager:registertag register tag call failure with error message = " + + e.getMessage(), + e); + } + return tagStatus; + } + + @SuppressWarnings("unchecked") + private void insertUserNotesToEs(Request actorMessage) { + ProjectLogger.log("Calling method to save inside Es=="); + Map noteMap = (Map) actorMessage.getRequest().get(JsonKey.NOTE); + if (ProjectUtil.isNotNull(noteMap) && noteMap.size() > 0) { + String id = (String) noteMap.get(JsonKey.ID); + insertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.usernotes.getTypeName(), + id, + noteMap); + } else { + ProjectLogger.log("No data found to save inside Es for Notes--", LoggerEnum.INFO.name()); + } + } + + @SuppressWarnings("unchecked") + private void updateUserNotesToEs(Request actorMessage) { + Map noteMap = (Map) actorMessage.getRequest().get(JsonKey.NOTE); + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.usernotes.getTypeName(), + (String) noteMap.get(JsonKey.ID), + noteMap); + } + + private void mergeUserDetailsToEs(Request mergeRequest) { + String mergeeId = (String) mergeRequest.get(JsonKey.FROM_ACCOUNT_ID); + Map mergeeMap = + (Map) mergeRequest.get(JsonKey.USER_MERGEE_ACCOUNT); + updateDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + mergeeId, + mergeeMap); + ProjectLogger.log( + "user details for updated for user in ES with id:" + mergeeId, LoggerEnum.INFO.name()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/NotesManagementActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/NotesManagementActor.java new file mode 100644 index 0000000000..be3bf32f8f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/NotesManagementActor.java @@ -0,0 +1,441 @@ +package org.sunbird.learner.actors; + +import java.util.*; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.telemetry.util.TelemetryUtil; +import scala.concurrent.Future; + +/** This class provides API's to create, update, get and delete user note */ +@ActorConfig( + tasks = {"createNote", "getNote", "searchNote", "updateNote", "deleteNote"}, + asyncTasks = {} +) +public class NotesManagementActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + /** Receives the actor message and perform the operation for user note */ + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + switch (request.getOperation()) { + case "createNote": + createNote(request); + break; + case "updateNote": + updateNote(request); + break; + case "searchNote": + searchNote(request); + break; + case "getNote": + getNote(request); + break; + case "deleteNote": + deleteNote(request); + break; + default: + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + /** + * Method to create note using userId, courseId or contentId, title and note along with tags which + * are optional + * + * @param actorMessage + */ + @SuppressWarnings("unchecked") + private void createNote(Request actorMessage) { + ProjectLogger.log("Create Note method call start"); + // object of telemetry event... + Map targetObject = new HashMap<>(); + List> correlatedObject = new ArrayList<>(); + try { + Map req = actorMessage.getRequest(); + if (!validUser((String) req.get(JsonKey.USER_ID))) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidUserId.getErrorCode(), + ResponseCode.invalidUserId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + String uniqueId = ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv()); + req.put(JsonKey.ID, uniqueId); + req.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + req.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + String updatedBy = (String) actorMessage.getRequest().get(JsonKey.REQUESTED_BY); + if (!(StringUtils.isBlank(updatedBy))) { + req.put(JsonKey.CREATED_BY, updatedBy); + req.put(JsonKey.UPDATED_BY, updatedBy); + } + req.put(JsonKey.IS_DELETED, false); + Util.DbInfo userNotesDbInfo = Util.dbInfoMap.get(JsonKey.USER_NOTES_DB); + Response result = + cassandraOperation.insertRecord( + userNotesDbInfo.getKeySpace(), userNotesDbInfo.getTableName(), req); + ProjectLogger.log("Note data saved into cassandra."); + result.getResult().put(JsonKey.ID, uniqueId); + result.getResult().remove(JsonKey.RESPONSE); + sender().tell(result, self()); + + targetObject = + TelemetryUtil.generateTargetObject(uniqueId, JsonKey.NOTE, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject(uniqueId, JsonKey.NOTE, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject(updatedBy, JsonKey.USER, null, correlatedObject); + + Map rollup = + prepareRollUpForObjectType( + (String) req.get(JsonKey.CONTENT_ID), (String) req.get(JsonKey.COURSE_ID)); + TelemetryUtil.addTargetObjectRollUp(rollup, targetObject); + + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + + Request request = new Request(); + request.setOperation(ActorOperations.INSERT_USER_NOTES_ES.getValue()); + request.getRequest().put(JsonKey.NOTE, req); + ProjectLogger.log("Calling background job to save org data into ES" + uniqueId); + tellToAnother(request); + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + sender().tell(e, self()); + return; + } + } + + /** + * Method to update the tags, title and note details of the user note + * + * @param actorMessage containing noteId and requestedBy + */ + @SuppressWarnings("unchecked") + private void updateNote(Request actorMessage) { + ProjectLogger.log("Update Note method call start"); + // object of telemetry event... + Map targetObject = new HashMap<>(); + List> correlatedObject = new ArrayList<>(); + try { + String noteId = (String) actorMessage.getContext().get(JsonKey.NOTE_ID); + String userId = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY); + if (!validateUserForNoteUpdation(userId, noteId)) { + throw new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ResponseCode.unAuthorized.getErrorMessage(), + ResponseCode.UNAUTHORIZED.getResponseCode()); + } + Map list = getNoteRecordById(noteId); + if (list.isEmpty()) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidNoteId.getErrorCode(), + ResponseCode.invalidNoteId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + Map req = actorMessage.getRequest(); + req.remove(JsonKey.USER_ID); + req.remove(JsonKey.COURSE_ID); + req.remove(JsonKey.CONTENT_ID); + req.remove(JsonKey.IS_DELETED); + req.remove(JsonKey.NOTE_ID); + req.put(JsonKey.ID, noteId); + req.put(JsonKey.UPDATED_BY, userId); + req.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + Util.DbInfo userNotesDbInfo = Util.dbInfoMap.get(JsonKey.USER_NOTES_DB); + Response result = + cassandraOperation.updateRecord( + userNotesDbInfo.getKeySpace(), userNotesDbInfo.getTableName(), req); + ProjectLogger.log("Note data updated"); + result.getResult().put(JsonKey.ID, noteId); + result.getResult().remove(JsonKey.RESPONSE); + sender().tell(result, self()); + + targetObject = TelemetryUtil.generateTargetObject(noteId, JsonKey.NOTE, JsonKey.UPDATE, null); + TelemetryUtil.generateCorrelatedObject(noteId, JsonKey.NOTE, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject(userId, JsonKey.USER, null, correlatedObject); + Map rollup = new HashMap<>(); + TelemetryUtil.addTargetObjectRollUp(rollup, targetObject); + + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + + Request request = new Request(); + request.getRequest().put(JsonKey.NOTE, req); + request.setOperation(ActorOperations.UPDATE_USER_NOTES_ES.getValue()); + tellToAnother(request); + + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + sender().tell(e, self()); + return; + } + } + + /** + * Method to get the note for the given note Id of the user + * + * @param actorMessage containing noteId and requestedBy + */ + private void getNote(Request actorMessage) { + ProjectLogger.log("Update Note method call start"); + try { + String noteId = (String) actorMessage.getContext().get(JsonKey.NOTE_ID); + String userId = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY); + if (!validateUserForNoteUpdation(userId, noteId)) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ResponseCode.invalidParameterValue.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + Map request = new HashMap<>(); + Map filters = new HashMap<>(); + filters.put(JsonKey.ID, noteId); + + request.put(JsonKey.FILTERS, filters); + Response response = new Response(); + Map result = getElasticSearchData(request); + if (!result.isEmpty() && ((Long) result.get(JsonKey.COUNT) == 0)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidNoteId.getErrorCode(), + ResponseCode.invalidNoteId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + response.put(JsonKey.RESPONSE, result); + sender().tell(response, self()); + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + sender().tell(e, self()); + return; + } + } + + /** + * Method to search the note for the given request + * + * @param actorMessage containing search parameters + */ + private void searchNote(Request actorMessage) { + ProjectLogger.log("Update Note method call start"); + try { + + Map searchQueryMap = actorMessage.getRequest(); + searchQueryMap.put(JsonKey.REQUESTED_BY, actorMessage.getContext().get(JsonKey.REQUESTED_BY)); + Response response = new Response(); + Map result = getElasticSearchData(searchQueryMap); + response.put(JsonKey.RESPONSE, result); + sender().tell(response, self()); + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + sender().tell(e, self()); + return; + } + } + + /** + * Method to get note data from ElasticSearch + * + * @param searchQueryMap + * @return Map - note data + */ + @SuppressWarnings("unchecked") + private Map getElasticSearchData(Map searchQueryMap) { + Map filters = new HashMap<>(); + if (searchQueryMap.containsKey(JsonKey.FILTERS)) { + filters = (Map) searchQueryMap.get(JsonKey.FILTERS); + } + if (null != searchQueryMap.get(JsonKey.REQUESTED_BY)) { + filters.put(JsonKey.USER_ID, searchQueryMap.get(JsonKey.REQUESTED_BY)); + } + filters.put(JsonKey.IS_DELETED, false); + searchQueryMap.put(JsonKey.FILTERS, filters); + SearchDTO searchDto = Util.createSearchDto(searchQueryMap); + List excludedFields = new ArrayList<>(); + if (null != searchDto.getExcludedFields()) { + excludedFields = searchDto.getExcludedFields(); + } + excludedFields.add(JsonKey.IS_DELETED); + searchDto.setExcludedFields(excludedFields); + Future> resultF = + esService.search(searchDto, EsType.usernotes.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (result != null) { + Object count = result.get(JsonKey.COUNT); + Object note = result.get(JsonKey.CONTENT); + result = new LinkedHashMap<>(); + result.put(JsonKey.COUNT, count); + result.put(JsonKey.NOTE, note); + result.put(JsonKey.CONTENT, note); + } else { + result = new HashMap<>(); + } + String[] types = {EsType.usernotes.getTypeName()}; + return result; + } + + /** + * Method to mark the note as deleted [Soft Delete i.e to set the isDeleted field to true] + * + * @param actorMessage + */ + private void deleteNote(Request actorMessage) { + ProjectLogger.log("Delete Note method call start"); + // object of telemetry event... + Map targetObject = new HashMap<>(); + List> correlatedObject = new ArrayList<>(); + try { + String noteId = (String) actorMessage.getContext().get(JsonKey.NOTE_ID); + String userId = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY); + if (!validateUserForNoteUpdation(userId, noteId)) { + throw new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ResponseCode.unAuthorized.getErrorMessage(), + ResponseCode.UNAUTHORIZED.getResponseCode()); + } + if (!noteIdExists(noteId)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidNoteId.getErrorCode(), + ResponseCode.invalidNoteId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + Map req = new HashMap<>(); + req.put(JsonKey.ID, noteId); + req.put(JsonKey.IS_DELETED, true); + req.put(JsonKey.UPDATED_BY, userId); + req.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + Util.DbInfo userNotesDbInfo = Util.dbInfoMap.get(JsonKey.USER_NOTES_DB); + Response result = + cassandraOperation.updateRecord( + userNotesDbInfo.getKeySpace(), userNotesDbInfo.getTableName(), req); + result.getResult().remove(JsonKey.RESPONSE); + sender().tell(result, self()); + + targetObject = TelemetryUtil.generateTargetObject(noteId, JsonKey.NOTE, JsonKey.DELETE, null); + TelemetryUtil.generateCorrelatedObject(noteId, JsonKey.NOTE, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject(userId, JsonKey.USER, null, correlatedObject); + + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + + Request request = new Request(); + request.getRequest().put(JsonKey.NOTE, req); + request.setOperation(ActorOperations.UPDATE_USER_NOTES_ES.getValue()); + tellToAnother(request); + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + sender().tell(e, self()); + return; + } + } + + /** + * Method to validate User based on userId from ElasticSearch Data + * + * @param userId + * @return true if user data is present in ES else false + */ + private Boolean validUser(String userId) { + Boolean result = false; + + if (!StringUtils.isBlank(userId)) { + Future> dataF = + esService.getDataByIdentifier(EsType.user.getTypeName(), userId); + Map data = + (Map) ElasticSearchHelper.getResponseFromFuture(dataF); + if (null != data && !data.isEmpty()) { + result = true; + } + } + return result; + } + + /** + * Method to validate note using noteId + * + * @param noteId + * @return true if note exists in Cassandra else false + */ + private Boolean noteIdExists(String noteId) { + Boolean result = false; + Map list = getNoteRecordById(noteId); + if (!list.isEmpty()) { + result = true; + } + return result; + } + + /** + * Method to get Note details using note Id + * + * @param noteId + * @return Note data as List> + */ + private Map getNoteRecordById(String noteId) { + Future> resultF = + esService.getDataByIdentifier(EsType.usernotes.getTypeName(), noteId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + return result; + } + + private Boolean validateUserForNoteUpdation(String userId, String noteId) { + Boolean result = false; + Map noteData = getNoteRecordById(noteId); + if (MapUtils.isEmpty(noteData)) return result; + if (!StringUtils.isBlank(userId)) { + result = true; + } + if (!userId.equalsIgnoreCase((String) noteData.get(JsonKey.USER_ID))) { + throw new ProjectCommonException( + ResponseCode.errorForbidden.getErrorCode(), + ResponseCode.errorForbidden.getErrorMessage(), + ResponseCode.FORBIDDEN.getResponseCode()); + } + return result; + } + + /** This method will handle rollup values (for contentId and courseId) in object */ + public static Map prepareRollUpForObjectType(String contentId, String courseId) { + + Map rollupMap = new HashMap<>(); + + if (StringUtils.isBlank(courseId)) { // if courseId is blank the level 1 should be contentId + if (StringUtils.isNotBlank(contentId)) { + rollupMap.put("l1", contentId); + } + } else { + rollupMap.put("l1", courseId); // if courseId is not blank level 1 should be courseId + if (StringUtils.isNotBlank(contentId)) { + rollupMap.put("l2", contentId); + } + } + return rollupMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/OnDemandSchedulerActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/OnDemandSchedulerActor.java new file mode 100644 index 0000000000..f490378656 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/OnDemandSchedulerActor.java @@ -0,0 +1,80 @@ +package org.sunbird.learner.actors; + +import static org.sunbird.common.request.orgvalidator.BaseOrgRequestValidator.ERROR_CODE; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.quartz.scheduler.OnDemandSchedulerManager; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Amit Kumar */ +@ActorConfig( + tasks = {"onDemandStartScheduler"}, + asyncTasks = {} +) +public class OnDemandSchedulerActor extends BaseActor { + private static final String TYPE = "type"; + + @Override + public void onReceive(Request actorMessage) throws Throwable { + if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.ONDEMAND_START_SCHEDULER.getValue())) { + startSchedular(actorMessage); + } else { + ProjectLogger.log("UNSUPPORTED OPERATION", LoggerEnum.ERROR); + } + } + + private void startSchedular(Request actorMessage) { + Map req = actorMessage.getRequest(); + ArrayList jobTypes = (ArrayList) req.get(TYPE); + if (jobTypes.size() > 0) { + String[] jobs = jobTypes.stream().toArray(String[]::new); + validateJobs(jobs); + scheduleJob(jobs); + } else { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ERROR_CODE, + TYPE); + } + } + + private void validateJobs(String[] jobs) { + List jobsAllowed = new ArrayList(); + jobsAllowed.add("bulkupload"); + jobsAllowed.add("shadowuser"); + for (String job : jobs) { + if (!jobsAllowed.contains(job)) { + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ResponseCode.invalidParameter.getErrorMessage(), + ERROR_CODE, + TYPE); + } + } + } + + private void scheduleJob(String[] jobs) { + Response response = new Response(); + OnDemandSchedulerManager onDemandSchedulerManager = OnDemandSchedulerManager.getInstance(); + new Thread(() -> onDemandSchedulerManager.triggerScheduler(jobs)).start(); + Map result = new HashMap(); + result.put(JsonKey.STATUS, JsonKey.SUCCESS); + response.put(JsonKey.RESULT, result); + sender().tell(response, self()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/OrganisationManagementActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/OrganisationManagementActor.java new file mode 100644 index 0000000000..5e804d0f35 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/OrganisationManagementActor.java @@ -0,0 +1,1728 @@ +package org.sunbird.learner.actors; + +import static org.sunbird.learner.util.Util.isNotNull; +import static org.sunbird.learner.util.Util.isNull; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.text.MessageFormat; +import java.util.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.EsIndex; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.models.organisation.Organisation; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.validator.location.LocationRequestValidator; +import scala.concurrent.Future; + +/** + * This actor will handle organisation related operation . + * + * @author Arvind + */ +@ActorConfig( + tasks = { + "createOrg", + "updateOrg", + "updateOrgStatus", + "getOrgDetails", + "addMemberOrganisation", + "removeMemberOrganisation", + "getOrgTypeList", + "createOrgType", + "updateOrgType", + "assignKeys" + }, + asyncTasks = {} +) +public class OrganisationManagementActor extends BaseActor { + private final CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static final LocationRequestValidator validator = new LocationRequestValidator(); + private final EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.ORGANISATION); + if (request.getOperation().equalsIgnoreCase(ActorOperations.CREATE_ORG.getValue())) { + createOrg(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.UPDATE_ORG_STATUS.getValue())) { + updateOrgStatus(request); + } else if (request.getOperation().equalsIgnoreCase(ActorOperations.UPDATE_ORG.getValue())) { + updateOrgData(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.GET_ORG_DETAILS.getValue())) { + getOrgDetails(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.ADD_MEMBER_ORGANISATION.getValue())) { + addMemberOrganisation(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.REMOVE_MEMBER_ORGANISATION.getValue())) { + removeMemberOrganisation(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.GET_ORG_TYPE_LIST.getValue())) { + getOrgTypeList(); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.CREATE_ORG_TYPE.getValue())) { + createOrgType(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.UPDATE_ORG_TYPE.getValue())) { + updateOrgType(request); + } else if (request.getOperation().equalsIgnoreCase(ActorOperations.ASSIGN_KEYS.getValue())) { + assignKey(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void updateOrgType(Request actorMessage) { + ProjectLogger.log("updateOrgType method call start"); + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + try { + Util.DbInfo orgTypeDbInfo = Util.dbInfoMap.get(JsonKey.ORG_TYPE_DB); + Map request = actorMessage.getRequest(); + Response result = + cassandraOperation.getRecordsByProperty( + orgTypeDbInfo.getKeySpace(), + orgTypeDbInfo.getTableName(), + JsonKey.NAME, + request.get(JsonKey.NAME)); + List> list = (List>) result.get(JsonKey.RESPONSE); + if (!(list.isEmpty())) { + Map map = list.get(0); + if (!(((String) map.get(JsonKey.ID)).equals(request.get(JsonKey.ID)))) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.orgTypeAlreadyExist.getErrorCode(), + ResponseCode.orgTypeAlreadyExist.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + } + + request.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + Response response = + cassandraOperation.updateRecord( + orgTypeDbInfo.getKeySpace(), orgTypeDbInfo.getTableName(), request); + sender().tell(response, self()); + + targetObject = + TelemetryUtil.generateTargetObject( + (String) request.get(JsonKey.ID), "organisationType", JsonKey.UPDATE, null); + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + // update DataCacheHandler orgType map with new data + new Thread() { + @Override + public void run() { + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + DataCacheHandler.getOrgTypeMap() + .put( + ((String) request.get(JsonKey.NAME)).toLowerCase(), + (String) request.get(JsonKey.ID)); + } + } + }.start(); + } catch (Exception e) { + ProjectLogger.log("Exception Occurred while updating data to orgType table :: ", e); + sender().tell(e, self()); + } + } + + private void createOrgType(Request actorMessage) { + + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + ProjectLogger.log("createOrgType method call start"); + try { + Util.DbInfo orgTypeDbInfo = Util.dbInfoMap.get(JsonKey.ORG_TYPE_DB); + Map request = actorMessage.getRequest(); + Response result = + cassandraOperation.getAllRecords( + orgTypeDbInfo.getKeySpace(), orgTypeDbInfo.getTableName()); + List> list = (List>) result.get(JsonKey.RESPONSE); + if (!(list.isEmpty())) { + for (Map map : list) { + if (((String) map.get(JsonKey.NAME)) + .equalsIgnoreCase((String) request.get(JsonKey.NAME))) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.orgTypeAlreadyExist.getErrorCode(), + ResponseCode.orgTypeAlreadyExist.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + } + } + request.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + String id = ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv()); + request.put(JsonKey.ID, id); + Response response = + cassandraOperation.insertRecord( + orgTypeDbInfo.getKeySpace(), orgTypeDbInfo.getTableName(), request); + sender().tell(response, self()); + + targetObject = + TelemetryUtil.generateTargetObject(id, "organisationType", JsonKey.CREATE, null); + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + + // update DataCacheHandler orgType map with new data + new Thread() { + @Override + public void run() { + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + DataCacheHandler.getOrgTypeMap() + .put( + ((String) request.get(JsonKey.NAME)).toLowerCase(), + (String) request.get(JsonKey.ID)); + } + } + }.start(); + } catch (Exception e) { + ProjectLogger.log("Exception Occurred while inserting data to orgType table :: ", e); + sender().tell(e, self()); + } + } + + private void getOrgTypeList() { + ProjectLogger.log("getOrgTypeList method call start"); + try { + Util.DbInfo orgTypeDbInfo = Util.dbInfoMap.get(JsonKey.ORG_TYPE_DB); + Response response = + cassandraOperation.getAllRecords( + orgTypeDbInfo.getKeySpace(), orgTypeDbInfo.getTableName()); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (!(list.isEmpty())) { + for (Map map : list) { + map.remove(JsonKey.CREATED_BY); + map.remove(JsonKey.CREATED_DATE); + map.remove(JsonKey.UPDATED_BY); + map.remove(JsonKey.UPDATED_DATE); + } + } + sender().tell(response, self()); + } catch (Exception e) { + ProjectLogger.log("Exception Occurred while fetching orgType List :: ", e); + sender().tell(e, self()); + } + } + + /** Method to create an Organisation . */ + @SuppressWarnings("unchecked") + private void createOrg(Request actorMessage) { + ProjectLogger.log("OrgManagementActor: Create org method call start", LoggerEnum.INFO.name()); + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + String callerId = (String) actorMessage.getContext().get(JsonKey.CALLER_ID); + try { + actorMessage.toLower(); + Map request = actorMessage.getRequest(); + validateLocationCodeAndIds(request); + if (request.containsKey(JsonKey.ORG_TYPE) + && !StringUtils.isBlank((String) request.get(JsonKey.ORG_TYPE))) { + request.put(JsonKey.ORG_TYPE_ID, validateOrgType((String) request.get(JsonKey.ORG_TYPE))); + } + + Map addressReq = null; + if (null != request.get(JsonKey.ADDRESS)) { + addressReq = (Map) request.get(JsonKey.ADDRESS); + request.remove(JsonKey.ADDRESS); + } + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + + channelMandatoryValidation(request); + validateChannel(request); + String updatedBy = (String) actorMessage.getRequest().get(JsonKey.REQUESTED_BY); + if (!(StringUtils.isBlank(updatedBy))) { + request.put(JsonKey.CREATED_BY, updatedBy); + } + String uniqueId = ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv()); + request.put(JsonKey.ID, uniqueId); + request.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + if (JsonKey.BULK_ORG_UPLOAD.equalsIgnoreCase(callerId)) { + if (null == request.get(JsonKey.STATUS)) { + request.put(JsonKey.STATUS, ProjectUtil.OrgStatus.ACTIVE.getValue()); + } + } else { + request.put(JsonKey.STATUS, ProjectUtil.OrgStatus.ACTIVE.getValue()); + } + // removing default from request, not allowing user to create default org. + request.remove(JsonKey.IS_DEFAULT); + + String passedExternalId = (String) request.get(JsonKey.EXTERNAL_ID); + if (StringUtils.isNotBlank(passedExternalId)) { + passedExternalId = passedExternalId.toLowerCase(); + String channel = (String) request.get(JsonKey.CHANNEL); + if (!validateChannelExternalIdUniqueness(channel, passedExternalId, null)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorDuplicateEntry, + MessageFormat.format( + ResponseCode.errorDuplicateEntry.getErrorMessage(), + passedExternalId, + JsonKey.EXTERNAL_ID)); + } + request.put(JsonKey.EXTERNAL_ID, passedExternalId); + request.put(JsonKey.PROVIDER, StringUtils.lowerCase(channel)); + } else { + request.remove(JsonKey.EXTERNAL_ID); + request.remove(JsonKey.PROVIDER); + } + // update address if present in request + if (null != addressReq && addressReq.size() > 0) { + String addressId = ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv()); + addressReq.put(JsonKey.ID, addressId); + addressReq.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + + if (!(StringUtils.isBlank(updatedBy))) { + addressReq.put(JsonKey.CREATED_BY, updatedBy); + } + upsertAddress(addressReq); + request.put(JsonKey.ADDRESS_ID, addressId); + telemetryGenerationForOrgAddress(addressReq, request, false, actorMessage.getContext()); + } + + Boolean isRootOrg = (Boolean) request.get(JsonKey.IS_ROOT_ORG); + // set root org on basis of whether the org itself is root org or not ... + if (null != isRootOrg && isRootOrg) { + request.put(JsonKey.ROOT_ORG_ID, uniqueId); + } + if (request.containsKey(JsonKey.EMAIL) + && !EmailValidator.isEmailValid((String) request.get(JsonKey.EMAIL))) { + ProjectCommonException.throwClientErrorException(ResponseCode.emailFormatError); + } + + // adding one extra filed for tag. + if (!StringUtils.isBlank(((String) request.get(JsonKey.HASHTAGID)))) { + request.put( + JsonKey.HASHTAGID, + validateHashTagId(((String) request.get(JsonKey.HASHTAGID)), JsonKey.CREATE, "")); + } else { + request.put(JsonKey.HASHTAGID, uniqueId); + } + + if (request.containsKey(JsonKey.CHANNEL)) { + String slug = Slug.makeSlug((String) request.getOrDefault(JsonKey.CHANNEL, ""), true); + if (null != isRootOrg && isRootOrg) { + boolean bool = isSlugUnique(slug); + if (bool) { + request.put(JsonKey.SLUG, slug); + } else { + sender().tell(ProjectUtil.createClientException(ResponseCode.slugIsNotUnique), self()); + return; + } + } else { + request.put(JsonKey.SLUG, slug); + } + } + + if (null != isRootOrg && isRootOrg) { + boolean bool = Util.registerChannel(request); + request.put( + JsonKey.IS_SSO_ROOTORG_ENABLED, + request.containsKey(JsonKey.IS_SSO_ROOTORG_ENABLED) + ? request.get(JsonKey.IS_SSO_ROOTORG_ENABLED) + : false); + if (!bool) { + sender().tell(ProjectUtil.createServerError(ResponseCode.channelRegFailed), self()); + return; + } + } else { + request.put(JsonKey.IS_ROOT_ORG, false); + request.put(JsonKey.IS_SSO_ROOTORG_ENABLED, false); + } + // This will remove all extra unnecessary parameter from request + ObjectMapper mapper = new ObjectMapper(); + Organisation org = mapper.convertValue(request, Organisation.class); + request = mapper.convertValue(org, Map.class); + Response result = + cassandraOperation.insertRecord( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), request); + + if (StringUtils.isNotBlank(passedExternalId)) { + String channel = (String) request.get(JsonKey.CHANNEL); + createOrgExternalIdRecord(channel, passedExternalId, uniqueId); + } + ProjectLogger.log( + "OrgManagementActor : createOrg : Created org id is ----." + uniqueId, + LoggerEnum.INFO.name()); + result.getResult().put(JsonKey.ORGANISATION_ID, uniqueId); + sender().tell(result, self()); + Request orgReq = new Request(); + orgReq.getRequest().put(JsonKey.ORGANISATION, request); + orgReq.setOperation(ActorOperations.INSERT_ORG_INFO_ELASTIC.getValue()); + ProjectLogger.log( + "OrganisationManagementActor:createOrg: Calling background job to sync org data " + + uniqueId, + LoggerEnum.INFO.name()); + tellToAnother(orgReq); + targetObject = + TelemetryUtil.generateTargetObject(uniqueId, JsonKey.ORGANISATION, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject( + uniqueId, JsonKey.ORGANISATION, null, correlatedObject); + TelemetryUtil.telemetryProcessingCall( + (Map) actorMessage.getRequest().get(JsonKey.ORGANISATION), + targetObject, + correlatedObject, + actorMessage.getContext()); + } catch (ProjectCommonException e) { + ProjectLogger.log( + "OrganisationManagementActor:createOrg: Error occurred = " + e.getMessage(), + LoggerEnum.INFO.name()); + sender().tell(e, self()); + return; + } + } + + private void createOrgExternalIdRecord(String channel, String externalId, String orgId) { + Map orgExtIdRequest = new HashMap(); + orgExtIdRequest.put(JsonKey.PROVIDER, StringUtils.lowerCase(channel)); + orgExtIdRequest.put(JsonKey.EXTERNAL_ID, StringUtils.lowerCase(externalId)); + orgExtIdRequest.put(JsonKey.ORG_ID, orgId); + cassandraOperation.insertRecord(JsonKey.SUNBIRD, JsonKey.ORG_EXT_ID_DB, orgExtIdRequest); + } + + private void deleteOrgExternalIdRecord(String channel, String externalId) { + Map orgExtIdRequest = new HashMap(); + orgExtIdRequest.put(JsonKey.PROVIDER, StringUtils.lowerCase(channel)); + orgExtIdRequest.put(JsonKey.EXTERNAL_ID, StringUtils.lowerCase(externalId)); + cassandraOperation.deleteRecord(JsonKey.SUNBIRD, JsonKey.ORG_EXT_ID_DB, orgExtIdRequest); + } + + private String validateHashTagId(String hashTagId, String opType, String orgId) { + Map filters = new HashMap<>(); + filters.put(JsonKey.HASHTAGID, hashTagId); + SearchDTO searchDto = new SearchDTO(); + searchDto.getAdditionalProperties().put(JsonKey.FILTERS, filters); + Future> resultF = + esService.search(searchDto, ProjectUtil.EsType.organisation.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + List> dataMapList = (List>) result.get(JsonKey.CONTENT); + if (opType.equalsIgnoreCase(JsonKey.CREATE)) { + if (!dataMapList.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidHashTagId.getErrorCode(), + ResponseCode.invalidHashTagId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else if (opType.equalsIgnoreCase(JsonKey.UPDATE) && !dataMapList.isEmpty()) { + Map orgMap = dataMapList.get(0); + if (!(((String) orgMap.get(JsonKey.ID)).equalsIgnoreCase(orgId))) { + throw new ProjectCommonException( + ResponseCode.invalidHashTagId.getErrorCode(), + ResponseCode.invalidHashTagId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + return hashTagId; + } + + private String validateOrgType(String orgType) { + String orgTypeId = null; + if (!StringUtils.isBlank(DataCacheHandler.getOrgTypeMap().get(orgType.toLowerCase()))) { + orgTypeId = DataCacheHandler.getOrgTypeMap().get(orgType.toLowerCase()); + } else { + Util.DbInfo orgTypeDbInfo = Util.dbInfoMap.get(JsonKey.ORG_TYPE_DB); + Response response = + cassandraOperation.getAllRecords( + orgTypeDbInfo.getKeySpace(), orgTypeDbInfo.getTableName()); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (!list.isEmpty()) { + for (Map map : list) { + if ((((String) map.get(JsonKey.NAME)).toLowerCase()) + .equalsIgnoreCase(orgType.toLowerCase())) { + orgTypeId = (String) map.get(JsonKey.ID); + DataCacheHandler.getOrgTypeMap() + .put(((String) map.get(JsonKey.NAME)).toLowerCase(), (String) map.get(JsonKey.ID)); + } + } + } + if (null == orgTypeId) { + throw ProjectUtil.createClientException(ResponseCode.invalidOrgType); + } + } + return orgTypeId; + } + + /** Updates the status of the Organisation */ + @SuppressWarnings("unchecked") + private void updateOrgStatus(Request actorMessage) { + + // object of telemetry event... + Map targetObject = null; + try { + actorMessage.toLower(); + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + Map request = actorMessage.getRequest(); + if (!(validateOrgRequest(request))) { + ProjectLogger.log("REQUESTED DATA IS NOT VALID"); + return; + } + Map orgDao; + Map updateOrgDao = new HashMap<>(); + String updatedBy = (String) request.get(JsonKey.REQUESTED_BY); + String orgId = (String) request.get(JsonKey.ORGANISATION_ID); + Response result = + cassandraOperation.getRecordById( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), orgId); + List> list = (List>) result.get(JsonKey.RESPONSE); + if (!(list.isEmpty())) { + orgDao = list.get(0); + } else { + ProjectLogger.log("Invalid Org Id"); + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + + Integer currentStatus = (Integer) orgDao.get(JsonKey.STATUS); + Integer nextStatus = (Integer) request.get(JsonKey.STATUS); + if (!(Util.checkOrgStatusTransition(currentStatus, nextStatus))) { + ProjectLogger.log("Invalid Org State transation", LoggerEnum.INFO.name()); + sender().tell(ProjectUtil.createClientException(ResponseCode.invalidRequestData), self()); + return; + } + + if (!(StringUtils.isBlank(updatedBy))) { + updateOrgDao.put(JsonKey.UPDATED_BY, updatedBy); + } + updateOrgDao.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + updateOrgDao.put(JsonKey.ID, orgDao.get(JsonKey.ID)); + updateOrgDao.put(JsonKey.STATUS, nextStatus); + Response response = + cassandraOperation.updateRecord( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), updateOrgDao); + response.getResult().put(JsonKey.ORGANISATION_ID, orgDao.get(JsonKey.ID)); + sender().tell(response, self()); + + // update the ES -- + Request orgRequest = new Request(); + orgRequest.getRequest().put(JsonKey.ORGANISATION, updateOrgDao); + orgRequest.setOperation(ActorOperations.UPDATE_ORG_INFO_ELASTIC.getValue()); + tellToAnother(orgRequest); + + targetObject = + TelemetryUtil.generateTargetObject(orgId, JsonKey.ORGANISATION, JsonKey.UPDATE, null); + Map telemetryAction = new HashMap<>(); + telemetryAction.put("updateOrgStatus", "org status updated."); + TelemetryUtil.telemetryProcessingCall( + telemetryAction, targetObject, new ArrayList<>(), actorMessage.getContext()); + return; + } catch (ProjectCommonException e) { + sender().tell(e, self()); + return; + } + } + + /** Update the Organisation data */ + @SuppressWarnings("unchecked") + private void updateOrgData(Request actorMessage) { + + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + String callerId = (String) actorMessage.getContext().get(JsonKey.CALLER_ID); + try { + actorMessage.toLower(); + Map request = actorMessage.getRequest(); + String orgId = (String) request.get(JsonKey.ORGANISATION_ID); + Response result = + cassandraOperation.getRecordById( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), orgId); + List> list = (List>) result.get(JsonKey.RESPONSE); + Map orgDao; + if (!(list.isEmpty())) { + orgDao = list.get(0); + } else { + ProjectLogger.log( + "OrganisationManagementActor: updateOrgData invalid orgId", LoggerEnum.DEBUG.name()); + sender().tell(ProjectUtil.createClientException(ResponseCode.invalidRequestData), self()); + return; + } + + String existingExternalId = (String) orgDao.get(JsonKey.EXTERNAL_ID); + // fetch channel from org, if channel is not passed + if (!request.containsKey(JsonKey.CHANNEL)) { + String channelFromDB = (String) orgDao.get(JsonKey.CHANNEL); + if (StringUtils.isBlank(channelFromDB)) { + String rootOrgId = (String) orgDao.get(JsonKey.ROOT_ORG_ID); + Map rootOrg = Util.getOrgDetails(rootOrgId); + channelFromDB = (String) rootOrg.get(JsonKey.CHANNEL); + } + request.put(JsonKey.CHANNEL, channelFromDB); + } + validateLocationCodeAndIds(request); + if (request.containsKey(JsonKey.ORG_TYPE) + && !StringUtils.isBlank((String) request.get(JsonKey.ORG_TYPE))) { + request.put(JsonKey.ORG_TYPE_ID, validateOrgType((String) request.get(JsonKey.ORG_TYPE))); + } + if (!(validateOrgRequest(request))) { + ProjectLogger.log("REQUESTED DATA IS NOT VALID for Org update", LoggerEnum.INFO.name()); + return; + } + if (request.containsKey(JsonKey.EMAIL) + && !EmailValidator.isEmailValid((String) request.get(JsonKey.EMAIL))) { + ProjectCommonException.throwClientErrorException(ResponseCode.emailFormatError); + } + // + boolean channelAdded = false; + if ((!request.containsKey(JsonKey.CHANNEL)) && request.containsKey(JsonKey.PROVIDER)) { + // then make provider as channel to fetch root org id. + request.put(JsonKey.CHANNEL, request.get(JsonKey.PROVIDER)); + channelAdded = true; + } + if (request.containsKey(JsonKey.CHANNEL)) { + if (!request.containsKey(JsonKey.IS_ROOT_ORG) + || !(Boolean) request.get(JsonKey.IS_ROOT_ORG)) { + String rootOrgId = getRootOrgIdFromChannel((String) request.get(JsonKey.CHANNEL)); + if (!StringUtils.isBlank(rootOrgId) || channelAdded) { + request.put( + JsonKey.ROOT_ORG_ID, + "".equals(rootOrgId) ? JsonKey.DEFAULT_ROOT_ORG_ID : rootOrgId); + } else { + ProjectLogger.log("Invalid channel id.", LoggerEnum.INFO.name()); + sender().tell(ProjectUtil.createClientException(ResponseCode.invalidChannel), self()); + return; + } + } else if (!channelAdded + && !validateChannelUniqueness( + (String) request.get(JsonKey.CHANNEL), + (String) request.get(JsonKey.ORGANISATION_ID))) { + ProjectLogger.log("Channel validation failed", LoggerEnum.INFO.name()); + sender() + .tell( + ProjectUtil.createClientException(ResponseCode.channelUniquenessInvalid), self()); + return; + } + } + // if channel is not coming and we added it from provider to collect the + // rootOrgId then + // remove channel + if (channelAdded) { + request.remove(JsonKey.CHANNEL); + } + Map addressReq = null; + if (null != request.get(JsonKey.ADDRESS)) { + addressReq = (Map) request.get(JsonKey.ADDRESS); + request.remove(JsonKey.ADDRESS); + } + // removing default from request, not allowing user to create default org. + request.remove(JsonKey.IS_DEFAULT); + // allow lower case values for source and externalId to the database + if (request.get(JsonKey.PROVIDER) != null) { + request.put(JsonKey.PROVIDER, ((String) request.get(JsonKey.PROVIDER)).toLowerCase()); + } + String passedExternalId = (String) request.get(JsonKey.EXTERNAL_ID); + if (StringUtils.isNotBlank(passedExternalId)) { + passedExternalId = passedExternalId.toLowerCase(); + String channel = (String) request.get(JsonKey.CHANNEL); + if (!validateChannelExternalIdUniqueness( + channel, passedExternalId, (String) request.get(JsonKey.ORGANISATION_ID))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorDuplicateEntry, + MessageFormat.format( + ResponseCode.errorDuplicateEntry.getErrorMessage(), + passedExternalId, + JsonKey.EXTERNAL_ID)); + } + request.put(JsonKey.EXTERNAL_ID, passedExternalId); + } else { + request.remove(JsonKey.EXTERNAL_ID); + } + Map updateOrgDao = new HashMap<>(); + updateOrgDao.putAll(request); + updateOrgDao.remove(JsonKey.ORGANISATION_ID); + updateOrgDao.remove(JsonKey.IS_APPROVED); + updateOrgDao.remove(JsonKey.APPROVED_BY); + updateOrgDao.remove(JsonKey.APPROVED_DATE); + updateOrgDao.remove(JsonKey.CONTACT_DETAILS); + if (JsonKey.BULK_ORG_UPLOAD.equalsIgnoreCase(callerId)) { + if (null == request.get(JsonKey.STATUS)) { + updateOrgDao.remove(JsonKey.STATUS); + } + } else { + updateOrgDao.remove(JsonKey.STATUS); + } + + String updatedBy = (String) actorMessage.getRequest().get(JsonKey.REQUESTED_BY); + + boolean isAddressUpdated = false; + // update address if present in request + if (null != addressReq && addressReq.size() == 1) { + if (orgDao.get(JsonKey.ADDRESS_ID) != null) { + String addressId = (String) orgDao.get(JsonKey.ADDRESS_ID); + addressReq.put(JsonKey.ID, addressId); + isAddressUpdated = true; + } + // add new address record + else { + String addressId = ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv()); + addressReq.put(JsonKey.ID, addressId); + orgDao.put(JsonKey.ADDRESS_ID, addressId); + } + if (!(StringUtils.isBlank(updatedBy))) { + addressReq.put(JsonKey.UPDATED_BY, updatedBy); + } + upsertAddress(addressReq); + telemetryGenerationForOrgAddress( + addressReq, orgDao, isAddressUpdated, actorMessage.getContext()); + } + if (!StringUtils.isBlank(((String) request.get(JsonKey.HASHTAGID)))) { + request.put( + JsonKey.HASHTAGID, + validateHashTagId(((String) request.get(JsonKey.HASHTAGID)), JsonKey.UPDATE, orgId)); + } + if (!(StringUtils.isBlank(updatedBy))) { + updateOrgDao.put(JsonKey.UPDATED_BY, updatedBy); + } + updateOrgDao.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + updateOrgDao.put(JsonKey.ID, orgDao.get(JsonKey.ID)); + + // if channel is available then make slug for channel. + // remove the slug key if coming from user input + updateOrgDao.remove(JsonKey.SLUG); + if (updateOrgDao.containsKey(JsonKey.CHANNEL)) { + + String slug = Slug.makeSlug((String) updateOrgDao.getOrDefault(JsonKey.CHANNEL, ""), true); + if ((boolean) orgDao.get(JsonKey.IS_ROOT_ORG)) { + String rootOrgId = getRootOrgIdFromSlug(slug); + if (StringUtils.isBlank(rootOrgId) + || (!StringUtils.isBlank(rootOrgId) + && rootOrgId.equalsIgnoreCase((String) orgDao.get(JsonKey.ID)))) { + updateOrgDao.put(JsonKey.SLUG, slug); + } else { + sender().tell(ProjectUtil.createClientException(ResponseCode.slugIsNotUnique), self()); + return; + } + } else { + updateOrgDao.put(JsonKey.SLUG, slug); + updateOrgDao.put(JsonKey.IS_SSO_ROOTORG_ENABLED, false); + } + } + + if (null != orgDao.get(JsonKey.IS_ROOT_ORG) && (boolean) orgDao.get(JsonKey.IS_ROOT_ORG)) { + String channel = (String) orgDao.get(JsonKey.CHANNEL); + String updateOrgDaoChannel = (String) updateOrgDao.get(JsonKey.CHANNEL); + String license = (String) request.get(JsonKey.LICENSE); + if (null != updateOrgDaoChannel && null != channel && !(updateOrgDaoChannel.equals(channel)) + || StringUtils.isNotBlank(license)) { + Map tempMap = new HashMap<>(); + tempMap.put(JsonKey.CHANNEL, updateOrgDaoChannel); + tempMap.put(JsonKey.HASHTAGID, orgDao.get(JsonKey.HASHTAGID)); + tempMap.put(JsonKey.DESCRIPTION, orgDao.get(JsonKey.DESCRIPTION)); + tempMap.put(JsonKey.LICENSE, license); + boolean bool = Util.updateChannel(tempMap); + if (!bool) { + sender().tell(ProjectUtil.createServerError(ResponseCode.channelRegFailed), self()); + return; + } + } + } + ObjectMapper mapper = new ObjectMapper(); + // This will remove all extra unnecessary parameter from request + Organisation org = mapper.convertValue(updateOrgDao, Organisation.class); + updateOrgDao = mapper.convertValue(org, Map.class); + Response response = + cassandraOperation.updateRecord( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), updateOrgDao); + response.getResult().put(JsonKey.ORGANISATION_ID, orgDao.get(JsonKey.ID)); + + if (StringUtils.isNotBlank(passedExternalId)) { + String channel = (String) request.get(JsonKey.CHANNEL); + if (StringUtils.isBlank(existingExternalId)) { + createOrgExternalIdRecord(channel, passedExternalId, orgId); + } else { + if (!existingExternalId.equalsIgnoreCase(passedExternalId)) { + deleteOrgExternalIdRecord(channel, existingExternalId); + createOrgExternalIdRecord(channel, passedExternalId, orgId); + } + } + } + + sender().tell(response, self()); + + if (null != addressReq) { + updateOrgDao.put(JsonKey.ADDRESS, addressReq); + } + + Request orgRequest = new Request(); + orgRequest.getRequest().put(JsonKey.ORGANISATION, updateOrgDao); + orgRequest.setOperation(ActorOperations.UPDATE_ORG_INFO_ELASTIC.getValue()); + tellToAnother(orgRequest); + targetObject = + TelemetryUtil.generateTargetObject( + (String) orgDao.get(JsonKey.ID), JsonKey.ORGANISATION, JsonKey.UPDATE, null); + TelemetryUtil.telemetryProcessingCall( + updateOrgDao, targetObject, correlatedObject, actorMessage.getContext()); + } catch (ProjectCommonException e) { + sender().tell(e, self()); + return; + } + } + + private void telemetryGenerationForOrgAddress( + Map addressReq, + Map orgDao, + boolean isAddressUpdated, + Map context) { + + String addressState = JsonKey.CREATE; + if (isAddressUpdated) { + addressState = JsonKey.UPDATE; + } + Map targetObject = + TelemetryUtil.generateTargetObject( + (String) addressReq.get(JsonKey.ID), JsonKey.ADDRESS, addressState, null); + List> correlatedObject = new ArrayList<>(); + TelemetryUtil.generateCorrelatedObject( + (String) orgDao.get(JsonKey.ID), JsonKey.ORGANISATION, null, correlatedObject); + TelemetryUtil.telemetryProcessingCall(addressReq, targetObject, correlatedObject, context); + } + + /** Method to add member to the organisation */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private void addMemberOrganisation(Request actorMessage) { + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + Response response = null; + actorMessage.toLower(); + Util.DbInfo userOrgDbInfo = Util.dbInfoMap.get(JsonKey.USER_ORG_DB); + Util.DbInfo organisationDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + Map usrOrgData = actorMessage.getRequest(); + if (!(validateOrgRequestForMembers(usrOrgData))) { + ProjectLogger.log("REQUESTED DATA IS NOT VALID"); + return; + } + if (!(validateUsrRequest(usrOrgData))) { + ProjectLogger.log("REQUESTED DATA IS NOT VALID"); + return; + } + // remove source and external id + usrOrgData.remove(JsonKey.EXTERNAL_ID); + usrOrgData.remove(JsonKey.SOURCE); + usrOrgData.remove(JsonKey.PROVIDER); + usrOrgData.remove(JsonKey.USERNAME); + usrOrgData.remove(JsonKey.USER_NAME); + usrOrgData.remove(JsonKey.USER_EXTERNAL_ID); + usrOrgData.remove(JsonKey.USER_PROVIDER); + usrOrgData.remove(JsonKey.USER_ID_TYPE); + usrOrgData.put(JsonKey.IS_DELETED, false); + + String updatedBy = null; + String orgId = null; + String userId = null; + List roles = new ArrayList<>(); + orgId = (String) usrOrgData.get(JsonKey.ORGANISATION_ID); + userId = (String) usrOrgData.get(JsonKey.USER_ID); + if (isNotNull(usrOrgData.get(JsonKey.REQUESTED_BY))) { + updatedBy = (String) usrOrgData.get(JsonKey.REQUESTED_BY); + usrOrgData.remove(JsonKey.REQUESTED_BY); + } + if (isNotNull(usrOrgData.get(JsonKey.ROLES))) { + roles.addAll((List) usrOrgData.get(JsonKey.ROLES)); + if (!((List) usrOrgData.get(JsonKey.ROLES)).isEmpty()) { + String msg = Util.validateRoles((List) usrOrgData.get(JsonKey.ROLES)); + if (!msg.equalsIgnoreCase(JsonKey.SUCCESS)) { + throw new ProjectCommonException( + ResponseCode.invalidRole.getErrorCode(), + ResponseCode.invalidRole.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } + + usrOrgData.remove(JsonKey.ROLE); + if (isNull(roles) && roles.isEmpty()) { + // create exception here invalid request data and tell the exception , then + // return + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + if (!roles.isEmpty()) usrOrgData.put(JsonKey.ROLES, roles); + // check user already exist for the org or not + Map requestData = new HashMap<>(); + requestData.put(JsonKey.USER_ID, userId); + requestData.put(JsonKey.ORGANISATION_ID, orgId); + Response result = + cassandraOperation.getRecordsByProperties( + userOrgDbInfo.getKeySpace(), userOrgDbInfo.getTableName(), requestData); + + List list = (List) result.get(JsonKey.RESPONSE); + Map tempOrgap = null; + boolean isNewRecord = false; + if (!list.isEmpty()) { + tempOrgap = (Map) list.get(0); + if (null != tempOrgap && !((boolean) tempOrgap.get(JsonKey.IS_DELETED))) { + // user already enrolled for the organisation + response = new Response(); + response.getResult().put(JsonKey.RESPONSE, ResponseMessage.Message.EXISTING_ORG_MEMBER); + sender().tell(response, self()); + return; + } else if (null != tempOrgap && ((boolean) tempOrgap.get(JsonKey.IS_DELETED))) { + usrOrgData.put(JsonKey.ID, tempOrgap.get(JsonKey.ID)); + } + } else { + usrOrgData.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv())); + isNewRecord = true; + } + if (!(StringUtils.isBlank(updatedBy))) { + String updatedByName = Util.getUserNamebyUserId(updatedBy); + usrOrgData.put(JsonKey.ADDED_BY, updatedBy); + usrOrgData.put(JsonKey.APPROVED_BY, updatedBy); + if (!StringUtils.isBlank(updatedByName)) { + usrOrgData.put(JsonKey.ADDED_BY_NAME, updatedByName); + } + } + usrOrgData.put(JsonKey.ORG_JOIN_DATE, ProjectUtil.getFormattedDate()); + usrOrgData.put(JsonKey.APPROOVE_DATE, ProjectUtil.getFormattedDate()); + usrOrgData.put(JsonKey.IS_REJECTED, false); + usrOrgData.put(JsonKey.IS_APPROVED, true); + usrOrgData.put(JsonKey.IS_DELETED, false); + if (isNewRecord) { + response = + cassandraOperation.insertRecord( + userOrgDbInfo.getKeySpace(), userOrgDbInfo.getTableName(), usrOrgData); + } else { + response = + cassandraOperation.updateRecord( + userOrgDbInfo.getKeySpace(), userOrgDbInfo.getTableName(), usrOrgData); + } + Response orgResult = + cassandraOperation.getRecordById( + organisationDbInfo.getKeySpace(), organisationDbInfo.getTableName(), orgId); + + List orgList = (List) orgResult.get(JsonKey.RESPONSE); + Map newOrgMap = new HashMap<>(); + if (!orgList.isEmpty()) { + Integer count = 0; + Map orgMap = (Map) orgList.get(0); + if (isNotNull(orgMap.get(JsonKey.NO_OF_MEMBERS))) { + count = (Integer) orgMap.get(JsonKey.NO_OF_MEMBERS); + } + newOrgMap.put(JsonKey.ID, orgId); + newOrgMap.put(JsonKey.NO_OF_MEMBERS, count + 1); + cassandraOperation.updateRecord( + organisationDbInfo.getKeySpace(), organisationDbInfo.getTableName(), newOrgMap); + } + + sender().tell(response, self()); + + // update ES with latest data through background job manager + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + ProjectLogger.log("method call going to satrt for ES--....."); + Request request = new Request(); + request.setOperation(ActorOperations.UPDATE_USER_ORG_ES.getValue()); + request.getRequest().put(JsonKey.USER, usrOrgData); + ProjectLogger.log("making a call to save user data to ES"); + try { + tellToAnother(request); + } catch (Exception ex) { + ProjectLogger.log( + "Exception Occurred during saving user to Es while addMemberOrganisation : ", ex); + } + } else { + ProjectLogger.log("no call for ES to save user"); + } + + targetObject = TelemetryUtil.generateTargetObject(userId, JsonKey.USER, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject(userId, JsonKey.USER, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject(orgId, JsonKey.ORGANISATION, null, correlatedObject); + Map telemetryAction = new HashMap<>(); + telemetryAction.put("orgMembershipAdded", "orgMembershipAdded"); + TelemetryUtil.telemetryProcessingCall( + telemetryAction, targetObject, correlatedObject, actorMessage.getContext()); + } + + /** Method to remove member from the organisation */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private void removeMemberOrganisation(Request actorMessage) { + Response response = null; + // object of telemetry event... + List> correlatedObject = new ArrayList<>(); + actorMessage.toLower(); + Util.DbInfo userOrgDbInfo = Util.dbInfoMap.get(JsonKey.USER_ORG_DB); + Util.DbInfo organisationDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + Map usrOrgData = actorMessage.getRequest(); + if (!(validateUsrRequest(usrOrgData))) { + ProjectLogger.log("REQUESTED DATA IS NOT VALID"); + return; + } + if (!(validateOrgRequestForMembers(usrOrgData))) { + ProjectLogger.log("REQUESTED DATA IS NOT VALID"); + return; + } + + // remove source and external id + usrOrgData.remove(JsonKey.EXTERNAL_ID); + usrOrgData.remove(JsonKey.SOURCE); + usrOrgData.remove(JsonKey.USERNAME); + usrOrgData.remove(JsonKey.USER_NAME); + + String updatedBy = null; + String orgId = null; + String userId = null; + + orgId = (String) usrOrgData.get(JsonKey.ORGANISATION_ID); + userId = (String) usrOrgData.get(JsonKey.USER_ID); + + if (isNotNull(usrOrgData.get(JsonKey.REQUESTED_BY))) { + updatedBy = (String) usrOrgData.get(JsonKey.REQUESTED_BY); + usrOrgData.remove(JsonKey.REQUESTED_BY); + } + // check user already exist for the org or not + Map requestData = new HashMap<>(); + requestData.put(JsonKey.USER_ID, userId); + requestData.put(JsonKey.ORGANISATION_ID, orgId); + Response result = + cassandraOperation.getRecordsByProperties( + userOrgDbInfo.getKeySpace(), userOrgDbInfo.getTableName(), requestData); + + List list = (List) result.get(JsonKey.RESPONSE); + if (list.isEmpty()) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } else { + Map dataMap = (Map) list.get(0); + if (null != dataMap.get(JsonKey.IS_DELETED) && (boolean) dataMap.get(JsonKey.IS_DELETED)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.userInactiveForThisOrg.getErrorCode(), + ResponseCode.userInactiveForThisOrg.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + if (!(StringUtils.isBlank(updatedBy))) { + dataMap.put(JsonKey.UPDATED_BY, updatedBy); + } + dataMap.put(JsonKey.ORG_LEFT_DATE, ProjectUtil.getFormattedDate()); + dataMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + dataMap.put(JsonKey.IS_DELETED, true); + response = + cassandraOperation.updateRecord( + userOrgDbInfo.getKeySpace(), userOrgDbInfo.getTableName(), dataMap); + Map newOrgMap = new HashMap<>(); + + Response orgresult = + cassandraOperation.getRecordById( + organisationDbInfo.getKeySpace(), organisationDbInfo.getTableName(), orgId); + List orgList = (List) orgresult.get(JsonKey.RESPONSE); + if (!orgList.isEmpty()) { + Map orgMap = (Map) orgList.get(0); + if (isNotNull(orgMap.get(JsonKey.NO_OF_MEMBERS))) { + Integer count = (Integer) orgMap.get(JsonKey.NO_OF_MEMBERS); + newOrgMap.put(JsonKey.ID, orgId); + newOrgMap.put(JsonKey.NO_OF_MEMBERS, count == 0 ? 0 : (count - 1)); + cassandraOperation.updateRecord( + organisationDbInfo.getKeySpace(), organisationDbInfo.getTableName(), newOrgMap); + } + } + sender().tell(response, self()); + + // update ES with latest data through background job manager + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + ProjectLogger.log("method call going to satrt for ES--....."); + Request request = new Request(); + request.setOperation(ActorOperations.REMOVE_USER_ORG_ES.getValue()); + request.getRequest().put(JsonKey.USER, dataMap); + ProjectLogger.log("making a call to save user data to ES"); + try { + tellToAnother(request); + } catch (Exception ex) { + ProjectLogger.log( + "Exception Occurred during saving user to Es while removing memeber from Organisation : ", + ex); + } + } else { + ProjectLogger.log("no call for ES to save user"); + } + Map targetObject = + TelemetryUtil.generateTargetObject(userId, JsonKey.USER, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject(userId, JsonKey.USER, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject(orgId, JsonKey.ORGANISATION, null, correlatedObject); + Map telemetryAction = new HashMap<>(); + telemetryAction.put("orgMembershipRemoved", "orgMembershipRemoved"); + TelemetryUtil.telemetryProcessingCall( + telemetryAction, targetObject, correlatedObject, actorMessage.getContext()); + } + } + + /** Provides the details of the Organisation */ + private void getOrgDetails(Request actorMessage) { + actorMessage.toLower(); + Map request = actorMessage.getRequest(); + if (!(validateOrgRequest(request))) { + ProjectLogger.log("REQUESTED DATA IS NOT VALID"); + return; + } + String orgId = (String) request.get(JsonKey.ORGANISATION_ID); + Future> resultF = + esService.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), orgId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + + if (MapUtils.isEmpty(result)) { + throw new ProjectCommonException( + ResponseCode.orgDoesNotExist.getErrorCode(), + ResponseCode.orgDoesNotExist.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + result.remove(JsonKey.CONTACT_DETAILS); + Response response = new Response(); + response.put(JsonKey.RESPONSE, result); + sender().tell(response, self()); + } + + /** Inserts an address if not present, else updates the existing address */ + private void upsertAddress(Map addressReq) { + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ADDRESS_DB); + cassandraOperation.upsertRecord(orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), addressReq); + } + + /** + * validates if the Organisation and parent Organisation has the same root Organisation else + * throws error + */ + @SuppressWarnings("unchecked") + public void validateRootOrg(Map request) { + ProjectLogger.log("Validating Root org started---"); + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + if (!StringUtils.isBlank((String) request.get(JsonKey.PARENT_ORG_ID))) { + Response result = + cassandraOperation.getRecordById( + orgDbInfo.getKeySpace(), + orgDbInfo.getTableName(), + (String) request.get(JsonKey.PARENT_ORG_ID)); + List> list = (List>) result.get(JsonKey.RESPONSE); + Map parentOrgDao = new HashMap<>(); + if (!(list.isEmpty())) { + parentOrgDao = list.get(0); + } + if (!StringUtils.isBlank((String) parentOrgDao.get(JsonKey.ROOT_ORG_ID))) { + String parentRootOrg = (String) parentOrgDao.get(JsonKey.ROOT_ORG_ID); + if (null != request.get(JsonKey.ROOT_ORG_ID) + && !parentRootOrg.equalsIgnoreCase(request.get(JsonKey.ROOT_ORG).toString())) { + throw new ProjectCommonException( + ResponseCode.invalidRootOrganisationId.getErrorCode(), + ResponseCode.invalidRootOrganisationId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else { + // set the parent root org to this organisation. + request.put(JsonKey.ROOT_ORG_ID, parentRootOrg); + } + } + } + ProjectLogger.log("Validating Root org ended successfully---"); + } + + // Check whether channel value is present + public void channelMandatoryValidation(Map request) { + if (StringUtils.isBlank((String) request.get(JsonKey.CHANNEL))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.CHANNEL), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * Validates whether the organisation or source with externalId exists in DB + * + * @param req Request from the user + * @return boolean + */ + @SuppressWarnings("unchecked") + private boolean validateOrgRequest(Map req) { + + if (isNull(req)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + + if (isNull(req.get(JsonKey.ORGANISATION_ID))) { + + if (isNull(req.get(JsonKey.PROVIDER)) || isNull(req.get(JsonKey.EXTERNAL_ID))) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + + // fetch orgid from database on basis of source and external id and put orgid + // into request . + Util.DbInfo userdbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + + Map requestDbMap = new HashMap<>(); + requestDbMap.put(JsonKey.PROVIDER, req.get(JsonKey.PROVIDER)); + requestDbMap.put(JsonKey.EXTERNAL_ID, req.get(JsonKey.EXTERNAL_ID)); + Response result = + cassandraOperation.getRecordsByProperties( + userdbInfo.getKeySpace(), userdbInfo.getTableName(), requestDbMap); + List> list = (List>) result.get(JsonKey.RESPONSE); + + if (list.isEmpty()) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + + req.put(JsonKey.ORGANISATION_ID, list.get(0).get(JsonKey.ID)); + } + return true; + } + + /** + * Validates whether the organisation or source with externalId exists in DB + * + * @param req + * @return boolean + */ + @SuppressWarnings("unchecked") + private boolean validateOrgRequestForMembers(Map req) { + if (isNull(req)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + if (isNull(req.get(JsonKey.ORGANISATION_ID)) + && (isNull(req.get(JsonKey.PROVIDER)) || isNull(req.get(JsonKey.EXTERNAL_ID)))) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.sourceAndExternalIdValidationError.getErrorCode(), + ResponseCode.sourceAndExternalIdValidationError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + // fetch orgid from database on basis of source and external id and put orgid + // into request . + + Map requestDbMap = new HashMap<>(); + if (!StringUtils.isBlank((String) req.get(JsonKey.ORGANISATION_ID))) { + requestDbMap.put(JsonKey.ID, req.get(JsonKey.ORGANISATION_ID)); + } else { + requestDbMap.put(JsonKey.PROVIDER, StringUtils.lowerCase((String) req.get(JsonKey.PROVIDER))); + requestDbMap.put( + JsonKey.EXTERNAL_ID, StringUtils.lowerCase((String) req.get(JsonKey.EXTERNAL_ID))); + } + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, requestDbMap); + Future> esResponseF = + esService.search(searchDTO, ProjectUtil.EsType.organisation.getTypeName()); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponseF); + List> list = (List>) esResponse.get(JsonKey.CONTENT); + if (null == list || list.isEmpty()) { + + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + req.put(JsonKey.ORGANISATION_ID, list.get(0).get(JsonKey.ID)); + req.put(JsonKey.HASHTAGID, list.get(0).get(JsonKey.HASHTAGID)); + return true; + } + + /** + * Validates where the userId or provider with userName is in database and is valid + * + * @param req + * @return boolean + */ + @SuppressWarnings("unchecked") + private boolean validateUsrRequest(Map req) { + if (isNull(req)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + Map data = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + data.putAll(req); + if (isNull(data.get(JsonKey.USER_ID)) + && isNull(data.get(JsonKey.USER_EXTERNAL_ID)) + && isNull(data.get(JsonKey.USERNAME))) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.usrValidationError.getErrorCode(), + ResponseCode.usrValidationError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + Response result = null; + boolean fromExtId = false; + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Map requestDbMap = new HashMap<>(); + if (!StringUtils.isBlank((String) data.get(JsonKey.USER_ID))) { + requestDbMap.put(JsonKey.ID, data.get(JsonKey.USER_ID)); + result = + cassandraOperation.getRecordsByProperty( + usrDbInfo.getKeySpace(), + usrDbInfo.getTableName(), + JsonKey.ID, + data.get(JsonKey.USER_ID)); + } else if (StringUtils.isNotBlank((String) data.get(JsonKey.USER_EXTERNAL_ID)) + && StringUtils.isNotBlank((String) data.get(JsonKey.USER_PROVIDER)) + && StringUtils.isNotBlank((String) data.get(JsonKey.USER_ID_TYPE))) { + requestDbMap.put(JsonKey.PROVIDER, data.get(JsonKey.USER_PROVIDER)); + requestDbMap.put(JsonKey.ID_TYPE, data.get(JsonKey.USER_ID_TYPE)); + requestDbMap.put( + JsonKey.EXTERNAL_ID, Util.encryptData((String) data.get(JsonKey.USER_EXTERNAL_ID))); + + result = + cassandraOperation.getRecordsByProperties( + JsonKey.SUNBIRD, JsonKey.USR_EXT_IDNT_TABLE, requestDbMap); + fromExtId = true; + } else { + usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + requestDbMap.put(JsonKey.PROVIDER, data.get(JsonKey.PROVIDER)); + requestDbMap.put(JsonKey.USERNAME, data.get(JsonKey.USERNAME)); + if (data.containsKey(JsonKey.PROVIDER) + && !StringUtils.isBlank((String) data.get(JsonKey.PROVIDER))) { + data.put( + JsonKey.LOGIN_ID, + (String) data.get(JsonKey.USERNAME) + "@" + (String) data.get(JsonKey.PROVIDER)); + } else { + data.put(JsonKey.LOGIN_ID, data.get(JsonKey.USERNAME)); + } + String loginId = ""; + try { + loginId = encryptionService.encryptData((String) data.get(JsonKey.LOGIN_ID)); + } catch (Exception e) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + result = + cassandraOperation.getRecordsByProperty( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), JsonKey.LOGIN_ID, loginId); + } + List> list = (List>) result.get(JsonKey.RESPONSE); + if (list.isEmpty()) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidUsrData.getErrorCode(), + ResponseCode.invalidUsrData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return false; + } + String userId = + (fromExtId) + ? (String) list.get(0).get(JsonKey.USER_ID) + : (String) list.get(0).get(JsonKey.ID); + req.put(JsonKey.USER_ID, userId); + return true; + } + + private List> getOrg(String channel) { + ProjectLogger.log( + "OrganisationManagementActor:getOrg: channel = " + channel, LoggerEnum.INFO.name()); + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + Map requestData = new HashMap<>(); + requestData.put(JsonKey.CHANNEL, channel); + requestData.put(JsonKey.IS_ROOT_ORG, true); + Response result = + cassandraOperation.getRecordsByProperties( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), requestData); + ProjectLogger.log( + "OrganisationManagementActor:getOrg: result = " + result.toString(), + LoggerEnum.INFO.name()); + ProjectLogger.log( + "OrganisationManagementActor:getOrg: result.response = " + + result.get(JsonKey.RESPONSE).toString(), + LoggerEnum.INFO.name()); + return (List>) result.get(JsonKey.RESPONSE); + } + + private String getRootOrgIdFromChannel(String channel) { + ProjectLogger.log( + "OrganisationManagementActor:getRootOrgIdFromChannel: channel = " + channel, + LoggerEnum.INFO.name()); + if (!StringUtils.isBlank(channel)) { + List> list = getOrg(channel); + if (!list.isEmpty()) return (String) list.get(0).getOrDefault(JsonKey.ID, ""); + } + + return ""; + } + + private String getRootOrgIdFromSlug(String slug) { + if (!StringUtils.isBlank(slug)) { + Map filters = new HashMap<>(); + filters.put(JsonKey.SLUG, slug); + filters.put(JsonKey.IS_ROOT_ORG, true); + Map esResult = + elasticSearchComplexSearch( + filters, EsIndex.sunbird.getIndexName(), EsType.organisation.getTypeName()); + if (isNotNull(esResult) + && esResult.containsKey(JsonKey.CONTENT) + && isNotNull(esResult.get(JsonKey.CONTENT)) + && (!((List) esResult.get(JsonKey.CONTENT)).isEmpty())) { + Map esContent = + ((List>) esResult.get(JsonKey.CONTENT)).get(0); + return (String) esContent.getOrDefault(JsonKey.ID, ""); + } + } + return ""; + } + + private boolean isSlugUnique(String slug) { + if (!StringUtils.isBlank(slug)) { + Map filters = new HashMap<>(); + filters.put(JsonKey.SLUG, slug); + filters.put(JsonKey.IS_ROOT_ORG, true); + Map esResult = + elasticSearchComplexSearch( + filters, EsIndex.sunbird.getIndexName(), EsType.organisation.getTypeName()); + if (isNotNull(esResult) + && esResult.containsKey(JsonKey.CONTENT) + && isNotNull(esResult.get(JsonKey.CONTENT))) { + return (((List) esResult.get(JsonKey.CONTENT)).isEmpty()); + } + } + return false; + } + + private Map elasticSearchComplexSearch( + Map filters, String index, String type) { + + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + Future> resultF = esService.search(searchDTO, type); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + return esResponse; + } + + /** + * validates if channel is already present in the organisation while Updating + * + * @param channel + * @return boolean + */ + @SuppressWarnings("unchecked") + private boolean validateChannelUniqueness(String channel, String orgId) { + if (!StringUtils.isBlank(channel)) { + return validateFieldUniqueness(JsonKey.CHANNEL, channel, orgId); + } + return (orgId == null); + } + + private boolean validateChannelExternalIdUniqueness( + String channel, String externalId, String orgId) { + Map compositeKeyMap = new HashMap(); + compositeKeyMap.put(JsonKey.PROVIDER, StringUtils.lowerCase(channel)); + compositeKeyMap.put(JsonKey.EXTERNAL_ID, StringUtils.lowerCase(externalId)); + return handleChannelExternalIdUniqueness(compositeKeyMap, orgId); + } + + private boolean validateFieldUniqueness(String key, String value, String orgId) { + if (value != null) { + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + Response result = + cassandraOperation.getRecordsByProperty( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), key, value); + List> list = (List>) result.get(JsonKey.RESPONSE); + if ((list.isEmpty())) { + return true; + } else { + if (orgId == null) { + return false; + } + Map data = list.get(0); + String id = (String) data.get(JsonKey.ID); + if (id.equalsIgnoreCase(orgId)) { + return true; + } else { + return false; + } + } + } + return true; + } + + private boolean handleChannelExternalIdUniqueness( + Map compositeKeyMap, String orgId) { + if (MapUtils.isNotEmpty(compositeKeyMap)) { + Response result = + cassandraOperation.getRecordsByCompositeKey( + JsonKey.SUNBIRD, JsonKey.ORG_EXT_ID_DB, compositeKeyMap); + List> list = (List>) result.get(JsonKey.RESPONSE); + if ((list.isEmpty())) { + return true; + } else { + if (orgId == null) { + return false; + } + Map data = list.get(0); + String id = (String) data.get(JsonKey.ORG_ID); + if (id.equalsIgnoreCase(orgId)) { + return true; + } else { + return false; + } + } + } + return false; + } + + /** + * This method will do the channel uniqueness validation + * + * @param req + */ + private void validateChannel(Map req) { + // this if will run for suborg creation, it will fetch + // rootOrgId from passed channel value. + if (!req.containsKey(JsonKey.IS_ROOT_ORG) || !(Boolean) req.get(JsonKey.IS_ROOT_ORG)) { + String channel = (String) req.get(JsonKey.CHANNEL); + + Map rootOrg = getRootOrgFromChannel(channel); + if (MapUtils.isEmpty(rootOrg)) { + ProjectLogger.log( + "OrganisationManagementActor:validateChannel: Invalid channel = " + channel, + LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.invalidChannel.getErrorCode(), + ResponseCode.invalidChannel.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + String rootOrgId = (String) rootOrg.get(JsonKey.ID); + if (!StringUtils.isBlank(rootOrgId)) { + req.put(JsonKey.ROOT_ORG_ID, rootOrgId); + } else { + ProjectLogger.log( + "OrganisationManagementActor:validateChannel: Invalid channel = " + channel, + LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.invalidChannel.getErrorCode(), + ResponseCode.invalidChannel.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Object status = rootOrg.get(JsonKey.STATUS); + if (null != status && 1 != (Integer) status) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorInactiveOrg, + ProjectUtil.formatMessage( + ResponseCode.errorInactiveOrg.getErrorMessage(), JsonKey.CHANNEL, channel)); + } + } else if (!validateChannelUniqueness((String) req.get(JsonKey.CHANNEL), null)) { + ProjectLogger.log( + "OrganisationManagementActor:validateChannel: Channel validation failed", + LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.channelUniquenessInvalid.getErrorCode(), + ResponseCode.channelUniquenessInvalid.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /* + * This method will fetch root org details from elastic search based on channel value. + */ + private Map getRootOrgFromChannel(String channel) { + ProjectLogger.log( + "OrganisationManagementActor:getRootOrgFromChannel: channel = " + channel, + LoggerEnum.INFO.name()); + if (StringUtils.isNotBlank(channel)) { + Map filterMap = new HashMap<>(); + filterMap.put(JsonKey.CHANNEL, channel); + filterMap.put(JsonKey.IS_ROOT_ORG, true); + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filterMap); + Future> esResponseF = + esService.search(searchDTO, ProjectUtil.EsType.organisation.getTypeName()); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponseF); + + List> list = (List>) esResponse.get(JsonKey.CONTENT); + if (CollectionUtils.isNotEmpty(list)) { + return list.get(0); + } + } + return new HashMap(); + } + + /* + * This method will validate the locationId and locationCode. + */ + @SuppressWarnings("unchecked") + private void validateLocationCodeAndIds(Map request) { + List locationIdsList; + if (CollectionUtils.isNotEmpty((List) request.get(JsonKey.LOCATION_IDS))) { + locationIdsList = + validator.getHierarchyLocationIds( + getActorRef(LocationActorOperation.SEARCH_LOCATION.getValue()), + (List) request.get(JsonKey.LOCATION_IDS)); + request.put(JsonKey.LOCATION_IDS, locationIdsList); + } else { + if (CollectionUtils.isNotEmpty((List) request.get(JsonKey.LOCATION_CODE))) { + locationIdsList = + validator.getValidatedLocationIds( + getActorRef(LocationActorOperation.SEARCH_LOCATION.getValue()), + (List) request.get(JsonKey.LOCATION_CODE)); + request.put(JsonKey.LOCATION_IDS, locationIdsList); + request.remove(JsonKey.LOCATION_CODE); + } + } + } + + private Map getOrgById(String id) { + Map responseMap = new HashMap<>(); + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + Response response = + cassandraOperation.getRecordById(orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), id); + Map record = response.getResult(); + if (null != record && null != record.get(JsonKey.RESPONSE)) { + if (((List) record.get(JsonKey.RESPONSE)).size() != 0) { + responseMap = (Map) ((List) record.get(JsonKey.RESPONSE)).get(0); + } + ProjectLogger.log( + "OrganisationManagementActor:getOrgById found org with Id: " + id, + LoggerEnum.INFO.name()); + } + return responseMap; + } + + private boolean isRootOrgIdValid(String id) { + Map orgDbMap = getOrgById(id); + return MapUtils.isNotEmpty(orgDbMap) ? (boolean) orgDbMap.get(JsonKey.IS_ROOT_ORG) : false; + } + + private void throwExceptionForInvalidRootOrg(String id) { + ProjectLogger.log( + "OrganisationManagementActor:throwExceptionForInvalidRootOrg no root org found with Id: " + + id, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidOrgId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + private void assignKey(Request request) { + addKeysToRequestMap(request); + removeUnusedField(request); + if (!isRootOrgIdValid((String) request.get(JsonKey.ID))) { + throwExceptionForInvalidRootOrg((String) request.get(JsonKey.ID)); + } + Response response = updateCassandraOrgRecord(request.getRequest()); + sender().tell(response, self()); + ProjectLogger.log( + "OrganisationManagementActor:assignKey keys assigned to root org with Id: " + + request.get(JsonKey.ID), + LoggerEnum.INFO.name()); + updateOrgInfoToES(request.getRequest()); + } + + private void removeUnusedField(Request request) { + request.getRequest().remove(JsonKey.ENC_KEYS); + request.getRequest().remove(JsonKey.SIGN_KEYS); + request.getRequest().remove(JsonKey.USER_ID); + } + + private void addKeysToRequestMap(Request request) { + List encKeys = (List) request.get(JsonKey.ENC_KEYS); + List signKeys = (List) request.get(JsonKey.SIGN_KEYS); + Map> keys = new HashMap<>(); + keys.put(JsonKey.ENC_KEYS, encKeys); + keys.put(JsonKey.SIGN_KEYS, signKeys); + request.getRequest().put(JsonKey.KEYS, keys); + } + + private void updateOrgInfoToES(Map updatedOrgMap) { + Request orgRequest = new Request(); + orgRequest.getRequest().put(JsonKey.ORGANISATION, updatedOrgMap); + orgRequest.setOperation(ActorOperations.UPDATE_ORG_INFO_ELASTIC.getValue()); + tellToAnother(orgRequest); + } + + private Response updateCassandraOrgRecord(Map reqMap) { + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + return cassandraOperation.updateRecord( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), reqMap); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/SchedularActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/SchedularActor.java new file mode 100644 index 0000000000..14aaf0bdf3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/SchedularActor.java @@ -0,0 +1,82 @@ +package org.sunbird.learner.actors; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; + +/** @author Amit Kumar */ +@ActorConfig( + tasks = {}, + asyncTasks = {"scheduleBulkUpload"} +) +public class SchedularActor extends BaseActor { + @Override + public void onReceive(Request actorMessage) throws Throwable { + if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.SCHEDULE_BULK_UPLOAD.getValue())) { + schedule(actorMessage); + } else { + ProjectLogger.log("UNSUPPORTED OPERATION"); + } + } + + @SuppressWarnings("unchecked") + private void schedule(Request request) { + List> result = (List>) request.get(JsonKey.DATA); + Util.DbInfo bulkDb = Util.dbInfoMap.get(JsonKey.BULK_OP_DB); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + for (Map map : result) { + int retryCount = 0; + if (null != map.get(JsonKey.RETRY_COUNT)) { + retryCount = (int) map.get(JsonKey.RETRY_COUNT); + } + if (retryCount > 2) { + String data = (String) map.get(JsonKey.DATA); + try { + Map bulkMap = new HashMap<>(); + bulkMap.put(JsonKey.DATA, UserUtility.encryptData(data)); + bulkMap.put(JsonKey.PROCESS_ID, map.get(JsonKey.ID)); + bulkMap.put(JsonKey.STATUS, ProjectUtil.BulkProcessStatus.FAILED.getValue()); + cassandraOperation.updateRecord(bulkDb.getKeySpace(), bulkDb.getTableName(), bulkMap); + } catch (Exception e) { + ProjectLogger.log( + "Exception occurred while encrypting data while running scheduler for bulk upload process : ", + e); + } + } else { + Map bulkMap = new HashMap<>(); + bulkMap.put(JsonKey.RETRY_COUNT, retryCount + 1); + bulkMap.put(JsonKey.ID, map.get(JsonKey.ID)); + bulkMap.put(JsonKey.STATUS, ProjectUtil.BulkProcessStatus.IN_PROGRESS.getValue()); + cassandraOperation.updateRecord(bulkDb.getKeySpace(), bulkDb.getTableName(), bulkMap); + Request req = new Request(); + req.put(JsonKey.PROCESS_ID, map.get(JsonKey.ID)); + ProjectLogger.log( + "SchedularActor: scheduleBulkUpload called with processId " + + map.get(JsonKey.ID) + + " and type " + + map.get(JsonKey.OBJECT_TYPE), + LoggerEnum.INFO); + if (JsonKey.LOCATION.equalsIgnoreCase((String) map.get(JsonKey.OBJECT_TYPE))) { + req.setOperation(BulkUploadActorOperation.LOCATION_BULK_UPLOAD_BACKGROUND_JOB.getValue()); + } else if (JsonKey.ORGANISATION.equalsIgnoreCase((String) map.get(JsonKey.OBJECT_TYPE))) { + req.setOperation(BulkUploadActorOperation.ORG_BULK_UPLOAD_BACKGROUND_JOB.getValue()); + } else if (JsonKey.USER.equals((String) map.get(JsonKey.OBJECT_TYPE))) { + req.setOperation(BulkUploadActorOperation.USER_BULK_UPLOAD_BACKGROUND_JOB.getValue()); + } else { + req.setOperation(ActorOperations.PROCESS_BULK_UPLOAD.getValue()); + } + tellToAnother(req); + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BaseBulkUploadActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BaseBulkUploadActor.java new file mode 100644 index 0000000000..766b53d9c2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BaseBulkUploadActor.java @@ -0,0 +1,492 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.opencsv.CSVReader; +import com.opencsv.CSVReaderBuilder; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.ArrayUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.ProjectUtil.BulkProcessStatus; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessDao; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessTaskDao; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessDaoImpl; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessTaskDaoImpl; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; +import org.sunbird.learner.util.Util; + +/** + * Actor contains the common functionality for bulk upload. + * + * @author arvind. + */ +public abstract class BaseBulkUploadActor extends BaseActor { + + public void validateBulkUploadFields( + String[] csvHeaderLine, String[] allowedFields, Boolean allFieldsMandatory) { + validateBulkUploadFields(csvHeaderLine, allowedFields, allFieldsMandatory, false); + } + + /** + * Method to validate whether the header fields are valid. + * + * @param csvHeaderLine Array of string represents the header line of file. + * @param allowedFields List of mandatory header fields. + * @param allFieldsMandatory Boolean value . If true then all allowed fields should be in the + * csvHeaderline . In case of false- csvHeader could be subset of the allowed fields. + */ + public void validateBulkUploadFields( + String[] csvHeaderLine, String[] allowedFields, Boolean allFieldsMandatory, boolean toLower) { + + if (ArrayUtils.isEmpty(csvHeaderLine)) { + throw new ProjectCommonException( + ResponseCode.emptyHeaderLine.getErrorCode(), + ResponseCode.emptyHeaderLine.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + if (allFieldsMandatory) { + Arrays.stream(allowedFields) + .forEach( + x -> { + if (toLower) { + x = x.toLowerCase(); + } + if (!(ArrayUtils.contains(csvHeaderLine, x))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + x); + } + }); + } + Arrays.stream(csvHeaderLine) + .forEach( + x -> { + if (toLower) { + x = x.toLowerCase(); + } + if (!(ArrayUtils.contains(allowedFields, x))) { + throwInvalidColumnException(x, String.join(", ", allowedFields)); + } + }); + } + + private void throwInvalidColumnException(String invalidColumn, String validColumns) { + throw new ProjectCommonException( + ResponseCode.invalidColumns.getErrorCode(), + ResponseCode.invalidColumns.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + invalidColumn, + validColumns); + } + + /** + * Method to trim all the elements of string array. + * + * @param columnArr array of names. + * @return String[] string array having all attribute names trimmed. + */ + public String[] trimColumnAttributes(String[] columnArr) { + for (int i = 0; i < columnArr.length; i++) { + columnArr[i] = columnArr[i].trim(); + } + return columnArr; + } + + public BulkUploadProcess getBulkUploadProcessForFailedStatus( + String processId, int status, Exception ex) { + BulkUploadProcess bulkUploadProcess = new BulkUploadProcess(); + bulkUploadProcess.setId(processId); + bulkUploadProcess.setStatus(status); + bulkUploadProcess.setFailureResult(ex.getMessage()); + return bulkUploadProcess; + } + + /** + * Method to get CsvReader from byte array. + * + * @param byteArray represents the content of file in bytes. + * @param seperator The delimiter to use for separating entries. + * @param quoteChar The character to use for quoted elements. + * @param lineNum The number of lines to skip before reading. + * @return CsvReader. + * @throws UnsupportedEncodingException + */ + public CSVReader getCsvReader(byte[] byteArray, char seperator, char quoteChar, int lineNum) + throws UnsupportedEncodingException { + InputStreamReader inputStreamReader = + new InputStreamReader(new ByteArrayInputStream(byteArray), StandardCharsets.UTF_8); + CSVReaderBuilder csvReaderBuilder = new CSVReaderBuilder(inputStreamReader); + CSVReader csvReader = csvReaderBuilder.build(); + return csvReader; + } + + public List parseCsvFile(byte[] byteArray, String processId) throws IOException { + CSVReader csvReader = null; + // Create List for holding objects + List rows = new ArrayList<>(); + try { + csvReader = getCsvReader(byteArray, ',', '"', 0); + String[] strArray; + // Read one line at a time + while ((strArray = csvReader.readNext()) != null) { + if (ProjectUtil.isNotEmptyStringArray(strArray)) { + continue; + } + List list = new ArrayList<>(); + for (String token : strArray) { + list.add(token); + } + rows.add(list.toArray(list.toArray(new String[strArray.length]))); + } + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while processing csv file : ", ex); + BulkUploadProcessDao bulkUploadDao = new BulkUploadProcessDaoImpl(); + BulkUploadProcess bulkUploadProcess = + getBulkUploadProcessForFailedStatus(processId, BulkProcessStatus.FAILED.getValue(), ex); + bulkUploadDao.update(bulkUploadProcess); + throw ex; + } finally { + try { + IOUtils.closeQuietly(csvReader); + } catch (Exception e) { + ProjectLogger.log("Exception occurred while closing csv reader : ", e); + } + } + return rows; + } + + /** + * Method to check whether number of lines in the file is permissible or not. + * + * @param maxLines Number represents the max allowed lines in the file including the header line + * as well. + * @param actualLines Number represents the number of lines in the file including the header line + * as well. + */ + public void validateFileSizeAgainstLineNumbers(int maxLines, int actualLines) { + if (actualLines > 0 && actualLines > maxLines) { + throw new ProjectCommonException( + ResponseCode.dataSizeError.getErrorCode(), + ProjectUtil.formatMessage(ResponseCode.dataSizeError.getErrorMessage(), (maxLines - 1)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * Method to check whether file content is not empty. + * + * @param csvLines list of csv lines. Here we are checking file size should greater than 1 since + * first line represents the header. + */ + public void validateEmptyBulkUploadFile(List csvLines) { + + if (null != csvLines) { + if (csvLines.size() < 2) { + throw new ProjectCommonException( + ResponseCode.emptyFile.getErrorCode(), + ResponseCode.emptyFile.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else { + throw new ProjectCommonException( + ResponseCode.emptyFile.getErrorCode(), + ResponseCode.emptyFile.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + protected Integer getBatchSize(String key) { + Integer DEFAULT_BATCH_SIZE = 10; + Integer batchSize = DEFAULT_BATCH_SIZE; + try { + batchSize = Integer.parseInt(ProjectUtil.getConfigValue(key)); + } catch (Exception ex) { + ProjectLogger.log("Failed to read cassandra batch size for:" + key, ex); + } + return batchSize; + } + + protected Integer validateAndParseRecords( + byte[] fileByteArray, String processId, Map additionalRowFields) + throws IOException { + return validateAndParseRecords(fileByteArray, processId, additionalRowFields, null, false); + } + + protected Integer validateAndParseRecords( + byte[] fileByteArray, + String processId, + Map additionalRowFields, + Map csvColumnMap, + boolean toLowerCase) + throws IOException { + + Integer sequence = 0; + Integer count = 0; + CSVReader csvReader = null; + String[] csvLine; + String[] csvColumns = null; + Map record = new HashMap<>(); + List records = new ArrayList<>(); + ObjectMapper mapper = new ObjectMapper(); + try { + csvReader = getCsvReader(fileByteArray, ',', '"', 0); + while ((csvLine = csvReader.readNext()) != null) { + if (ProjectUtil.isNotEmptyStringArray(csvLine)) { + continue; + } + if (sequence == 0) { + csvColumns = trimColumnAttributes(csvLine); + } else { + for (int j = 0; j < csvColumns.length && j < csvLine.length; j++) { + String value = (csvLine[j].trim().length() == 0 ? null : csvLine[j].trim()); + String coulumn = toLowerCase ? csvColumns[j].toLowerCase() : csvColumns[j]; + if (csvColumnMap != null && csvColumnMap.get(coulumn) != null) { + record.put((String) csvColumnMap.get(coulumn), value); + } else { + record.put(csvColumns[j], value); + } + } + record.putAll(additionalRowFields); + BulkUploadProcessTask tasks = new BulkUploadProcessTask(); + tasks.setStatus(ProjectUtil.BulkProcessStatus.NEW.getValue()); + tasks.setSequenceId(sequence); + tasks.setProcessId(processId); + tasks.setData(mapper.writeValueAsString(record)); + tasks.setCreatedOn(new Timestamp(System.currentTimeMillis())); + records.add(tasks); + count++; + if (count >= getBatchSize(JsonKey.CASSANDRA_WRITE_BATCH_SIZE)) { + performBatchInsert(records); + records.clear(); + count = 0; + } + record.clear(); + } + sequence++; + } + if (count != 0) { + performBatchInsert(records); + count = 0; + records.clear(); + } + } catch (Exception ex) { + BulkUploadProcessDao bulkUploadDao = new BulkUploadProcessDaoImpl(); + BulkUploadProcess bulkUploadProcess = + getBulkUploadProcessForFailedStatus(processId, BulkProcessStatus.FAILED.getValue(), ex); + bulkUploadDao.update(bulkUploadProcess); + throw ex; + } finally { + IOUtils.closeQuietly(csvReader); + } + // since one record represents the header + return sequence - 1; + } + + protected void performBatchInsert(List records) { + BulkUploadProcessTaskDao bulkUploadProcessTaskDao = new BulkUploadProcessTaskDaoImpl(); + try { + bulkUploadProcessTaskDao.insertBatchRecord(records); + } catch (Exception ex) { + ProjectLogger.log("Cassandra batch insert failed , performing retry logic.", LoggerEnum.INFO); + for (BulkUploadProcessTask task : records) { + try { + bulkUploadProcessTaskDao.create(task); + } catch (Exception exception) { + ProjectLogger.log( + "Cassandra Insert failed for BulkUploadProcessTask-" + + task.getProcessId() + + task.getSequenceId(), + exception); + } + } + } + } + + protected void performBatchUpdate(List records) { + BulkUploadProcessTaskDao bulkUploadProcessTaskDao = new BulkUploadProcessTaskDaoImpl(); + try { + bulkUploadProcessTaskDao.updateBatchRecord(records); + } catch (Exception ex) { + ProjectLogger.log("Cassandra batch update failed , performing retry logic.", LoggerEnum.INFO); + for (BulkUploadProcessTask task : records) { + try { + bulkUploadProcessTaskDao.update(task); + } catch (Exception exception) { + ProjectLogger.log( + "Cassandra Update failed for BulkUploadProcessTask-" + + task.getProcessId() + + task.getSequenceId(), + exception); + } + } + } + } + + protected void validateFileHeaderFields( + Map req, String[] bulkAllowedFields, Boolean allFieldsMandatory) + throws IOException { + validateFileHeaderFields(req, bulkAllowedFields, allFieldsMandatory, false, null, null); + } + + protected void validateFileHeaderFields( + Map req, + String[] bulkAllowedFields, + Boolean allFieldsMandatory, + boolean toLower) + throws IOException { + validateFileHeaderFields(req, bulkAllowedFields, allFieldsMandatory, toLower, null, null); + } + + protected void validateFileHeaderFields( + Map req, + String[] bulkLocationAllowedFields, + Boolean allFieldsMandatory, + boolean toLower, + List mandatoryColumns, + Map supportedColumnsMap) + throws IOException { + byte[] fileByteArray = (byte[]) req.get(JsonKey.FILE); + + CSVReader csvReader = null; + Boolean flag = true; + String[] csvLine; + try { + csvReader = getCsvReader(fileByteArray, ',', '"', 0); + while (flag) { + csvLine = csvReader.readNext(); + if (csvLine == null) { + ProjectCommonException.throwClientErrorException( + ResponseCode.csvFileEmpty, ResponseCode.csvFileEmpty.getErrorMessage()); + } + if (ProjectUtil.isNotEmptyStringArray(csvLine)) { + continue; + } + csvLine = trimColumnAttributes(csvLine); + validateBulkUploadFields(csvLine, bulkLocationAllowedFields, allFieldsMandatory, toLower); + if (mandatoryColumns != null) { + validateMandatoryColumns(mandatoryColumns, csvLine, supportedColumnsMap); + } + flag = false; + } + csvLine = csvReader.readNext(); + if (csvLine == null) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorCsvNoDataRows, ResponseCode.errorCsvNoDataRows.getErrorMessage()); + } + } catch (Exception ex) { + ProjectLogger.log( + "BaseBulkUploadActor:validateFileHeaderFields: Exception = " + ex.getMessage(), ex); + throw ex; + } finally { + IOUtils.closeQuietly(csvReader); + } + } + + private void validateMandatoryColumns( + List mandatoryColumns, String[] csvLine, Map supportedColumnsMap) { + List csvColumns = new ArrayList<>(); + List csvMappedColumns = new ArrayList<>(); + Arrays.stream(csvLine) + .forEach( + x -> { + csvColumns.add(x.toLowerCase()); + csvMappedColumns.add((String) supportedColumnsMap.get(x.toLowerCase())); + }); + + mandatoryColumns.forEach( + column -> { + if (!(csvMappedColumns.contains(column))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + column); + } + }); + } + + public BulkUploadProcess handleUpload(String objectType, String createdBy) throws IOException { + String processId = ProjectUtil.getUniqueIdFromTimestamp(1); + Response response = new Response(); + response.getResult().put(JsonKey.PROCESS_ID, processId); + BulkUploadProcess bulkUploadProcess = getBulkUploadProcess(processId, objectType, createdBy, 0); + BulkUploadProcessDao bulkUploadDao = new BulkUploadProcessDaoImpl(); + Response res = bulkUploadDao.create(bulkUploadProcess); + if (((String) res.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + sender().tell(response, self()); + } else { + ProjectLogger.log( + "BaseBulkUploadActor:handleUpload: Error creating record in bulk_upload_process."); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return bulkUploadProcess; + } + + public void processBulkUpload( + int recordCount, + String processId, + BulkUploadProcess bulkUploadProcess, + String operation, + String[] allowedFields) + throws IOException { + ProjectLogger.log( + "BaseBulkUploadActor: processBulkUpload called with operation = " + operation); + BulkUploadProcessDao bulkUploadDao = new BulkUploadProcessDaoImpl(); + bulkUploadProcess.setTaskCount(recordCount); + bulkUploadDao.update(bulkUploadProcess); + + Request request = new Request(); + request.put(JsonKey.PROCESS_ID, processId); + request.put(JsonKey.FIELDS, allowedFields); + request.setOperation(operation); + + tellToAnother(request); + } + + public BulkUploadProcess getBulkUploadProcess( + String processId, String objectType, String requestedBy, Integer taskCount) { + BulkUploadProcess bulkUploadProcess = new BulkUploadProcess(); + bulkUploadProcess.setId(processId); + bulkUploadProcess.setObjectType(objectType); + bulkUploadProcess.setUploadedBy(requestedBy); + bulkUploadProcess.setUploadedDate(ProjectUtil.getFormattedDate()); + bulkUploadProcess.setCreatedBy(requestedBy); + bulkUploadProcess.setCreatedOn(new Timestamp(Calendar.getInstance().getTime().getTime())); + bulkUploadProcess.setProcessStartTime(ProjectUtil.getFormattedDate()); + bulkUploadProcess.setStatus(ProjectUtil.BulkProcessStatus.NEW.getValue()); + bulkUploadProcess.setTaskCount(taskCount); + + Map user = Util.getUserbyUserId(requestedBy); + if (user != null) { + bulkUploadProcess.setOrganisationId((String) user.get(JsonKey.ROOT_ORG_ID)); + } + + return bulkUploadProcess; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BaseBulkUploadBackgroundJobActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BaseBulkUploadBackgroundJobActor.java new file mode 100644 index 0000000000..32edcb6989 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BaseBulkUploadBackgroundJobActor.java @@ -0,0 +1,332 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.opencsv.CSVWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.Constants; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.BulkUploadJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.util.CloudStorageUtil; +import org.sunbird.common.util.CloudStorageUtil.CloudStorageType; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessDao; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessTaskDao; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessDaoImpl; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessTaskDaoImpl; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; +import org.sunbird.learner.actors.bulkupload.model.StorageDetails; + +public abstract class BaseBulkUploadBackgroundJobActor extends BaseBulkUploadActor { + + protected void setSuccessTaskStatus( + BulkUploadProcessTask task, + ProjectUtil.BulkProcessStatus status, + Map row, + String action) + throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + row.put(JsonKey.OPERATION, action); + task.setSuccessResult(mapper.writeValueAsString(row)); + task.setStatus(status.getValue()); + } + + protected void setTaskStatus( + BulkUploadProcessTask task, + ProjectUtil.BulkProcessStatus status, + String failureMessage, + Map row, + String action) + throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + row.put(JsonKey.OPERATION, action); + if (ProjectUtil.BulkProcessStatus.COMPLETED.getValue() == status.getValue()) { + task.setSuccessResult(mapper.writeValueAsString(row)); + task.setStatus(status.getValue()); + } else if (ProjectUtil.BulkProcessStatus.FAILED.getValue() == status.getValue()) { + row.put(JsonKey.ERROR_MSG, failureMessage); + task.setStatus(status.getValue()); + task.setFailureResult(mapper.writeValueAsString(row)); + } + } + + public void handleBulkUploadBackground(Request request, Function function) { + String processId = (String) request.get(JsonKey.PROCESS_ID); + BulkUploadProcessDao bulkUploadDao = new BulkUploadProcessDaoImpl(); + String logMessagePrefix = + MessageFormat.format( + "BaseBulkUploadBackGroundJobActor:handleBulkUploadBackground:{0}: ", processId); + + ProjectLogger.log(logMessagePrefix + "called", LoggerEnum.INFO); + + BulkUploadProcess bulkUploadProcess = bulkUploadDao.read(processId); + if (null == bulkUploadProcess) { + ProjectLogger.log(logMessagePrefix + "Invalid process ID.", LoggerEnum.ERROR); + return; + } + + int status = bulkUploadProcess.getStatus(); + if (!(ProjectUtil.BulkProcessStatus.COMPLETED.getValue() == status) + || ProjectUtil.BulkProcessStatus.INTERRUPT.getValue() == status) { + try { + function.apply(bulkUploadProcess); + } catch (Exception e) { + bulkUploadProcess.setStatus(ProjectUtil.BulkProcessStatus.FAILED.getValue()); + bulkUploadProcess.setFailureResult(e.getMessage()); + bulkUploadDao.update(bulkUploadProcess); + ProjectLogger.log( + logMessagePrefix + "Exception occurred with error message = " + e.getMessage(), + LoggerEnum.INFO, + e); + } + } + + bulkUploadProcess.setStatus(ProjectUtil.BulkProcessStatus.COMPLETED.getValue()); + bulkUploadDao.update(bulkUploadProcess); + } + + public void processBulkUpload( + BulkUploadProcess bulkUploadProcess, + Function function, + Map outputColumnMap, + String[] outputColumnsOrder) { + BulkUploadProcessTaskDao bulkUploadProcessTaskDao = new BulkUploadProcessTaskDaoImpl(); + String logMessagePrefix = + MessageFormat.format( + "BaseBulkUploadBackGroundJobActor:processBulkUpload:{0}: ", bulkUploadProcess.getId()); + Integer sequence = 0; + Integer taskCount = bulkUploadProcess.getTaskCount(); + List> successList = new LinkedList<>(); + List> failureList = new LinkedList<>(); + while (sequence < taskCount) { + Integer nextSequence = sequence + getBatchSize(JsonKey.CASSANDRA_WRITE_BATCH_SIZE); + Map queryMap = new HashMap<>(); + queryMap.put(JsonKey.PROCESS_ID, bulkUploadProcess.getId()); + Map sequenceRange = new HashMap<>(); + sequenceRange.put(Constants.GT, sequence); + sequenceRange.put(Constants.LTE, nextSequence); + queryMap.put(BulkUploadJsonKey.SEQUENCE_ID, sequenceRange); + List tasks = bulkUploadProcessTaskDao.readByPrimaryKeys(queryMap); + if (tasks == null) { + ProjectLogger.log( + logMessagePrefix + + "No bulkUploadProcessTask found for process id: " + + bulkUploadProcess.getId() + + " and range " + + sequence + + ":" + + nextSequence, + LoggerEnum.INFO); + sequence = nextSequence; + continue; + } + function.apply(tasks); + + try { + ObjectMapper mapper = new ObjectMapper(); + for (BulkUploadProcessTask task : tasks) { + + if (task.getStatus().equals(ProjectUtil.BulkProcessStatus.FAILED.getValue())) { + failureList.add( + mapper.readValue( + task.getFailureResult(), new TypeReference>() {})); + } else if (task.getStatus().equals(ProjectUtil.BulkProcessStatus.COMPLETED.getValue())) { + successList.add( + mapper.readValue( + task.getSuccessResult(), new TypeReference>() {})); + } + } + + } catch (IOException e) { + ProjectLogger.log( + logMessagePrefix + "Exception occurred with error message = " + e.getMessage(), + LoggerEnum.INFO, + e); + } + performBatchUpdate(tasks); + sequence = nextSequence; + } + setCompletionStatus( + bulkUploadProcess, successList, failureList, outputColumnMap, outputColumnsOrder); + } + + private void setCompletionStatus( + BulkUploadProcess bulkUploadProcess, + List successList, + List failureList, + Map outputColumnsMap, + String[] outputColumnsOrder) { + String logMessagePrefix = + MessageFormat.format( + "BaseBulkUploadBackGroundJobActor:processBulkUpload:{0}: ", bulkUploadProcess.getId()); + try { + + ProjectLogger.log(logMessagePrefix + "completed", LoggerEnum.INFO); + bulkUploadProcess.setSuccessResult(ProjectUtil.convertMapToJsonString(successList)); + bulkUploadProcess.setFailureResult(ProjectUtil.convertMapToJsonString(failureList)); + bulkUploadProcess.setStatus(ProjectUtil.BulkProcessStatus.COMPLETED.getValue()); + StorageDetails storageDetails = + uploadResultToCloud( + bulkUploadProcess, successList, failureList, outputColumnsMap, outputColumnsOrder); + if (null != storageDetails) { + bulkUploadProcess.setEncryptedStorageDetails(storageDetails); + } + } catch (Exception e) { + ProjectLogger.log( + logMessagePrefix + "Exception occurred with error message := " + e.getMessage(), + LoggerEnum.INFO, + e); + } + BulkUploadProcessDao bulkUploadDao = new BulkUploadProcessDaoImpl(); + bulkUploadDao.update(bulkUploadProcess); + } + + protected void validateMandatoryFields( + Map csvColumns, BulkUploadProcessTask task, String[] mandatoryFields) + throws JsonProcessingException { + if (mandatoryFields != null) { + for (String field : mandatoryFields) { + if (StringUtils.isEmpty((String) csvColumns.get(field))) { + String errorMessage = + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), new Object[] {field}); + + setTaskStatus( + task, ProjectUtil.BulkProcessStatus.FAILED, errorMessage, csvColumns, JsonKey.CREATE); + + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, errorMessage); + } + } + } + } + + private StorageDetails uploadResultToCloud( + BulkUploadProcess bulkUploadProcess, + List> successList, + List> failureList, + Map outputColumnsMap, + String[] outputColumnsOrder) + throws IOException { + + String objKey = generateObjectKey(bulkUploadProcess); + File file = null; + try { + file = getFileHandle(bulkUploadProcess.getObjectType(), bulkUploadProcess.getId()); + writeResultsToFile(file, successList, failureList, outputColumnsMap, outputColumnsOrder); + CloudStorageUtil.upload( + CloudStorageType.AZURE, + bulkUploadProcess.getObjectType(), + objKey, + file.getAbsolutePath()); + return new StorageDetails( + CloudStorageType.AZURE.getType(), bulkUploadProcess.getObjectType(), objKey); + } catch (Exception ex) { + ProjectLogger.log( + "Exception occurred while uploading file to cloud.:: " + ex.getMessage(), ex); + } finally { + FileUtils.deleteQuietly(file); + } + return null; + } + + private File getFileHandle(String objType, String processId) { + String logMessagePrefix = + MessageFormat.format("BaseBulkUploadBackGroundJobActor:getFileHandle:{0}: ", processId); + File file = null; + try { + file = File.createTempFile(objType, "upload"); + } catch (IOException e) { + ProjectLogger.log( + logMessagePrefix + "Exception occurred with error message = " + e.getMessage(), + LoggerEnum.INFO, + e); + } + return file; + } + + private String generateObjectKey(BulkUploadProcess bulkUploadProcess) { + String objType = bulkUploadProcess.getObjectType(); + String processId = bulkUploadProcess.getId(); + return "bulk_upload_" + objType + "_" + processId + ".csv"; + } + + private void writeResultsToFile( + File file, + List> successList, + List> failureList, + Map outputColumnsMap, + String[] outputColumnsOrder) + throws IOException { + try (CSVWriter csvWriter = new CSVWriter(new FileWriter(file)); ) { + List headerRowWithInternalNames = new ArrayList<>(Arrays.asList(outputColumnsOrder)); + + headerRowWithInternalNames.add(JsonKey.BULK_UPLOAD_STATUS); + headerRowWithInternalNames.add(JsonKey.BULK_UPLOAD_ERROR); + + if (MapUtils.isNotEmpty(outputColumnsMap)) { + List headerRowWithDisplayNames = new ArrayList<>(); + headerRowWithInternalNames.forEach( + s -> { + if (outputColumnsMap.containsKey(s)) { + headerRowWithDisplayNames.add(outputColumnsMap.get(s)); + } else { + headerRowWithDisplayNames.add(s); + } + }); + csvWriter.writeNext(headerRowWithDisplayNames.toArray(new String[0])); + } else { + csvWriter.writeNext(headerRowWithInternalNames.toArray(new String[0])); + } + + addResults(successList, headerRowWithInternalNames, csvWriter); + addResults(failureList, headerRowWithInternalNames, csvWriter); + csvWriter.flush(); + } + } + + private void addResults( + List> resultList, List headerRows, CSVWriter csvWriter) { + resultList + .stream() + .forEach( + map -> { + preProcessResult(map); + String[] nextLine = new String[headerRows.size()]; + String errMsg = (String) map.get(JsonKey.ERROR_MSG); + int i = 0; + for (String field : headerRows) { + if (JsonKey.BULK_UPLOAD_STATUS.equals(field)) { + nextLine[i++] = errMsg == null ? JsonKey.SUCCESS : JsonKey.FAILED; + } else if (JsonKey.BULK_UPLOAD_ERROR.equals(field)) { + nextLine[i++] = errMsg == null ? "" : errMsg; + } else { + nextLine[i++] = String.valueOf(map.get(field)); + } + } + csvWriter.writeNext(nextLine); + }); + } + + public abstract void preProcessResult(Map result); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BulkUploadManagementActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BulkUploadManagementActor.java new file mode 100644 index 0000000000..e0093c44b1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/BulkUploadManagementActor.java @@ -0,0 +1,457 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.*; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.BulkProcessStatus; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.util.CloudStorageUtil; +import org.sunbird.common.util.CloudStorageUtil.CloudStorageType; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessTaskDao; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessDaoImpl; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessTaskDaoImpl; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; +import org.sunbird.learner.actors.bulkupload.model.StorageDetails; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.learner.util.Util.DbInfo; + +/** This actor will handle bulk upload operation . */ +@ActorConfig( + tasks = {"bulkUpload", "getBulkOpStatus", "getBulkUploadStatusDownloadLink"}, + asyncTasks = {} +) +public class BulkUploadManagementActor extends BaseBulkUploadActor { + + private BulkUploadProcessTaskDao bulkUploadProcessTaskDao = new BulkUploadProcessTaskDaoImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + if (request.getOperation().equalsIgnoreCase(ActorOperations.BULK_UPLOAD.getValue())) { + upload(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.GET_BULK_OP_STATUS.getValue())) { + getUploadStatus(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.GET_BULK_UPLOAD_STATUS_DOWNLOAD_LINK.getValue())) { + getBulkUploadDownloadStatusLink(request); + + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void getBulkUploadDownloadStatusLink(Request actorMessage) { + String processId = (String) actorMessage.getRequest().get(JsonKey.PROCESS_ID); + BulkUploadProcessDaoImpl bulkuploadDao = new BulkUploadProcessDaoImpl(); + BulkUploadProcess bulkUploadProcess = bulkuploadDao.read(processId); + if (bulkUploadProcess != null) { + + try { + StorageDetails cloudStorageData = bulkUploadProcess.getDecryptedStorageDetails(); + if (cloudStorageData == null) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorUnavailableDownloadLink, null); + } + String signedUrl = + CloudStorageUtil.getSignedUrl( + CloudStorageType.getByName(cloudStorageData.getStorageType()), + cloudStorageData.getContainer(), + cloudStorageData.getFileName()); + Response response = new Response(); + response.setResponseCode(ResponseCode.OK); + Map resultMap = response.getResult(); + resultMap.put(JsonKey.SIGNED_URL, signedUrl); + resultMap.put(JsonKey.OBJECT_TYPE, bulkUploadProcess.getObjectType()); + resultMap.put(JsonKey.PROCESS_ID, bulkUploadProcess.getId()); + resultMap.put(JsonKey.STATUS, bulkUploadProcess.getStatus()); + updateResponseStatus(resultMap); + sender().tell(response, self()); + } catch (IOException e) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorGenerateDownloadLink, null); + } + } else { + ProjectCommonException.throwResourceNotFoundException(); + } + } + + private void getUploadStatus(Request actorMessage) { + String processId = (String) actorMessage.getRequest().get(JsonKey.PROCESS_ID); + ObjectMapper mapper = new ObjectMapper(); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getDecryptionServiceInstance(null); + Response response = null; + List fields = + Arrays.asList( + JsonKey.ID, + JsonKey.STATUS, + JsonKey.OBJECT_TYPE, + JsonKey.SUCCESS_RESULT, + JsonKey.FAILURE_RESULT); + Util.DbInfo bulkDb = Util.dbInfoMap.get(JsonKey.BULK_OP_DB); + response = + cassandraOperation.getRecordById( + bulkDb.getKeySpace(), bulkDb.getTableName(), processId, fields); + @SuppressWarnings("unchecked") + List> resList = + ((List>) response.get(JsonKey.RESPONSE)); + if (!resList.isEmpty()) { + Map resMap = resList.get(0); + String objectType = (String) resMap.get(JsonKey.OBJECT_TYPE); + if ((int) resMap.get(JsonKey.STATUS) == ProjectUtil.BulkProcessStatus.COMPLETED.getValue()) { + resMap.put(JsonKey.PROCESS_ID, resMap.get(JsonKey.ID)); + updateResponseStatus(resMap); + ProjectUtil.removeUnwantedFields(resMap, JsonKey.ID); + if (!(JsonKey.LOCATION.equalsIgnoreCase(objectType))) { + Object[] successMap = null; + Object[] failureMap = null; + try { + if (null != resMap.get(JsonKey.SUCCESS_RESULT)) { + successMap = + mapper.readValue( + decryptionService.decryptData((String) resMap.get(JsonKey.SUCCESS_RESULT)), + Object[].class); + if (JsonKey.USER.equalsIgnoreCase(objectType)) { + Arrays.stream(successMap) + .forEach( + x -> { + UserUtility.decryptUserData((Map) x); + Util.addMaskEmailAndPhone((Map) x); + }); + } + resMap.put(JsonKey.SUCCESS_RESULT, successMap); + } + if (null != resMap.get(JsonKey.FAILURE_RESULT)) { + failureMap = + mapper.readValue( + decryptionService.decryptData((String) resMap.get(JsonKey.FAILURE_RESULT)), + Object[].class); + if (JsonKey.USER.equalsIgnoreCase(objectType)) { + Arrays.stream(successMap) + .forEach( + x -> { + UserUtility.decryptUserData((Map) x); + Util.addMaskEmailAndPhone((Map) x); + }); + } + resMap.put(JsonKey.FAILURE_RESULT, failureMap); + } + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + } else { + Map queryMap = new HashMap<>(); + queryMap.put(JsonKey.PROCESS_ID, processId); + List tasks = bulkUploadProcessTaskDao.readByPrimaryKeys(queryMap); + + List successList = new ArrayList<>(); + List failureList = new ArrayList<>(); + tasks + .stream() + .forEach( + x -> { + if (x.getStatus() == BulkProcessStatus.COMPLETED.getValue()) { + addTaskDataToList(successList, x.getSuccessResult()); + } else { + addTaskDataToList(failureList, x.getFailureResult()); + } + }); + resMap.put(JsonKey.SUCCESS_RESULT, successList); + resMap.put(JsonKey.FAILURE_RESULT, failureList); + } + sender().tell(response, self()); + } else { + resMap.put(JsonKey.PROCESS_ID, resMap.get(JsonKey.ID)); + updateResponseStatus(resMap); + ProjectUtil.removeUnwantedFields( + resMap, + JsonKey.ID, + JsonKey.OBJECT_TYPE, + JsonKey.SUCCESS_RESULT, + JsonKey.FAILURE_RESULT); + sender().tell(response, self()); + } + } else { + ProjectCommonException.throwResourceNotFoundException(); + } + } + + private void updateResponseStatus(Map response) { + String status = ""; + int progressStatus = (int) response.get(JsonKey.STATUS); + if (progressStatus == ProjectUtil.BulkProcessStatus.COMPLETED.getValue()) { + status = BulkUploadJsonKey.COMPLETED; + } else if (progressStatus == ProjectUtil.BulkProcessStatus.IN_PROGRESS.getValue()) { + status = BulkUploadJsonKey.IN_PROGRESS; + } else { + status = BulkUploadJsonKey.NOT_STARTED; + } + response.put(JsonKey.STATUS, status); + response.put( + JsonKey.MESSAGE, + MessageFormat.format(BulkUploadJsonKey.OPERATION_STATUS_MSG, status.toLowerCase())); + } + + private void addTaskDataToList(List list, String data) { + try { + ObjectMapper mapper = new ObjectMapper(); + list.add(mapper.readValue(data, Map.class)); + } catch (IOException ex) { + ProjectLogger.log("Error while converting success list to map" + ex.getMessage(), ex); + } + } + + @SuppressWarnings("unchecked") + private void upload(Request actorMessage) throws IOException { + String processId = ProjectUtil.getUniqueIdFromTimestamp(1); + Map req = (Map) actorMessage.getRequest().get(JsonKey.DATA); + req.put(JsonKey.CREATED_BY, req.get(JsonKey.CREATED_BY)); + if (((String) req.get(JsonKey.OBJECT_TYPE)).equals(JsonKey.USER)) { + processBulkUserUpload(req, processId); + } else if (((String) req.get(JsonKey.OBJECT_TYPE)).equals(JsonKey.ORGANISATION)) { + processBulkOrgUpload(req, processId); + } + } + + private void processBulkOrgUpload(Map req, String processId) throws IOException { + int orgDataSize = 0; + ProjectLogger.log("BulkUploadManagementActor: processBulkOrgUpload called.", LoggerEnum.INFO); + List orgList = null; + orgList = parseCsvFile((byte[]) req.get(JsonKey.FILE), processId); + if (null != orgList) { + if (null != PropertiesCache.getInstance().getProperty(JsonKey.BULK_UPLOAD_ORG_DATA_SIZE)) { + orgDataSize = + (Integer.parseInt( + PropertiesCache.getInstance().getProperty(JsonKey.BULK_UPLOAD_ORG_DATA_SIZE))); + ProjectLogger.log("bulk upload org data size read from config file " + orgDataSize); + } + validateFileSizeAgainstLineNumbers(orgDataSize, orgList.size()); + if (!orgList.isEmpty()) { + String[] columns = orgList.get(0); + String[] bulkOrgAllowedFields = DataCacheHandler.bulkOrgAllowedFields; + validateBulkUploadFields(columns, bulkOrgAllowedFields, false); + } else { + throw new ProjectCommonException( + ResponseCode.dataSizeError.getErrorCode(), + ProjectUtil.formatMessage(ResponseCode.dataSizeError.getErrorMessage(), orgDataSize), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else { + throw new ProjectCommonException( + ResponseCode.dataSizeError.getErrorCode(), + ProjectUtil.formatMessage(ResponseCode.dataSizeError.getErrorMessage(), orgDataSize), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + // save csv file to db + uploadCsvToDB( + orgList, processId, null, JsonKey.ORGANISATION, (String) req.get(JsonKey.CREATED_BY), null); + } + + private void processBulkUserUpload(Map req, String processId) { + DbInfo orgDb = Util.dbInfoMap.get(JsonKey.ORG_DB); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + String orgId = ""; + Response response = null; + if (!StringUtils.isBlank((String) req.get(JsonKey.ORGANISATION_ID))) { + response = + cassandraOperation.getRecordById( + orgDb.getKeySpace(), orgDb.getTableName(), (String) req.get(JsonKey.ORGANISATION_ID)); + } else { + Map map = new HashMap<>(); + map.put(JsonKey.EXTERNAL_ID, ((String) req.get(JsonKey.ORG_EXTERNAL_ID)).toLowerCase()); + map.put(JsonKey.PROVIDER, ((String) req.get(JsonKey.ORG_PROVIDER)).toLowerCase()); + response = + cassandraOperation.getRecordsByProperties(orgDb.getKeySpace(), orgDb.getTableName(), map); + } + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + + if (responseList.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else { + orgId = (String) responseList.get(0).get(JsonKey.ID); + } + + String rootOrgId = ""; + Map orgMap = responseList.get(0); + boolean isRootOrg = false; + if (null != orgMap.get(JsonKey.IS_ROOT_ORG)) { + isRootOrg = (boolean) orgMap.get(JsonKey.IS_ROOT_ORG); + } else { + isRootOrg = false; + } + if (isRootOrg) { + rootOrgId = orgId; + } else { + if (!StringUtils.isBlank((String) orgMap.get(JsonKey.ROOT_ORG_ID))) { + rootOrgId = (String) orgMap.get(JsonKey.ROOT_ORG_ID); + } else { + String msg = ""; + if (StringUtils.isBlank((String) req.get(JsonKey.ORGANISATION_ID))) { + msg = + ((String) req.get(JsonKey.ORG_EXTERNAL_ID)) + + " and " + + ((String) req.get(JsonKey.ORG_PROVIDER)); + } else { + msg = (String) req.get(JsonKey.ORGANISATION_ID); + } + throw new ProjectCommonException( + ResponseCode.rootOrgAssociationError.getErrorCode(), + ProjectUtil.formatMessage(ResponseCode.rootOrgAssociationError.getErrorMessage(), msg), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + List userList = null; + try { + userList = parseCsvFile((byte[]) req.get(JsonKey.FILE), processId); + } catch (IOException e) { + throw new ProjectCommonException( + ResponseCode.csvError.getErrorCode(), + ResponseCode.csvError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + int userDataSize = 0; + if (null != userList) { + if (StringUtils.isNotBlank(ProjectUtil.getConfigValue(JsonKey.BULK_UPLOAD_USER_DATA_SIZE))) { + userDataSize = + (Integer.parseInt( + ProjectUtil.getConfigValue(JsonKey.BULK_UPLOAD_USER_DATA_SIZE).trim())); + + ProjectLogger.log( + "BulkUploadManagementActor:processBulkUserUpload : bulk upload user data size" + + userDataSize, + LoggerEnum.INFO.name()); + } + validateFileSizeAgainstLineNumbers(userDataSize, userList.size()); + String[] bulkUserAllowedFields = DataCacheHandler.bulkUserAllowedFields; + if (!userList.isEmpty()) { + String[] columns = userList.get(0); + validateBulkUploadFields(columns, bulkUserAllowedFields, false); + } else { + throw new ProjectCommonException( + ResponseCode.csvError.getErrorCode(), + ResponseCode.csvError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else { + throw new ProjectCommonException( + ResponseCode.csvError.getErrorCode(), + ResponseCode.csvError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + // save csv file to db + uploadCsvToDB( + userList, processId, orgId, JsonKey.USER, (String) req.get(JsonKey.CREATED_BY), rootOrgId); + } + + private void uploadCsvToDB( + List dataList, + String processId, + String orgId, + String objectType, + String requestedBy, + String rootOrgId) { + ProjectLogger.log("BulkUploadManagementActor: uploadCsvToDB called.", LoggerEnum.INFO); + List> dataMapList = new ArrayList<>(); + if (dataList.size() > 1) { + try { + String[] columnArr = dataList.get(0); + columnArr = trimColumnAttributes(columnArr); + Map dataMap = null; + String channel = null; + // channel is required only in case of the user type bulk upload. + if (StringUtils.isNotBlank(objectType) && objectType.equalsIgnoreCase(JsonKey.USER)) { + channel = Util.getChannel(rootOrgId); + } + for (int i = 1; i < dataList.size(); i++) { + dataMap = new HashMap<>(); + String[] valueArr = dataList.get(i); + for (int j = 0; j < valueArr.length; j++) { + String value = (valueArr[j].trim().length() == 0 ? null : valueArr[j].trim()); + dataMap.put(columnArr[j], value); + } + if (!StringUtils.isBlank(objectType) && objectType.equalsIgnoreCase(JsonKey.USER)) { + dataMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + dataMap.put(JsonKey.ORGANISATION_ID, orgId); + dataMap.put(JsonKey.CHANNEL, channel); + } + dataMapList.add(dataMap); + } + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.csvError.getErrorCode(), + ResponseCode.csvError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else { + // tell sender that csv file is empty + throw new ProjectCommonException( + ResponseCode.csvError.getErrorCode(), + ResponseCode.csvError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + // convert userMapList to json string + Map map = new HashMap<>(); + + try { + ObjectMapper mapper = new ObjectMapper(); + map.put(JsonKey.DATA, mapper.writeValueAsString(dataMapList)); + } catch (IOException e) { + ProjectLogger.log( + "BulkUploadManagementActor:uploadCsvToDB: Exception while converting map to string: " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + map.put(JsonKey.ID, processId); + map.put(JsonKey.OBJECT_TYPE, objectType); + map.put(JsonKey.UPLOADED_BY, requestedBy); + map.put(JsonKey.UPLOADED_DATE, ProjectUtil.getFormattedDate()); + map.put(JsonKey.PROCESS_START_TIME, ProjectUtil.getFormattedDate()); + map.put(JsonKey.STATUS, ProjectUtil.BulkProcessStatus.NEW.getValue()); + Util.DbInfo bulkDb = Util.dbInfoMap.get(JsonKey.BULK_OP_DB); + Response res = + cassandraOperation.insertRecord(bulkDb.getKeySpace(), bulkDb.getTableName(), map); + res.put(JsonKey.PROCESS_ID, processId); + ProjectLogger.log( + "BulkUploadManagementActor: uploadCsvToDB returned response for processId: " + processId, + LoggerEnum.INFO); + sender().tell(res, self()); + if (((String) res.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + // send processId for data processing to background job + Request request = new Request(); + request.put(JsonKey.PROCESS_ID, processId); + request.setOperation(ActorOperations.PROCESS_BULK_UPLOAD.getValue()); + tellToAnother(request); + } + ProjectLogger.log( + "BulkUploadManagementActor: uploadCsvToDB completed processing for processId: " + processId, + LoggerEnum.INFO); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadActor.java new file mode 100644 index 0000000000..03d39a12e2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadActor.java @@ -0,0 +1,76 @@ +package org.sunbird.learner.actors.bulkupload; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.util.BulkUploadActorOperation; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.util.Util; + +/** + * Class to provide the location bulk upload functionality. + * + * @author arvind. + */ +@ActorConfig( + tasks = {"locationBulkUpload"}, + asyncTasks = {} +) +public class LocationBulkUploadActor extends BaseBulkUploadActor { + + String[] bulkLocationAllowedFields = { + GeoLocationJsonKey.CODE, + JsonKey.NAME, + GeoLocationJsonKey.PARENT_CODE, + GeoLocationJsonKey.PARENT_ID + }; + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.GEO_LOCATION); + String operation = request.getOperation(); + + switch (operation) { + case "locationBulkUpload": + upload(request); + break; + default: + onReceiveUnsupportedOperation("LocationBulkUploadActor"); + } + } + + private void upload(Request request) throws IOException { + Map req = (Map) request.getRequest().get(JsonKey.DATA); + validateFileHeaderFields(req, bulkLocationAllowedFields, true); + BulkUploadProcess bulkUploadProcess = + handleUpload(JsonKey.LOCATION, (String) req.get(JsonKey.CREATED_BY)); + String locationType = (String) req.get(GeoLocationJsonKey.LOCATION_TYPE); + processLocationBulkUpload(req, bulkUploadProcess.getId(), locationType, bulkUploadProcess); + } + + private void processLocationBulkUpload( + Map req, + String processId, + String locationType, + BulkUploadProcess bulkUploadProcess) + throws IOException { + byte[] fileByteArray = null; + if (null != req.get(JsonKey.FILE)) { + fileByteArray = (byte[]) req.get(JsonKey.FILE); + } + Map additionalRowFields = new HashMap<>(); + additionalRowFields.put(GeoLocationJsonKey.LOCATION_TYPE, locationType); + Integer recordCount = validateAndParseRecords(fileByteArray, processId, additionalRowFields); + processBulkUpload( + recordCount, + processId, + bulkUploadProcess, + BulkUploadActorOperation.LOCATION_BULK_UPLOAD_BACKGROUND_JOB.getValue(), + bulkLocationAllowedFields); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadBackGroundJobActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadBackGroundJobActor.java new file mode 100644 index 0000000000..c0153cbcfc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadBackGroundJobActor.java @@ -0,0 +1,208 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.sql.Timestamp; +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.location.LocationClient; +import org.sunbird.actorutil.location.impl.LocationClientImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.BulkProcessStatus; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; +import org.sunbird.learner.util.Util; +import org.sunbird.models.location.Location; +import org.sunbird.models.location.apirequest.UpsertLocationRequest; + +@ActorConfig( + tasks = {}, + asyncTasks = {"locationBulkUploadBackground"} +) +public class LocationBulkUploadBackGroundJobActor extends BaseBulkUploadBackgroundJobActor { + + private LocationClient locationClient = new LocationClientImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + + String operation = request.getOperation(); + Util.initializeContext(request, TelemetryEnvKey.GEO_LOCATION); + + switch (operation) { + case "locationBulkUploadBackground": + handleBulkUploadBackground( + request, + (bulkUploadProcess) -> { + processBulkUpload( + (BulkUploadProcess) bulkUploadProcess, + (tasks) -> { + processTasks((List) tasks); + return null; + }, + null, + (String[]) request.get(JsonKey.FIELDS)); + return null; + }); + break; + default: + ProjectLogger.log(operation + ": unsupported message"); + } + } + + private void processLocation(BulkUploadProcessTask task) { + ObjectMapper mapper = new ObjectMapper(); + ProjectLogger.log( + "LocationBulkUploadBackGroundJobActor: processLocation called", LoggerEnum.INFO); + String data = task.getData(); + try { + + Map row = mapper.readValue(data, Map.class); + + if (checkMandatoryFields(row, GeoLocationJsonKey.CODE)) { + Location location = null; + try { + location = + locationClient.getLocationByCode( + getActorRef(LocationActorOperation.SEARCH_LOCATION.getValue()), + (String) row.get(GeoLocationJsonKey.CODE)); + } catch (Exception ex) { + setTaskStatus(task, BulkProcessStatus.FAILED, ex.getMessage(), row, null); + } + if (null == location) { + callCreateLocation(row, task); + } else { + callUpdateLocation(row, mapper.convertValue(location, Map.class), task); + } + } else { + setTaskStatus( + task, + BulkProcessStatus.FAILED, + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), GeoLocationJsonKey.CODE), + row, + null); + } + } catch (IOException e) { + ProjectCommonException.throwClientErrorException( + ResponseCode.SERVER_ERROR, ResponseCode.SERVER_ERROR.getErrorMessage()); + } + } + + private boolean checkMandatoryFields(Map row, String... fields) { + + boolean flag = true; + for (String field : fields) { + if (!(row.containsKey(field))) { + flag = false; + break; + } + } + return flag; + } + + private void callUpdateLocation( + Map row, Map response, BulkUploadProcessTask task) + throws JsonProcessingException { + + String id = (String) response.get(JsonKey.ID); + row.put(JsonKey.ID, id); + + // since for update type is not allowed so remove from request body + String locationType = (String) row.remove(GeoLocationJsonKey.LOCATION_TYPE); + // check whether update for same type or different type. + if (!(areLocationTypesEqual( + locationType, (String) response.get(GeoLocationJsonKey.LOCATION_TYPE)))) { + row.put(GeoLocationJsonKey.LOCATION_TYPE, response.get(GeoLocationJsonKey.LOCATION_TYPE)); + setTaskStatus( + task, + BulkProcessStatus.FAILED, + MessageFormat.format( + ResponseCode.unupdatableField.getErrorMessage(), GeoLocationJsonKey.LOCATION_TYPE), + row, + JsonKey.UPDATE); + return; + } + ObjectMapper mapper = new ObjectMapper(); + try { + locationClient.updateLocation( + getActorRef(LocationActorOperation.UPDATE_LOCATION.getValue()), + mapper.convertValue(row, UpsertLocationRequest.class)); + } catch (Exception ex) { + ProjectLogger.log( + "LocationBulkUploadBackGroundJobActor : callUpdateLocation - got exception " + + ex.getMessage(), + LoggerEnum.INFO); + row.put(JsonKey.ERROR_MSG, ex.getMessage()); + setTaskStatus(task, BulkProcessStatus.FAILED, ex.getMessage(), row, JsonKey.UPDATE); + } + + row.put(GeoLocationJsonKey.LOCATION_TYPE, locationType); + task.setData(mapper.writeValueAsString(row)); + setSuccessTaskStatus(task, BulkProcessStatus.COMPLETED, row, JsonKey.UPDATE); + } + + private Boolean areLocationTypesEqual(String locationType, String responseType) { + return (locationType.equalsIgnoreCase(responseType)); + } + + private void callCreateLocation(Map row, BulkUploadProcessTask task) + throws JsonProcessingException { + + Request request = new Request(); + request.getRequest().putAll(row); + ObjectMapper mapper = new ObjectMapper(); + String locationId = ""; + try { + locationId = + locationClient.createLocation( + getActorRef(LocationActorOperation.CREATE_LOCATION.getValue()), + mapper.convertValue(row, UpsertLocationRequest.class)); + } catch (Exception ex) { + ProjectLogger.log( + "LocationBulkUploadBackGroundJobActor : callCreateLocation - got exception " + + ex.getMessage(), + LoggerEnum.INFO); + setTaskStatus(task, BulkProcessStatus.FAILED, ex.getMessage(), row, JsonKey.CREATE); + return; + } + + if (StringUtils.isEmpty(locationId)) { + ProjectLogger.log( + "LocationBulkUploadBackGroundJobActor : Null receive from interservice communication", + LoggerEnum.ERROR); + setTaskStatus( + task, + BulkProcessStatus.FAILED, + ResponseCode.internalError.getErrorMessage(), + row, + JsonKey.CREATE); + } else { + row.put(JsonKey.ID, locationId); + setSuccessTaskStatus(task, BulkProcessStatus.COMPLETED, row, JsonKey.CREATE); + } + } + + private void processTasks(List tasks) { + for (BulkUploadProcessTask task : tasks) { + if (task.getStatus() != null + && task.getStatus() != ProjectUtil.BulkProcessStatus.COMPLETED.getValue()) { + processLocation(task); + task.setLastUpdatedOn(new Timestamp(System.currentTimeMillis())); + task.setIterationId(task.getIterationId() + 1); + } + } + } + + @Override + public void preProcessResult(Map result) { + // Do nothing + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/OrgBulkUploadActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/OrgBulkUploadActor.java new file mode 100644 index 0000000000..02aa183c32 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/OrgBulkUploadActor.java @@ -0,0 +1,161 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessDao; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessDaoImpl; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {"orgBulkUpload"}, + asyncTasks = {} +) +public class OrgBulkUploadActor extends BaseBulkUploadActor { + + private SystemSettingClient systemSettingClient = new SystemSettingClientImpl(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.ORGANISATION); + String operation = request.getOperation(); + + if (operation.equalsIgnoreCase("orgBulkUpload")) { + upload(request); + } else { + onReceiveUnsupportedOperation("OrgBulkUploadActor"); + } + } + + private void upload(Request request) throws IOException { + Map req = (Map) request.getRequest().get(JsonKey.DATA); + Object dataObject = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "orgProfileConfig", + "csv", + new TypeReference() {}); + Map supportedColumnsMap = null; + Map supportedColumnsLowerCaseMap = null; + if (dataObject != null) { + supportedColumnsMap = + ((Map) ((Map) dataObject).get("supportedColumns")); + List supportedColumnsList = new ArrayList<>(); + supportedColumnsLowerCaseMap = + supportedColumnsMap + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> (entry.getKey()).toLowerCase(), entry -> entry.getValue())); + Map internalNamesLowerCaseMap = new HashMap<>(); + supportedColumnsMap.forEach( + (String k, Object v) -> { + internalNamesLowerCaseMap.put(v.toString().toLowerCase(), v.toString()); + }); + supportedColumnsLowerCaseMap.putAll(internalNamesLowerCaseMap); + supportedColumnsLowerCaseMap.forEach( + (key, value) -> { + supportedColumnsList.add(key); + supportedColumnsList.add((String) value); + }); + List mandatoryColumns = + (List) (((Map) dataObject).get("mandatoryColumns")); + validateFileHeaderFields( + req, + supportedColumnsList.toArray(new String[supportedColumnsList.size()]), + false, + true, + mandatoryColumns, + supportedColumnsLowerCaseMap); + } else { + validateFileHeaderFields(req, DataCacheHandler.bulkOrgAllowedFields, false, false); + } + BulkUploadProcess bulkUploadProcess = + handleUpload(JsonKey.ORGANISATION, (String) req.get(JsonKey.CREATED_BY)); + processOrgBulkUpload( + req, bulkUploadProcess.getId(), bulkUploadProcess, supportedColumnsLowerCaseMap); + } + + private void processOrgBulkUpload( + Map req, + String processId, + BulkUploadProcess bulkUploadProcess, + Map supportedColumnsMap) + throws IOException { + byte[] fileByteArray = null; + if (null != req.get(JsonKey.FILE)) { + fileByteArray = (byte[]) req.get(JsonKey.FILE); + } + HashMap additionalInfo = new HashMap<>(); + Map user = getUser((String) req.get(JsonKey.CREATED_BY)); + if (user != null) { + String rootOrgId = (String) user.get(JsonKey.ROOT_ORG_ID); + Map org = getOrg(rootOrgId); + if (org != null) { + if (org.get(JsonKey.STATUS) == null + || (int) org.get(JsonKey.STATUS) == ProjectUtil.OrgStatus.ACTIVE.getValue()) { + additionalInfo.put(JsonKey.CHANNEL, org.get(JsonKey.CHANNEL)); + } + } + } + if (!additionalInfo.containsKey(JsonKey.CHANNEL)) { + bulkUploadProcess.setStatus(ProjectUtil.BulkProcessStatus.FAILED.getValue()); + bulkUploadProcess.setFailureResult(ResponseCode.errorNoRootOrgAssociated.getErrorMessage()); + BulkUploadProcessDao bulkUploadDao = new BulkUploadProcessDaoImpl(); + bulkUploadDao.update(bulkUploadProcess); + ProjectCommonException.throwClientErrorException( + ResponseCode.errorNoRootOrgAssociated, + ResponseCode.errorNoRootOrgAssociated.getErrorMessage()); + } + Integer recordCount = + validateAndParseRecords( + fileByteArray, processId, additionalInfo, supportedColumnsMap, true); + processBulkUpload( + recordCount, + processId, + bulkUploadProcess, + BulkUploadActorOperation.ORG_BULK_UPLOAD_BACKGROUND_JOB.getValue(), + DataCacheHandler.bulkOrgAllowedFields); + } + + Map getUser(String userId) { + Future> resultF = + esService.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (result != null || result.size() > 0) { + return result; + } + return null; + } + + Map getOrg(String orgId) { + Future> resultF = + esService.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), orgId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (result != null && result.size() > 0) { + return result; + } + return null; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/OrgBulkUploadBackgroundJobActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/OrgBulkUploadBackgroundJobActor.java new file mode 100644 index 0000000000..1395579dd7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/OrgBulkUploadBackgroundJobActor.java @@ -0,0 +1,253 @@ +package org.sunbird.learner.actors.bulkupload; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.location.LocationClient; +import org.sunbird.actorutil.location.impl.LocationClientImpl; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.actorutil.org.impl.OrganisationClientImpl; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; +import org.sunbird.learner.util.Util; +import org.sunbird.models.location.Location; +import org.sunbird.models.organisation.Organisation; + +@ActorConfig( + tasks = {}, + asyncTasks = {"orgBulkUploadBackground"} +) +public class OrgBulkUploadBackgroundJobActor extends BaseBulkUploadBackgroundJobActor { + + private OrganisationClient orgClient = new OrganisationClientImpl(); + private SystemSettingClient systemSettingClient = new SystemSettingClientImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + Util.initializeContext(request, TelemetryEnvKey.ORGANISATION); + if (operation.equalsIgnoreCase("orgBulkUploadBackground")) { + Map outputColumns = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "orgProfileConfig", + "csv.outputColumns", + new TypeReference>() {}); + + String[] outputColumnsOrder = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "orgProfileConfig", + "csv.outputColumnsOrder", + new TypeReference() {}); + + handleBulkUploadBackground( + request, + (baseBulkUpload) -> { + processBulkUpload( + (BulkUploadProcess) baseBulkUpload, + (tasks) -> { + processTasks((List) tasks); + return null; + }, + outputColumns, + outputColumnsOrder != null + ? outputColumnsOrder + : (String[]) request.get(JsonKey.FIELDS)); + return null; + }); + } else { + onReceiveUnsupportedOperation("OrgBulkUploadBackgroundJobActor"); + } + } + + private void processTasks(List bulkUploadProcessTasks) { + Map locationCache = new HashMap<>(); + LocationClient locationClient = new LocationClientImpl(); + ActorRef locationActor = getActorRef(LocationActorOperation.SEARCH_LOCATION.getValue()); + for (BulkUploadProcessTask task : bulkUploadProcessTasks) { + if (task.getStatus() != null + && task.getStatus() != ProjectUtil.BulkProcessStatus.COMPLETED.getValue()) { + processOrg(task, locationClient, locationCache, locationActor); + task.setLastUpdatedOn(new Timestamp(System.currentTimeMillis())); + task.setIterationId(task.getIterationId() + 1); + } + } + } + + private void processOrg( + BulkUploadProcessTask task, + LocationClient locationClient, + Map locationCache, + ActorRef locationActor) { + ProjectLogger.log("OrgBulkUploadBackgroundJobActor: processOrg called", LoggerEnum.INFO); + String data = task.getData(); + ObjectMapper mapper = new ObjectMapper(); + try { + Map orgMap = mapper.readValue(data, Map.class); + Object mandatoryColumnsObject = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "orgProfileConfig", + "csv.mandatoryColumns", + new TypeReference() {}); + if (mandatoryColumnsObject != null) { + validateMandatoryFields(orgMap, task, (String[]) mandatoryColumnsObject); + } + int status = getOrgStatus(orgMap); + if (status == -1) { + orgMap.put(JsonKey.ERROR_MSG, ResponseCode.invalidOrgStatus.getErrorMessage()); + task.setFailureResult(mapper.writeValueAsString(orgMap)); + task.setStatus(ProjectUtil.BulkProcessStatus.FAILED.getValue()); + return; + } + + List locationCodes = new ArrayList<>(); + if (orgMap.get(JsonKey.LOCATION_CODE) instanceof String) { + locationCodes.add((String) orgMap.get(JsonKey.LOCATION_CODE)); + } else { + locationCodes = (List) orgMap.get(JsonKey.LOCATION_CODE); + } + + Organisation organisation = mapper.convertValue(orgMap, Organisation.class); + organisation.setStatus(status); + organisation.setId((String) orgMap.get(JsonKey.ORGANISATION_ID)); + + if (StringUtils.isEmpty(organisation.getId())) { + callCreateOrg(organisation, task, locationCodes); + } else { + callUpdateOrg(organisation, task, locationCodes); + } + setLocationInformation(task, locationClient, locationCache, locationActor, locationCodes); + } catch (Exception e) { + ProjectLogger.log( + "OrgBulkUploadBackgroundJobActor:callCreateOrg: Exception occurred with error message = " + + e.getMessage(), + LoggerEnum.INFO); + } + } + + private void setLocationInformation( + BulkUploadProcessTask task, + LocationClient locationClient, + Map locationCache, + ActorRef locationActor, + List locationCodes) + throws IOException, JsonParseException, JsonMappingException { + ObjectMapper mapper = new ObjectMapper(); + if (ProjectUtil.BulkProcessStatus.COMPLETED.getValue() == task.getStatus()) { + List locationNames = new ArrayList<>(); + for (String locationCode : locationCodes) { + if (locationCache.containsKey(locationCode)) { + locationNames.add(locationCache.get(locationCode).getName()); + } else { + Location location = locationClient.getLocationByCode(locationActor, locationCode); + locationNames.add(location.getName()); + } + } + Map row = mapper.readValue(task.getSuccessResult(), Map.class); + if (locationNames.size() == 1) { + row.put(JsonKey.LOCATION_NAME, locationNames.get(0)); + row.put(JsonKey.LOCATION_CODE, locationCodes.get(0)); + } else { + row.put(JsonKey.LOCATION_NAME, locationNames); + row.put(JsonKey.LOCATION_CODE, locationCodes); + } + task.setSuccessResult(mapper.writeValueAsString(row)); + } + } + + private int getOrgStatus(Map orgMap) { + int status = ProjectUtil.OrgStatus.ACTIVE.getValue(); + if (!StringUtils.isEmpty((String) orgMap.get(JsonKey.STATUS))) { + if (((String) orgMap.get(JsonKey.STATUS)).equalsIgnoreCase(JsonKey.INACTIVE)) { + status = ProjectUtil.OrgStatus.INACTIVE.getValue(); + } else if (((String) orgMap.get(JsonKey.STATUS)).equalsIgnoreCase(JsonKey.ACTIVE)) { + status = ProjectUtil.OrgStatus.ACTIVE.getValue(); + } else { + return -1; + } + orgMap.remove(JsonKey.STATUS); + } + return status; + } + + private void callCreateOrg( + Organisation org, BulkUploadProcessTask task, List locationCodes) + throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + Map row = mapper.convertValue(org, Map.class); + row.put(JsonKey.LOCATION_CODE, locationCodes); + String orgId; + try { + orgId = orgClient.createOrg(getActorRef(ActorOperations.CREATE_ORG.getValue()), row); + } catch (Exception ex) { + ProjectLogger.log( + "OrgBulkUploadBackgroundJobActor:callCreateOrg: Exception occurred with error message = " + + ex.getMessage(), + LoggerEnum.INFO); + setTaskStatus( + task, ProjectUtil.BulkProcessStatus.FAILED, ex.getMessage(), row, JsonKey.CREATE); + return; + } + + if (StringUtils.isEmpty(orgId)) { + ProjectLogger.log( + "OrgBulkUploadBackgroundJobActor:callCreateOrg: Org ID is null !", LoggerEnum.ERROR); + setTaskStatus( + task, + ProjectUtil.BulkProcessStatus.FAILED, + ResponseCode.internalError.getErrorMessage(), + row, + JsonKey.CREATE); + } else { + row.put(JsonKey.ORGANISATION_ID, orgId); + setSuccessTaskStatus(task, ProjectUtil.BulkProcessStatus.COMPLETED, row, JsonKey.CREATE); + } + } + + private void callUpdateOrg( + Organisation org, BulkUploadProcessTask task, List locationCodes) + throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + Map row = mapper.convertValue(org, Map.class); + row.put(JsonKey.LOCATION_CODE, locationCodes); + try { + row.put(JsonKey.ORGANISATION_ID, org.getId()); + orgClient.updateOrg(getActorRef(ActorOperations.UPDATE_ORG.getValue()), row); + } catch (Exception ex) { + ProjectLogger.log( + "OrgBulkUploadBackgroundJobActor:callUpdateOrg: Exception occurred with error message = " + + ex.getMessage(), + LoggerEnum.INFO); + row.put(JsonKey.ERROR_MSG, ex.getMessage()); + setTaskStatus( + task, ProjectUtil.BulkProcessStatus.FAILED, ex.getMessage(), row, JsonKey.UPDATE); + } + if (task.getStatus() != ProjectUtil.BulkProcessStatus.FAILED.getValue()) { + task.setData(mapper.writeValueAsString(row)); + setSuccessTaskStatus(task, ProjectUtil.BulkProcessStatus.COMPLETED, row, JsonKey.UPDATE); + } + } + + @Override + public void preProcessResult(Map result) { + // Do nothing + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkMigrationActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkMigrationActor.java new file mode 100644 index 0000000000..a442e16189 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkMigrationActor.java @@ -0,0 +1,438 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Iterables; +import com.mchange.v1.util.ArrayUtils; +import com.opencsv.CSVReader; +import java.io.IOException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.bean.MigrationUser; +import org.sunbird.bean.ShadowUserUpload; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.bulkupload.model.BulkMigrationUser; +import org.sunbird.learner.util.Util; +import org.sunbird.models.systemsetting.SystemSetting; +import org.sunbird.telemetry.util.TelemetryUtil; + +/** @author anmolgupta */ +@ActorConfig( + tasks = {"userBulkMigration"}, + asyncTasks = {} +) +public class UserBulkMigrationActor extends BaseBulkUploadActor { + + private SystemSettingClient systemSettingClient = new SystemSettingClientImpl(); + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + public static final int RETRY_COUNT = 2; + private CSVReader csvReader; + private static SystemSetting systemSetting; + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, "ShadowUserUpload"); + String operation = request.getOperation(); + if (operation.equalsIgnoreCase(BulkUploadActorOperation.USER_BULK_MIGRATION.getValue())) { + uploadCsv(request); + } else { + onReceiveUnsupportedOperation("userBulkMigration"); + } + } + + private void uploadCsv(Request request) throws IOException { + Map req = (Map) request.getRequest().get(JsonKey.DATA); + systemSetting = + systemSettingClient.getSystemSettingByField( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), "shadowdbmandatorycolumn"); + processCsvBytes(req, request); + } + + private void processCsvBytes(Map data, Request request) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + Map values = mapper.readValue(systemSetting.getValue(), Map.class); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + String processId = ProjectUtil.getUniqueIdFromTimestamp(1); + long validationStartTime = System.currentTimeMillis(); + String userId = getCreatedBy(request); + Map result = getUserById(userId); + String channel = getChannel(result); + String rootOrgId = getRootOrgId(result); + List migrationUserList = + getMigrationUsers(channel, processId, (byte[]) data.get(JsonKey.FILE), values); + ProjectLogger.log( + "UserBulkMigrationActor:processRecord: time taken to validate records of size " + .concat(migrationUserList.size() + "") + + "is(ms): ".concat((System.currentTimeMillis() - validationStartTime) + ""), + LoggerEnum.INFO.name()); + request.getRequest().put(JsonKey.ROOT_ORG_ID, rootOrgId); + BulkMigrationUser migrationUser = prepareRecord(request, processId, migrationUserList); + ProjectLogger.log( + "UserBulkMigrationActor:processRecord:processing record for number of users " + .concat(migrationUserList.size() + ""), + LoggerEnum.INFO.name()); + insertRecord(migrationUser); + TelemetryUtil.generateCorrelatedObject(processId, JsonKey.PROCESS_ID, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject( + migrationUser.getTaskCount() + "", JsonKey.TASK_COUNT, null, correlatedObject); + targetObject = + TelemetryUtil.generateTargetObject( + processId, + StringUtils.capitalize(JsonKey.MIGRATION_USER_OBJECT), + "ShadowUserUpload", + null); + TelemetryUtil.telemetryProcessingCall( + mapper.convertValue(migrationUser, Map.class), + targetObject, + correlatedObject, + request.getContext()); + } + + private void insertRecord(BulkMigrationUser bulkMigrationUser) { + long insertStartTime = System.currentTimeMillis(); + ObjectMapper mapper = new ObjectMapper(); + ProjectLogger.log( + "UserBulkMigrationActor:insertRecord:record started inserting with " + .concat(bulkMigrationUser.getId() + ""), + LoggerEnum.INFO.name()); + Map record = mapper.convertValue(bulkMigrationUser, Map.class); + long createdOn = System.currentTimeMillis(); + record.put(JsonKey.CREATED_ON, new Timestamp(createdOn)); + record.put(JsonKey.LAST_UPDATED_ON, new Timestamp(createdOn)); + Util.DbInfo dbInfo = Util.dbInfoMap.get(JsonKey.BULK_OP_DB); + Response response = + cassandraOperation.insertRecord(dbInfo.getKeySpace(), dbInfo.getTableName(), record); + response.put(JsonKey.PROCESS_ID, bulkMigrationUser.getId()); + ProjectLogger.log( + "UserBulkMigrationActor:insertRecord:time taken by cassandra to insert record of size " + .concat(record.size() + "") + + "is(ms):".concat((System.currentTimeMillis() - insertStartTime) + "")); + sender().tell(response, self()); + } + + private BulkMigrationUser prepareRecord( + Request request, String processID, List migrationUserList) { + try { + ObjectMapper mapper = new ObjectMapper(); + String decryptedData = mapper.writeValueAsString(migrationUserList); + BulkMigrationUser migrationUser = + new BulkMigrationUser.BulkMigrationUserBuilder(processID, decryptedData) + .setObjectType(JsonKey.MIGRATION_USER_OBJECT) + .setUploadedDate(ProjectUtil.getFormattedDate()) + .setStatus(ProjectUtil.BulkProcessStatus.NEW.getValue()) + .setRetryCount(RETRY_COUNT) + .setTaskCount(migrationUserList.size()) + .setCreatedBy(getCreatedBy(request)) + .setUploadedBy(getCreatedBy(request)) + .setOrganisationId((String) request.getRequest().get(JsonKey.ROOT_ORG_ID)) + .setTelemetryContext(getContextMap(processID, request)) + .build(); + return migrationUser; + } catch (Exception e) { + e.printStackTrace(); + ProjectLogger.log( + "UserBulkMigrationActor:prepareRecord:error occurred while getting preparing record with processId" + .concat(processID + ""), + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + private Map getContextMap(String processId, Request request) { + Map contextMap = (Map) request.getContext(); + ProjectLogger.log( + "UserBulkMigrationActor:getContextMap:started preparing record for processId:" + + processId + + "with request context:" + + contextMap, + LoggerEnum.INFO.name()); + contextMap.put(JsonKey.ACTOR_TYPE, StringUtils.capitalize(JsonKey.SYSTEM)); + contextMap.put(JsonKey.ACTOR_ID, ProjectUtil.getUniqueIdFromTimestamp(0)); + Iterables.removeIf(contextMap.values(), value -> StringUtils.isBlank(value)); + return contextMap; + } + + private String getCreatedBy(Request request) { + Map data = (Map) request.getRequest().get(JsonKey.DATA); + return MapUtils.isNotEmpty(data) ? data.get(JsonKey.CREATED_BY) : null; + } + + private List getMigrationUsers( + String channel, String processId, byte[] fileData, Map fieldsMap) { + Map> columnsMap = + (Map>) fieldsMap.get(JsonKey.FILE_TYPE_CSV); + List csvData = readCsv(fileData); + List csvHeaders = getCsvHeadersAsList(csvData); + List mandatoryHeaders = columnsMap.get(JsonKey.MANDATORY_FIELDS); + List supportedHeaders = columnsMap.get(JsonKey.SUPPORTED_COlUMNS); + mandatoryHeaders.replaceAll(String::toLowerCase); + supportedHeaders.replaceAll(String::toLowerCase); + checkCsvHeader(csvHeaders, mandatoryHeaders, supportedHeaders); + List mappedCsvHeaders = mapCsvColumn(csvHeaders); + List migrationUserList = + parseCsvRows(channel, getCsvRowsAsList(csvData), mappedCsvHeaders); + ShadowUserUpload migration = + new ShadowUserUpload.ShadowUserUploadBuilder() + .setHeaders(csvHeaders) + .setMappedHeaders(mappedCsvHeaders) + .setProcessId(processId) + .setFileData(fileData) + .setFileSize(fileData.length + "") + .setMandatoryFields(columnsMap.get(JsonKey.MANDATORY_FIELDS)) + .setSupportedFields(columnsMap.get(JsonKey.SUPPORTED_COlUMNS)) + .setValues(migrationUserList) + .validate(); + ProjectLogger.log( + "UserBulkMigrationActor:validateRequestAndReturnMigrationUsers: the migration object formed " + .concat(migration.toString()), + LoggerEnum.INFO.name()); + return migrationUserList; + } + + private List readCsv(byte[] fileData) { + List values = new ArrayList<>(); + try { + csvReader = getCsvReader(fileData, ',', '"', 0); + ProjectLogger.log( + "UserBulkMigrationActor:readCsv:csvReader initialized ".concat(csvReader.toString()), + LoggerEnum.INFO.name()); + values = csvReader.readAll(); + } catch (Exception ex) { + ProjectLogger.log( + "UserBulkMigrationActor:readCsv:error occurred while getting csvReader", + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } finally { + IOUtils.closeQuietly(csvReader); + } + return values; + } + + private List getCsvHeadersAsList(List csvData) { + List headers = new ArrayList<>(); + int CSV_COLUMN_NAMES = 0; + if (null == csvData || csvData.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.blankCsvData.getErrorCode(), + ResponseCode.blankCsvData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + headers.addAll(Arrays.asList(csvData.get(CSV_COLUMN_NAMES))); + headers.replaceAll(String::toLowerCase); + return headers; + } + + private List getCsvRowsAsList(List csvData) { + return csvData.subList(1, csvData.size()); + } + + private List mapCsvColumn(List csvColumns) { + List mappedColumns = new ArrayList<>(); + csvColumns.forEach( + column -> { + if (column.equalsIgnoreCase(JsonKey.EMAIL)) { + mappedColumns.add(column); + } + if (column.equalsIgnoreCase(JsonKey.PHONE)) { + mappedColumns.add(column); + } + if (column.equalsIgnoreCase(JsonKey.EXTERNAL_USER_ID)) { + mappedColumns.add(JsonKey.USER_EXTERNAL_ID); + } + if (column.equalsIgnoreCase(JsonKey.EXTERNAL_ORG_ID)) { + mappedColumns.add(JsonKey.ORG_EXTERNAL_ID); + } + if (column.equalsIgnoreCase(JsonKey.NAME)) { + mappedColumns.add(JsonKey.FIRST_NAME); + } + if (column.equalsIgnoreCase(JsonKey.INPUT_STATUS)) { + mappedColumns.add(column); + } + }); + return mappedColumns; + } + + private List parseCsvRows( + String channel, List values, List mappedHeaders) { + List migrationUserList = new ArrayList<>(); + values + .stream() + .forEach( + row -> { + int index = values.indexOf(row); + MigrationUser migrationUser = new MigrationUser(); + for (int i = 0; i < row.length; i++) { + if (row.length > mappedHeaders.size()) { + throw new ProjectCommonException( + ResponseCode.errorUnsupportedField.getErrorCode(), + ResponseCode.errorUnsupportedField.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + "Invalid provided ROW:" + (index + 1)); + } + String columnName = getColumnNameByIndex(mappedHeaders, i); + setFieldToMigrationUserObject(migrationUser, columnName, trimValue(row[i])); + } + // channel to be added here + migrationUser.setChannel(channel); + migrationUserList.add(migrationUser); + }); + return migrationUserList; + } + + private String trimValue(String value) { + if (StringUtils.isNotBlank(value)) { + return value.trim(); + } + return value; + } + + private void setFieldToMigrationUserObject( + MigrationUser migrationUser, String columnAttribute, Object value) { + + if (columnAttribute.equalsIgnoreCase(JsonKey.EMAIL)) { + String email = (String) value; + migrationUser.setEmail(email); + } + if (columnAttribute.equalsIgnoreCase(JsonKey.PHONE)) { + String phone = (String) value; + migrationUser.setPhone(phone); + } + if (columnAttribute.equalsIgnoreCase(JsonKey.ORG_EXTERNAL_ID)) { + migrationUser.setOrgExternalId((String) value); + } + if (columnAttribute.equalsIgnoreCase(JsonKey.USER_EXTERNAL_ID)) { + migrationUser.setUserExternalId((String) value); + } + + if (columnAttribute.equalsIgnoreCase(JsonKey.FIRST_NAME)) { + migrationUser.setName(StringUtils.trim((String) value)); + } + if (columnAttribute.equalsIgnoreCase(JsonKey.INPUT_STATUS)) { + migrationUser.setInputStatus((String) value); + } + } + + private String getColumnNameByIndex(List mappedHeaders, int index) { + return mappedHeaders.get(index); + } + + /** + * in bulk_upload_process db user will have channel of admin users + * + * @param result + * @return channel + */ + private String getChannel(Map result) { + String channel = (String) result.get(JsonKey.CHANNEL); + ProjectLogger.log( + "UserBulkMigrationActor:getChannel: the channel of admin user ".concat(channel + ""), + LoggerEnum.INFO.name()); + return channel; + } + /** + * in bulk_upload_process db organisationId will be of user. + * + * @param result + * @return rootOrgId + */ + private String getRootOrgId(Map result) { + String rootOrgId = (String) result.get(JsonKey.ROOT_ORG_ID); + ProjectLogger.log( + "UserBulkMigrationActor:getRootOrgId:the root org id of admin user " + .concat(rootOrgId + ""), + LoggerEnum.INFO.name()); + return rootOrgId; + } + + /** + * this method will fetch user record with userId from cassandra + * + * @param userId + * @return result + */ + private Map getUserById(String userId) { + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response response = + cassandraOperation.getRecordById(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userId); + if (((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Map result = ((Map) ((List) response.getResult().get(JsonKey.RESPONSE)).get(0)); + return result; + } + + private void checkCsvHeader( + List csvHeaders, List mandatoryHeaders, List supportedHeaders) { + checkMandatoryColumns(csvHeaders, mandatoryHeaders); + checkSupportedColumns(csvHeaders, supportedHeaders); + } + + private void checkMandatoryColumns(List csvHeaders, List mandatoryHeaders) { + ProjectLogger.log( + "UserBulkMigrationRequestValidator:checkMandatoryColumns:mandatory columns got " + + mandatoryHeaders, + LoggerEnum.INFO.name()); + mandatoryHeaders.forEach( + column -> { + if (!csvHeaders.contains(column)) { + ProjectLogger.log( + "UserBulkMigrationRequestValidator:mandatoryColumns: mandatory column is not present" + .concat(column + ""), + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + column); + } + }); + } + + private void checkSupportedColumns(List csvHeaders, List supportedHeaders) { + ProjectLogger.log( + "UserBulkMigrationRequestValidator:checkSupportedColumns:mandatory columns got " + + supportedHeaders, + LoggerEnum.INFO.name()); + csvHeaders.forEach( + suppColumn -> { + if (!supportedHeaders.contains(suppColumn)) { + ProjectLogger.log( + "UserBulkMigrationRequestValidator:supportedColumns: supported column is not present" + .concat(suppColumn + ""), + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.errorUnsupportedField.getErrorCode(), + ResponseCode.errorUnsupportedField.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + "Invalid provided column:" + .concat(suppColumn) + .concat(":supported headers are:") + .concat(ArrayUtils.stringifyContents(supportedHeaders.toArray()))); + } + }); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkUploadActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkUploadActor.java new file mode 100644 index 0000000000..fce86d4f00 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkUploadActor.java @@ -0,0 +1,113 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.BulkUploadActorOperation; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; + +@ActorConfig( + tasks = {"userBulkUpload"}, + asyncTasks = {} +) +public class UserBulkUploadActor extends BaseBulkUploadActor { + + private SystemSettingClient systemSettingClient = new SystemSettingClientImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + if (operation.equalsIgnoreCase("userBulkUpload")) { + upload(request); + } else { + onReceiveUnsupportedOperation("UserBulkUploadActor"); + } + } + + @SuppressWarnings("unchecked") + private void upload(Request request) throws IOException { + Map req = (Map) request.getRequest().get(JsonKey.DATA); + Object dataObject = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "userProfileConfig", + "csv", + new TypeReference() {}); + Map supportedColumnsMap = null; + Map supportedColumnsLowerCaseMap = null; + if (dataObject != null) { + supportedColumnsMap = + ((Map) ((Map) dataObject).get("supportedColumns")); + List supportedColumnsList = new ArrayList<>(); + supportedColumnsLowerCaseMap = + supportedColumnsMap + .entrySet() + .stream() + .collect( + Collectors.toMap( + entry -> (entry.getKey()).toLowerCase(), entry -> entry.getValue())); + + Map internalNamesLowerCaseMap = new HashMap<>(); + supportedColumnsMap.forEach( + (String k, Object v) -> { + internalNamesLowerCaseMap.put(v.toString().toLowerCase(), v.toString()); + }); + supportedColumnsLowerCaseMap.putAll(internalNamesLowerCaseMap); + supportedColumnsLowerCaseMap.forEach( + (key, value) -> { + supportedColumnsList.add(key); + supportedColumnsList.add((String) value); + }); + List mandatoryColumns = + (List) (((Map) dataObject).get("mandatoryColumns")); + validateFileHeaderFields( + req, + supportedColumnsList.toArray(new String[supportedColumnsList.size()]), + false, + true, + mandatoryColumns, + supportedColumnsLowerCaseMap); + + } else { + validateFileHeaderFields(req, DataCacheHandler.bulkUserAllowedFields, false); + } + BulkUploadProcess bulkUploadProcess = + handleUpload(JsonKey.USER, (String) req.get(JsonKey.CREATED_BY)); + processUserBulkUpload( + req, bulkUploadProcess.getId(), bulkUploadProcess, supportedColumnsLowerCaseMap); + } + + private void processUserBulkUpload( + Map req, + String processId, + BulkUploadProcess bulkUploadProcess, + Map supportedColumnsMap) + throws IOException { + byte[] fileByteArray = null; + if (null != req.get(JsonKey.FILE)) { + fileByteArray = (byte[]) req.get(JsonKey.FILE); + } + Integer recordCount = + validateAndParseRecords(fileByteArray, processId, new HashMap(), supportedColumnsMap, true); + processBulkUpload( + recordCount, + processId, + bulkUploadProcess, + BulkUploadActorOperation.USER_BULK_UPLOAD_BACKGROUND_JOB.getValue(), + DataCacheHandler.bulkUserAllowedFields); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkUploadBackgroundJobActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkUploadBackgroundJobActor.java new file mode 100644 index 0000000000..bb6595b3d9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/UserBulkUploadBackgroundJobActor.java @@ -0,0 +1,302 @@ +package org.sunbird.learner.actors.bulkupload; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.sql.Timestamp; +import java.text.MessageFormat; +import java.util.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.actorutil.org.impl.OrganisationClientImpl; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.actorutil.user.UserClient; +import org.sunbird.actorutil.user.impl.UserClientImpl; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; +import org.sunbird.learner.actors.role.service.RoleService; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.models.organisation.Organisation; +import org.sunbird.validator.user.UserBulkUploadRequestValidator; + +@ActorConfig( + tasks = {}, + asyncTasks = {"userBulkUploadBackground"} +) +public class UserBulkUploadBackgroundJobActor extends BaseBulkUploadBackgroundJobActor { + + private UserClient userClient = new UserClientImpl(); + private OrganisationClient organisationClient = new OrganisationClientImpl(); + private SystemSettingClient systemSettingClient = new SystemSettingClientImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + Util.initializeContext(request, TelemetryEnvKey.USER); + if (operation.equalsIgnoreCase("userBulkUploadBackground")) { + + Map outputColumns = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "userProfileConfig", + "csv.outputColumns", + new TypeReference() {}); + + String[] outputColumnsOrder = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "userProfileConfig", + "csv.outputColumnsOrder", + new TypeReference() {}); + + handleBulkUploadBackground( + request, + (baseBulkUpload) -> { + processBulkUpload( + (BulkUploadProcess) baseBulkUpload, + (tasks) -> { + processTasks( + (List) tasks, ((BulkUploadProcess) baseBulkUpload)); + return null; + }, + outputColumns, + outputColumnsOrder != null + ? outputColumnsOrder + : (String[]) request.get(JsonKey.FIELDS)); + return null; + }); + } else { + onReceiveUnsupportedOperation("UserBulkUploadBackgroundJobActor"); + } + } + + private void processTasks( + List bulkUploadProcessTasks, BulkUploadProcess bulkUploadProcess) { + for (BulkUploadProcessTask task : bulkUploadProcessTasks) { + try { + if (task.getStatus() != null + && task.getStatus() != ProjectUtil.BulkProcessStatus.COMPLETED.getValue()) { + processUser( + task, bulkUploadProcess.getOrganisationId(), bulkUploadProcess.getUploadedBy()); + task.setLastUpdatedOn(new Timestamp(System.currentTimeMillis())); + task.setIterationId(task.getIterationId() + 1); + } + } catch (Exception ex) { + ProjectLogger.log("Error in processTasks", ex); + task.setStatus(ProjectUtil.BulkProcessStatus.FAILED.getValue()); + } + } + } + + @SuppressWarnings("unchecked") + private void processUser(BulkUploadProcessTask task, String organisationId, String uploadedBy) { + ProjectLogger.log("UserBulkUploadBackgroundJobActor: processUser called", LoggerEnum.INFO); + String data = task.getData(); + Organisation organisation = null; + try { + ObjectMapper mapper = new ObjectMapper(); + Map userMap = mapper.readValue(data, Map.class); + String[] mandatoryColumnsObject = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + "userProfileConfig", + "csv.mandatoryColumns", + new TypeReference() {}); + if (mandatoryColumnsObject != null) { + validateMandatoryFields(userMap, task, mandatoryColumnsObject); + } + if (userMap.get(JsonKey.PHONE) != null) { + userMap.put(JsonKey.PHONE_VERIFIED, true); + } + try { + String roles = (String) userMap.get(JsonKey.ROLES); + if (roles != null) { + String[] roleArray = roles.split(","); + List roleList = new ArrayList<>(); + Arrays.stream(roleArray) + .forEach( + x -> { + roleList.add(x.trim()); + }); + userMap.put(JsonKey.ROLES, roleList); + RoleService.validateRoles((List) userMap.get(JsonKey.ROLES)); + } + UserBulkUploadRequestValidator.validateUserBulkUploadRequest(userMap); + } catch (Exception ex) { + setTaskStatus( + task, ProjectUtil.BulkProcessStatus.FAILED, ex.getMessage(), userMap, JsonKey.CREATE); + return; + } + String orgId = (String) userMap.get(JsonKey.ORG_ID); + String orgExternalId = (String) userMap.get(JsonKey.ORG_EXTERNAL_ID); + HashMap uploaderMap = new HashMap<>(); + uploaderMap.put(JsonKey.ORG_ID, organisationId); + Organisation uploaderOrg = getOrgDetails(uploaderMap); + if (StringUtils.isNotBlank(orgId) || StringUtils.isNotBlank(orgExternalId)) { + organisation = getOrgDetails(userMap); + if (null == organisation) { + setTaskStatus( + task, + ProjectUtil.BulkProcessStatus.FAILED, + ResponseCode.invalidOrgId.getErrorMessage(), + userMap, + JsonKey.CREATE); + return; + } else { + if (StringUtils.isNotBlank(orgId) + && StringUtils.isNotBlank(orgExternalId) + && !(orgId).equalsIgnoreCase(organisation.getId())) { + + String message = + MessageFormat.format( + ResponseCode.errorConflictingValues.getErrorMessage(), + JsonKey.ORGANISATION_ID, + orgId, + JsonKey.ORG_EXTERNAL_ID, + orgExternalId); + setTaskStatus( + task, ProjectUtil.BulkProcessStatus.FAILED, message, userMap, JsonKey.CREATE); + return; + + } else { + if (StringUtils.isNotBlank(orgExternalId)) { + userMap.put(JsonKey.ORGANISATION_ID, organisation.getId()); + } else { + userMap.put(JsonKey.ORGANISATION_ID, orgId); + } + } + } + } + if (null != organisation + && (!(organisation.getRootOrgId()).equalsIgnoreCase(organisationId)) + && (!(organisation.getRootOrgId()).equalsIgnoreCase(uploaderOrg.getRootOrgId()))) { + setTaskStatus( + task, + ProjectUtil.BulkProcessStatus.FAILED, + ResponseCode.errorConflictingRootOrgId.getErrorMessage(), + userMap, + JsonKey.CREATE); + return; + } + + if (organisation != null + && !ProjectUtil.OrgStatus.ACTIVE.getValue().equals(organisation.getStatus())) { + setTaskStatus( + task, + ProjectUtil.BulkProcessStatus.FAILED, + ResponseCode.invalidOrgStatus.getErrorMessage(), + userMap, + JsonKey.CREATE); + return; + } + + String orgName = ""; + if (null != organisation) { + orgName = organisation.getOrgName(); + } + + if (StringUtils.isNotEmpty((String) userMap.get(JsonKey.PHONE))) { + userMap.put(JsonKey.PHONE_VERIFIED, true); + } + if (StringUtils.isNotEmpty((String) userMap.get(JsonKey.EMAIL))) { + userMap.put(JsonKey.EMAIL_VERIFIED, true); + } + String userId = (String) userMap.get(JsonKey.USER_ID); + if (StringUtils.isEmpty(userId)) { + userMap.put(JsonKey.CREATED_BY, uploadedBy); + userMap.put(JsonKey.ROOT_ORG_ID, organisationId); + callCreateUser(userMap, task, orgName); + } else { + userMap.put(JsonKey.UPDATED_BY, uploadedBy); + callUpdateUser(userMap, task, orgName); + } + } catch (Exception e) { + ProjectLogger.log("Error in process user", data, e); + task.setStatus(ProjectUtil.BulkProcessStatus.FAILED.getValue()); + } + } + + @SuppressWarnings("unchecked") + private void callCreateUser(Map user, BulkUploadProcessTask task, String orgName) + throws JsonProcessingException { + ProjectLogger.log("UserBulkUploadBackgroundJobActor: callCreateUser called", LoggerEnum.INFO); + String userId; + try { + userId = userClient.createUser(getActorRef(ActorOperations.CREATE_USER.getValue()), user); + } catch (Exception ex) { + ProjectLogger.log( + "UserBulkUploadBackgroundJobActor:callCreateUser: Exception occurred with error message = " + + ex.getMessage(), + LoggerEnum.INFO); + setTaskStatus( + task, ProjectUtil.BulkProcessStatus.FAILED, ex.getMessage(), user, JsonKey.CREATE); + return; + } + + if (StringUtils.isEmpty(userId)) { + ProjectLogger.log( + "UserBulkUploadBackgroundJobActor:callCreateUser: User ID is null !", LoggerEnum.ERROR); + setTaskStatus( + task, + ProjectUtil.BulkProcessStatus.FAILED, + ResponseCode.internalError.getErrorMessage(), + user, + JsonKey.CREATE); + } else { + user.put(JsonKey.ID, userId); + user.put(JsonKey.ORG_NAME, orgName); + setSuccessTaskStatus(task, ProjectUtil.BulkProcessStatus.COMPLETED, user, JsonKey.CREATE); + } + } + + @SuppressWarnings("unchecked") + private void callUpdateUser(Map user, BulkUploadProcessTask task, String orgName) + throws JsonProcessingException { + ProjectLogger.log("UserBulkUploadBackgroundJobActor: callUpdateUser called", LoggerEnum.INFO); + try { + user.put(JsonKey.ORG_NAME, orgName); + userClient.updateUser(getActorRef(ActorOperations.UPDATE_USER.getValue()), user); + } catch (Exception ex) { + ProjectLogger.log( + "UserBulkUploadBackgroundJobActor:callUpdateUser: Exception occurred with error message = " + + ex.getMessage(), + LoggerEnum.INFO); + user.put(JsonKey.ERROR_MSG, ex.getMessage()); + setTaskStatus( + task, ProjectUtil.BulkProcessStatus.FAILED, ex.getMessage(), user, JsonKey.UPDATE); + } + if (task.getStatus() != ProjectUtil.BulkProcessStatus.FAILED.getValue()) { + ObjectMapper mapper = new ObjectMapper(); + task.setData(mapper.writeValueAsString(user)); + setSuccessTaskStatus(task, ProjectUtil.BulkProcessStatus.COMPLETED, user, JsonKey.UPDATE); + } + } + + private Organisation getOrgDetails(Map userMap) { + if (StringUtils.isNotBlank((String) userMap.get(JsonKey.ORG_EXTERNAL_ID))) { + Map filters = new HashMap<>(); + filters.put( + JsonKey.EXTERNAL_ID, ((String) userMap.get(JsonKey.ORG_EXTERNAL_ID)).toLowerCase()); + if (CollectionUtils.isNotEmpty(organisationClient.esSearchOrgByFilter(filters))) { + return organisationClient.esSearchOrgByFilter(filters).get(0); + } + return null; + } else if (StringUtils.isNotBlank((String) userMap.get(JsonKey.ORG_ID))) { + return organisationClient.esGetOrgById((String) userMap.get(JsonKey.ORG_ID)); + } + return null; + } + + @Override + public void preProcessResult(Map result) { + UserUtility.decryptUserData(result); + Util.addMaskEmailAndPhone(result); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/BulkUploadProcessDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/BulkUploadProcessDao.java new file mode 100644 index 0000000000..22ddd509da --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/BulkUploadProcessDao.java @@ -0,0 +1,26 @@ +package org.sunbird.learner.actors.bulkupload.dao; + +import org.sunbird.common.models.response.Response; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; + +/** Created by arvind on 24/4/18. */ +public interface BulkUploadProcessDao { + + /** + * @param bulkUploadProcess + * @return response Response + */ + Response create(BulkUploadProcess bulkUploadProcess); + + /** + * @param bulkUploadProcess + * @return response Response + */ + Response update(BulkUploadProcess bulkUploadProcess); + + /** + * @param id + * @return response Response + */ + BulkUploadProcess read(String id); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/BulkUploadProcessTaskDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/BulkUploadProcessTaskDao.java new file mode 100644 index 0000000000..16c7fc513c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/BulkUploadProcessTaskDao.java @@ -0,0 +1,67 @@ +package org.sunbird.learner.actors.bulkupload.dao; + +import java.util.List; +import java.util.Map; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; + +/** + * Class to provide Data access operation for the bulk_upload_process_task table. + * + * @author arvind. + */ +public interface BulkUploadProcessTaskDao { + + /** + * Method to insert individual record of bulk upload file as bulk upload process task entry in + * database. + * + * @param bulkUploadProcessTasks Pojo representing the table. + * @return String success if record inserted successfully. Response string got from underlying + * database implementation layer. + */ + String create(BulkUploadProcessTask bulkUploadProcessTasks); + + /** + * Method to update bulk upload process task entry in database. + * + * @param bulkUploadProcessTasks Pojo representing the table. + * @return String success if record inserted successfully. Response string got from underlying + * database implementation layer. + */ + String update(BulkUploadProcessTask bulkUploadProcessTasks); + + /** + * Method to read the record from database on basis of primary key represented by Pojo. + * + * @param BulkUploadProcessTask Pojo representing the table. + * @return BulkUploadProcessTask + */ + BulkUploadProcessTask read(BulkUploadProcessTask BulkUploadProcessTask); + + /** + * Method to read from database on basis of primary key.Here map represents the primary + * keys(composite key). + * + * @param compositeKey Composite key. + * @return List of records. + */ + List readByPrimaryKeys(Map compositeKey); + + /** + * Method to perform the batch insert. + * + * @param records List of records to be insert into database. + * @return String success if record inserted successfully. Response string got from underlying + * database implementation layer. + */ + String insertBatchRecord(List records); + + /** + * Method to perform the batch update. + * + * @param records List of records to be update into database. + * @return String success if record inserted successfully. Response string got from underlying + * database implementation layer. + */ + String updateBatchRecord(List records); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/impl/BulkUploadProcessDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/impl/BulkUploadProcessDaoImpl.java new file mode 100644 index 0000000000..8179e96a0a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/impl/BulkUploadProcessDaoImpl.java @@ -0,0 +1,61 @@ +package org.sunbird.learner.actors.bulkupload.dao.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessDao; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcess; + +/** Created by arvind on 24/4/18. */ +public class BulkUploadProcessDaoImpl implements BulkUploadProcessDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ObjectMapper mapper = new ObjectMapper(); + private static final String KEYSPACE_NAME = "sunbird"; + private static final String TABLE_NAME = "bulk_upload_process"; + + @Override + public Response create(BulkUploadProcess bulkUploadProcess) { + Map map = mapper.convertValue(bulkUploadProcess, Map.class); + map.put(JsonKey.CREATED_ON, new Timestamp(Calendar.getInstance().getTimeInMillis())); + Response response = cassandraOperation.insertRecord(KEYSPACE_NAME, TABLE_NAME, map); + // need to send ID along with success msg + response.put(JsonKey.ID, map.get(JsonKey.ID)); + return response; + } + + @Override + public Response update(BulkUploadProcess bulkUploadProcess) { + Map map = mapper.convertValue(bulkUploadProcess, Map.class); + if (map.containsKey(JsonKey.CREATED_ON)) { + map.remove(JsonKey.CREATED_ON); + } + map.put(JsonKey.LAST_UPDATED_ON, new Timestamp(Calendar.getInstance().getTimeInMillis())); + return cassandraOperation.updateRecord(KEYSPACE_NAME, TABLE_NAME, map); + } + + @Override + public BulkUploadProcess read(String id) { + Response response = cassandraOperation.getRecordById(KEYSPACE_NAME, TABLE_NAME, id); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(list)) { + return null; + } + try { + String jsonString = mapper.writeValueAsString((Map) list.get(0)); + return mapper.readValue(jsonString, BulkUploadProcess.class); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + return null; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/impl/BulkUploadProcessTaskDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/impl/BulkUploadProcessTaskDaoImpl.java new file mode 100644 index 0000000000..fbd24f6628 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/dao/impl/BulkUploadProcessTaskDaoImpl.java @@ -0,0 +1,99 @@ +package org.sunbird.learner.actors.bulkupload.dao.impl; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +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.models.util.ProjectLogger; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.bulkupload.dao.BulkUploadProcessTaskDao; +import org.sunbird.learner.actors.bulkupload.model.BulkUploadProcessTask; + +/** + * Data access implementation for BulkUploadProcessTask entity. + * + * @author arvind + */ +public class BulkUploadProcessTaskDaoImpl implements BulkUploadProcessTaskDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ObjectMapper mapper = new ObjectMapper(); + private static final String KEYSPACE_NAME = "sunbird"; + private static final String TABLE_NAME = "bulk_upload_process_task"; + + @Override + public String create(BulkUploadProcessTask bulkUploadProcessTask) { + Map map = mapper.convertValue(bulkUploadProcessTask, Map.class); + cassandraOperation.insertRecord(KEYSPACE_NAME, TABLE_NAME, map); + return JsonKey.SUCCESS; + } + + @Override + public String update(BulkUploadProcessTask bulkUploadProcessTask) { + Map> map = CassandraUtil.batchUpdateQuery(bulkUploadProcessTask); + Response response = + cassandraOperation.updateRecord( + KEYSPACE_NAME, + TABLE_NAME, + map.get(JsonKey.NON_PRIMARY_KEY), + map.get(JsonKey.PRIMARY_KEY)); + return (String) response.get(JsonKey.RESPONSE); + } + + @Override + public BulkUploadProcessTask read(BulkUploadProcessTask bulkUploadProcessTask) { + Response response = + cassandraOperation.getRecordById( + KEYSPACE_NAME, TABLE_NAME, CassandraUtil.getPrimaryKey(bulkUploadProcessTask)); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(list)) { + return null; + } + try { + String jsonString = mapper.writeValueAsString((Map) list.get(0)); + return mapper.readValue(jsonString, BulkUploadProcessTask.class); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + return null; + } + + @Override + public List readByPrimaryKeys(Map id) { + Response response = cassandraOperation.getRecordById(KEYSPACE_NAME, TABLE_NAME, id); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(list)) { + return null; + } + TypeReference> mapType = + new TypeReference>() {}; + List taskList = mapper.convertValue(list, mapType); + return taskList; + } + + @Override + public String insertBatchRecord(List records) { + TypeReference>> tRef = + new TypeReference>>() {}; + List> list = mapper.convertValue(records, tRef); + Response response = cassandraOperation.batchInsert(KEYSPACE_NAME, TABLE_NAME, list); + return (String) response.get(JsonKey.RESPONSE); + } + + @Override + public String updateBatchRecord(List records) { + List>> list = new ArrayList<>(); + for (BulkUploadProcessTask bulkUploadProcessTask : records) { + list.add(CassandraUtil.batchUpdateQuery(bulkUploadProcessTask)); + } + Response response = cassandraOperation.batchUpdate(KEYSPACE_NAME, TABLE_NAME, list); + return (String) response.get(JsonKey.RESPONSE); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkMigrationUser.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkMigrationUser.java new file mode 100644 index 0000000000..1dee629152 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkMigrationUser.java @@ -0,0 +1,265 @@ +package org.sunbird.learner.actors.bulkupload.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import java.sql.Timestamp; +import java.util.Map; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author anmolgupta */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BulkMigrationUser { + private static final long serialVersionUID = 1L; + private String id; + private String data; + private String failureResult; + private String objectType; + private String organisationId; + private String processEndTime; + private String processStartTime; + private Integer retryCount; + private Integer status; + private String successResult; + private String uploadedBy; + private String uploadedDate; + private Integer taskCount; + private String createdBy; + private Timestamp createdOn; + private Timestamp lastUpdatedOn; + private String storageDetails; + private Map telemetryContext; + + public BulkMigrationUser(BulkMigrationUserBuilder builder) { + this.id = builder.id; + this.data = builder.data; + this.failureResult = builder.failureResult; + this.objectType = builder.objectType; + this.organisationId = builder.organisationId; + this.processEndTime = builder.processEndTime; + this.processStartTime = builder.processStartTime; + this.retryCount = builder.retryCount; + this.status = builder.status; + this.successResult = builder.successResult; + this.uploadedBy = builder.uploadedBy; + this.uploadedDate = builder.uploadedDate; + this.taskCount = builder.taskCount; + this.createdBy = builder.createdBy; + this.createdOn = builder.createdOn; + this.lastUpdatedOn = builder.lastUpdatedOn; + this.storageDetails = builder.storageDetails; + this.telemetryContext = builder.telemetryContext; + } + + public BulkMigrationUser() {} + + public String getId() { + return id; + } + + public String getData() { + return data; + } + + public String getFailureResult() { + return failureResult; + } + + public String getObjectType() { + return objectType; + } + + public String getOrganisationId() { + return organisationId; + } + + public String getProcessEndTime() { + return processEndTime; + } + + public String getProcessStartTime() { + return processStartTime; + } + + public Integer getRetryCount() { + return retryCount; + } + + public Integer getStatus() { + return status; + } + + public String getSuccessResult() { + return successResult; + } + + public String getUploadedBy() { + return uploadedBy; + } + + public String getUploadedDate() { + return uploadedDate; + } + + public Integer getTaskCount() { + return taskCount; + } + + public String getCreatedBy() { + return createdBy; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public Timestamp getLastUpdatedOn() { + return lastUpdatedOn; + } + + public String getStorageDetails() { + return storageDetails; + } + + public Map getTelemetryContext() { + return telemetryContext; + } + + public static class BulkMigrationUserBuilder { + private EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null); + private String id; + private String data; + private String failureResult; + private String objectType; + private String organisationId; + private String processEndTime; + private String processStartTime; + private Integer retryCount; + private Integer status; + private String successResult; + private String uploadedBy; + private String uploadedDate; + private Integer taskCount; + private String createdBy; + private Timestamp createdOn; + private Timestamp lastUpdatedOn; + private String storageDetails; + private Map telemetryContext; + + public BulkMigrationUserBuilder setTelemetryContext(Map telemetryContext) { + this.telemetryContext = telemetryContext; + return this; + } + + public BulkMigrationUserBuilder(String id, String data) { + this.id = id; + this.data = encryptData(data); + } + + public BulkMigrationUserBuilder setFailureResult(String failureResult) { + this.failureResult = failureResult; + return this; + } + + public BulkMigrationUserBuilder setObjectType(String objectType) { + this.objectType = objectType; + return this; + } + + public BulkMigrationUserBuilder setOrganisationId(String organisationId) { + this.organisationId = organisationId; + return this; + } + + public BulkMigrationUserBuilder setProcessEndTime(String processEndTime) { + this.processEndTime = processEndTime; + return this; + } + + public BulkMigrationUserBuilder setProcessStartTime(String processStartTime) { + this.processStartTime = processStartTime; + return this; + } + + public BulkMigrationUserBuilder setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + return this; + } + + public BulkMigrationUserBuilder setStatus(Integer status) { + this.status = status; + return this; + } + + public BulkMigrationUserBuilder setSuccessResult(String successResult) { + this.successResult = successResult; + return this; + } + + public BulkMigrationUserBuilder setUploadedBy(String uploadedBy) { + this.uploadedBy = uploadedBy; + return this; + } + + public BulkMigrationUserBuilder setUploadedDate(String uploadedDate) { + this.uploadedDate = uploadedDate; + return this; + } + + public BulkMigrationUserBuilder setTaskCount(Integer taskCount) { + this.taskCount = taskCount; + return this; + } + + public BulkMigrationUserBuilder setCreatedBy(String createdBy) { + this.createdBy = createdBy; + return this; + } + + public BulkMigrationUserBuilder setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + return this; + } + + public BulkMigrationUserBuilder setLastUpdatedOn(Timestamp lastUpdatedOn) { + this.lastUpdatedOn = lastUpdatedOn; + return this; + } + + public BulkMigrationUserBuilder setStorageDetails(String storageDetails) { + this.storageDetails = storageDetails; + return this; + } + + private String encryptData(String decryptedData) { + long encStartTime = System.currentTimeMillis(); + try { + String encryptedData = encryptionService.encryptData(decryptedData); + ProjectLogger.log( + "BulkMigrationUser:encryptData:TIME TAKEN TO ENCRYPT DATA in(ms):" + .concat((System.currentTimeMillis() - encStartTime) + ""), + LoggerEnum.INFO.name()); + return encryptedData; + } catch (Exception e) { + ProjectLogger.log( + "BulkMigrationUser:encryptData:error occurred while encrypting data", + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.userDataEncryptionError.getResponseCode()); + } + } + + public BulkMigrationUser build() { + BulkMigrationUser migrationUser = new BulkMigrationUser(this); + return migrationUser; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkUploadProcess.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkUploadProcess.java new file mode 100644 index 0000000000..4bb1860d0e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkUploadProcess.java @@ -0,0 +1,207 @@ +package org.sunbird.learner.actors.bulkupload.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.Serializable; +import java.sql.Timestamp; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author arvind. */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class BulkUploadProcess implements Serializable { + + private static final long serialVersionUID = 1L; + private EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + private DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + + private String id; + private String data; + private String failureResult; + private String objectType; + private String organisationId; + private String processEndTime; + private String processStartTime; + private Integer retryCount; + private Integer status; + private String successResult; + private String uploadedBy; + private String uploadedDate; + private Integer taskCount; + private String createdBy; + private Timestamp createdOn; + private Timestamp lastUpdatedOn; + private String storageDetails; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getFailureResult() { + return failureResult; + } + + public void setFailureResult(String failureResult) { + this.failureResult = failureResult; + } + + public String getObjectType() { + return objectType; + } + + public void setObjectType(String objectType) { + this.objectType = objectType; + } + + public String getOrganisationId() { + return organisationId; + } + + public void setOrganisationId(String organisationId) { + this.organisationId = organisationId; + } + + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getSuccessResult() { + return successResult; + } + + public void setSuccessResult(String successResult) { + this.successResult = successResult; + } + + public String getUploadedBy() { + return uploadedBy; + } + + public void setUploadedBy(String uploadedBy) { + this.uploadedBy = uploadedBy; + } + + public String getUploadedDate() { + return uploadedDate; + } + + public void setUploadedDate(String uploadedDate) { + this.uploadedDate = uploadedDate; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } + + public Timestamp getLastUpdatedOn() { + return lastUpdatedOn; + } + + public void setLastUpdatedOn(Timestamp lastUpdatedOn) { + this.lastUpdatedOn = lastUpdatedOn; + } + + public String getProcessEndTime() { + return processEndTime; + } + + public void setProcessEndTime(String processEndTime) { + this.processEndTime = processEndTime; + } + + public String getProcessStartTime() { + return processStartTime; + } + + public void setProcessStartTime(String processStartTime) { + this.processStartTime = processStartTime; + } + + public Integer getTaskCount() { + return taskCount; + } + + public void setTaskCount(Integer taskCount) { + this.taskCount = taskCount; + } + + public String getStorageDetails() { + return this.storageDetails; + } + + public void setStorageDetails(String storageDetails) { + this.storageDetails = storageDetails; + } + + @JsonIgnore + public void setEncryptedStorageDetails(StorageDetails cloudStorageData) { + try { + setStorageDetails(encryptionService.encryptData(cloudStorageData.toJsonString())); + } catch (Exception e) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorSavingStorageDetails, null); + } + } + + @JsonIgnore + public StorageDetails getDecryptedStorageDetails() + throws JsonParseException, JsonMappingException, IOException { + String rawData = getStorageDetails(); + if (rawData != null) { + ObjectMapper mapper = new ObjectMapper(); + String decryptedData = decryptionService.decryptData(getStorageDetails()); + return mapper.readValue(decryptedData, StorageDetails.class); + } else { + return null; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkUploadProcessTask.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkUploadProcessTask.java new file mode 100644 index 0000000000..b127576209 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/BulkUploadProcessTask.java @@ -0,0 +1,104 @@ +package org.sunbird.learner.actors.bulkupload.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import java.io.Serializable; +import java.sql.Timestamp; +import org.sunbird.cassandraannotation.ClusteringKey; +import org.sunbird.cassandraannotation.PartitioningKey; + +/** + * Model class to represent the bulk_upload_process_tasks column family. + * + * @author arvind. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class BulkUploadProcessTask implements Serializable { + + private static final long serialVersionUID = 1L; + + @PartitioningKey() private String processId; + @ClusteringKey() private Integer sequenceId; + + private String data; + private String failureResult; + private String successResult; + private Timestamp createdOn; + private Timestamp lastUpdatedOn; + private Integer iterationId = new Integer(0); + private Integer status; + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getFailureResult() { + return failureResult; + } + + public void setFailureResult(String failureResult) { + this.failureResult = failureResult; + } + + public String getProcessId() { + return processId; + } + + public void setProcessId(String processId) { + this.processId = processId; + } + + public String getSuccessResult() { + return successResult; + } + + public void setSuccessResult(String successResult) { + this.successResult = successResult; + } + + public Integer getIterationId() { + return iterationId; + } + + public void setIterationId(Integer iterationId) { + this.iterationId = iterationId; + } + + public Integer getSequenceId() { + return sequenceId; + } + + public void setSequenceId(Integer sequenceId) { + this.sequenceId = sequenceId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } + + public Timestamp getLastUpdatedOn() { + return lastUpdatedOn; + } + + public void setLastUpdatedOn(Timestamp lastUpdatedOn) { + this.lastUpdatedOn = lastUpdatedOn; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/StorageDetails.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/StorageDetails.java new file mode 100644 index 0000000000..a823adab09 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/bulkupload/model/StorageDetails.java @@ -0,0 +1,48 @@ +package org.sunbird.learner.actors.bulkupload.model; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class StorageDetails { + + private String storageType; + private String container; + private String fileName; + + public StorageDetails(String storageType, String container, String fileName) { + super(); + this.storageType = storageType; + this.container = container; + this.fileName = fileName; + } + + public StorageDetails() {} + + public String getStorageType() { + return storageType; + } + + public void setStorageType(String storageType) { + this.storageType = storageType; + } + + public String getContainer() { + return container; + } + + public void setContainer(String container) { + this.container = container; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String toJsonString() throws JsonProcessingException { + return new ObjectMapper().writeValueAsString(this); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/client/ClientManagementActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/client/ClientManagementActor.java new file mode 100644 index 0000000000..f77a9666f8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/client/ClientManagementActor.java @@ -0,0 +1,274 @@ +package org.sunbird.learner.actors.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.telemetry.util.TelemetryUtil; + +@ActorConfig( + tasks = {"registerClient", "updateClientKey", "getClientKey"}, + asyncTasks = {} +) +public class ClientManagementActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.MASTER_KEY); + + if (request.getOperation().equalsIgnoreCase(ActorOperations.REGISTER_CLIENT.getValue())) { + registerClient(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.UPDATE_CLIENT_KEY.getValue())) { + updateClientKey(request); + } else if (request.getOperation().equalsIgnoreCase(ActorOperations.GET_CLIENT_KEY.getValue())) { + getClientKey(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + /** + * Method to register client + * + * @param actorMessage + */ + @SuppressWarnings("unchecked") + private void registerClient(Request actorMessage) { + ProjectLogger.log("Register client method call start"); + String clientName = (String) actorMessage.getRequest().get(JsonKey.CLIENT_NAME); + + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + Response data = getDataFromCassandra(JsonKey.CLIENT_NAME, clientName); + List> dataList = + (List>) data.getResult().get(JsonKey.RESPONSE); + if (!dataList.isEmpty() && dataList.get(0).containsKey(JsonKey.ID)) { + throw new ProjectCommonException( + ResponseCode.invalidClientName.getErrorCode(), + ResponseCode.invalidClientName.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + // check uniqueness of channel , channel is optional ... + String channel = (String) actorMessage.getRequest().get(JsonKey.CHANNEL); + if (!StringUtils.isBlank(channel)) { + data = getDataFromCassandra(JsonKey.CHANNEL, channel); + dataList = (List>) data.getResult().get(JsonKey.RESPONSE); + if (!dataList.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.channelUniquenessInvalid.getErrorCode(), + ResponseCode.channelUniquenessInvalid.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + Map req = new HashMap<>(); + String uniqueId = ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv()); + req.put(JsonKey.CLIENT_NAME, StringUtils.remove(clientName.toLowerCase(), " ")); + req.put(JsonKey.ID, uniqueId); + String masterKey = ProjectUtil.createAuthToken(clientName, uniqueId); + req.put(JsonKey.MASTER_KEY, masterKey); + req.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + req.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + req.put(JsonKey.CHANNEL, channel); + Util.DbInfo clientDbInfo = Util.dbInfoMap.get(JsonKey.CLIENT_INFO_DB); + Response result = + cassandraOperation.insertRecord( + clientDbInfo.getKeySpace(), clientDbInfo.getTableName(), req); + ProjectLogger.log("Client data saved into cassandra."); + result.getResult().put(JsonKey.CLIENT_ID, uniqueId); + result.getResult().put(JsonKey.MASTER_KEY, masterKey); + result.getResult().remove(JsonKey.RESPONSE); + // telemetry related data + targetObject = + TelemetryUtil.generateTargetObject(uniqueId, JsonKey.MASTER_KEY, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject(channel, "channel", "client.channel", correlatedObject); + + sender().tell(result, self()); + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + } + + /** + * Method to update client's master key based on client id and master key + * + * @param actorMessage + */ + @SuppressWarnings("unchecked") + private void updateClientKey(Request actorMessage) { + ProjectLogger.log("Update client key method call start"); + String clientId = (String) actorMessage.getRequest().get(JsonKey.CLIENT_ID); + String masterKey = (String) actorMessage.getRequest().get(JsonKey.MASTER_KEY); + + Map targetObject = null; + // correlated object of telemetry event... + List> correlatedObject = new ArrayList<>(); + + // telemetry related data + targetObject = + TelemetryUtil.generateTargetObject(clientId, JsonKey.MASTER_KEY, JsonKey.UPDATE, null); + + Response data = getDataFromCassandra(JsonKey.ID, clientId); + List> dataList = + (List>) data.getResult().get(JsonKey.RESPONSE); + if (dataList.isEmpty() + || !StringUtils.equalsIgnoreCase( + masterKey, (String) dataList.get(0).get(JsonKey.MASTER_KEY))) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + // check uniqueness of channel , channel is optional ... + String channel = (String) actorMessage.getRequest().get(JsonKey.CHANNEL); + if (!StringUtils.isBlank(channel) + && !channel.equalsIgnoreCase((String) dataList.get(0).get(JsonKey.CHANNEL))) { + data = getDataFromCassandra(JsonKey.CHANNEL, channel); + List> dataList1 = + (List>) data.getResult().get(JsonKey.RESPONSE); + if (!dataList1.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.channelUniquenessInvalid.getErrorCode(), + ResponseCode.channelUniquenessInvalid.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + String clientName = (String) actorMessage.getRequest().get(JsonKey.CLIENT_NAME); + if (!StringUtils.isBlank(clientName) + && !clientName.equalsIgnoreCase((String) dataList.get(0).get(JsonKey.CLIENT_NAME))) { + data = getDataFromCassandra(JsonKey.CLIENT_NAME, clientName); + List> dataList1 = + (List>) data.getResult().get(JsonKey.RESPONSE); + if (!dataList1.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidClientName.getErrorCode(), + ResponseCode.invalidClientName.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + Map req = new HashMap<>(); + req.put(JsonKey.CLIENT_ID, clientId); + String newMasterKey = + ProjectUtil.createAuthToken((String) dataList.get(0).get(JsonKey.CLIENT_NAME), clientId); + req.put(JsonKey.MASTER_KEY, newMasterKey); + req.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + req.put(JsonKey.ID, clientId); + if (!StringUtils.isBlank(channel)) { + req.put(JsonKey.CHANNEL, channel); + } + if (!StringUtils.isBlank(clientName)) { + req.put(JsonKey.CLIENT_NAME, clientName); + } + req.remove(JsonKey.CLIENT_ID); + Util.DbInfo clientDbInfo = Util.dbInfoMap.get(JsonKey.CLIENT_INFO_DB); + Response result = + cassandraOperation.updateRecord( + clientDbInfo.getKeySpace(), clientDbInfo.getTableName(), req); + ProjectLogger.log("Client data updated into cassandra."); + result.getResult().put(JsonKey.CLIENT_ID, clientId); + result.getResult().put(JsonKey.MASTER_KEY, newMasterKey); + result.getResult().remove(JsonKey.RESPONSE); + sender().tell(result, self()); + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + } + + /** + * Method to get Client details + * + * @param actorMessage + */ + @SuppressWarnings("unchecked") + private void getClientKey(Request actorMessage) { + ProjectLogger.log("Get client key method call start"); + String id = (String) actorMessage.getRequest().get(JsonKey.CLIENT_ID); + String type = (String) actorMessage.getRequest().get(JsonKey.TYPE); + Response data = null; + if (JsonKey.CLIENT_ID.equalsIgnoreCase(type)) { + data = getDataFromCassandra(JsonKey.ID, id); + List> dataList = + (List>) data.getResult().get(JsonKey.RESPONSE); + if (dataList.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else if (JsonKey.CHANNEL.equalsIgnoreCase(type)) { + data = getDataFromCassandra(JsonKey.CHANNEL, id); + List> dataList = + (List>) data.getResult().get(JsonKey.RESPONSE); + if (dataList.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + sender().tell(data, self()); + } + + /** + * Method to get data from cassandra for Client_Info table + * + * @param propertyName + * @param propertyValue + * @return + */ + private Response getDataFromCassandra(String propertyName, String propertyValue) { + ProjectLogger.log("Get data from cassandra method call start"); + Response result = null; + Util.DbInfo clientDbInfo = Util.dbInfoMap.get(JsonKey.CLIENT_INFO_DB); + if (StringUtils.equalsIgnoreCase(JsonKey.CLIENT_NAME, propertyName)) { + result = + cassandraOperation.getRecordsByProperty( + clientDbInfo.getKeySpace(), + clientDbInfo.getTableName(), + JsonKey.CLIENT_NAME, + propertyValue.toLowerCase()); + } else if (StringUtils.equalsIgnoreCase(JsonKey.ID, propertyName)) { + result = + cassandraOperation.getRecordsByProperty( + clientDbInfo.getKeySpace(), clientDbInfo.getTableName(), JsonKey.ID, propertyValue); + } else if (StringUtils.equalsIgnoreCase(JsonKey.CHANNEL, propertyName)) { + result = + cassandraOperation.getRecordsByProperty( + clientDbInfo.getKeySpace(), + clientDbInfo.getTableName(), + JsonKey.CHANNEL, + propertyValue); + } + if (null == result || result.getResult().isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return result; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/fileuploadservice/FileUploadServiceActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/fileuploadservice/FileUploadServiceActor.java new file mode 100644 index 0000000000..bc14cb3a29 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/fileuploadservice/FileUploadServiceActor.java @@ -0,0 +1,94 @@ +package org.sunbird.learner.actors.fileuploadservice; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.azure.CloudService; +import org.sunbird.common.models.util.azure.CloudServiceFactory; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** Class to upload the file on cloud storage. Created by arvind on 28/8/17. */ +@ActorConfig( + tasks = {"fileStorageService"}, + asyncTasks = {} +) +public class FileUploadServiceActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + if (request.getOperation().equalsIgnoreCase(ActorOperations.FILE_STORAGE_SERVICE.getValue())) { + processFileUpload(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void processFileUpload(Request actorMessage) throws IOException { + String processId = ProjectUtil.getUniqueIdFromTimestamp(1); + Map req = (Map) actorMessage.getRequest().get(JsonKey.DATA); + + Response response = new Response(); + String fileExtension = ""; + String fileName = (String) req.get(JsonKey.FILE_NAME); + if (!StringUtils.isBlank(fileName)) { + String[] split = fileName.split("\\."); + if (split.length > 1) { + fileExtension = split[split.length - 1]; + } + } + String fName = "File-" + processId; + if (!StringUtils.isBlank(fileExtension)) { + fName = fName + "." + fileExtension.toLowerCase(); + ProjectLogger.log("File - " + fName + " Extension is " + fileExtension); + } + + File file = new File(fName); + FileOutputStream fos = null; + String avatarUrl = null; + try { + fos = new FileOutputStream(file); + fos.write((byte[]) req.get(JsonKey.FILE)); + + CloudService service = (CloudService) CloudServiceFactory.get("Azure"); + if (null == service) { + ProjectLogger.log("The cloud service is not available"); + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + String container = (String) req.get(JsonKey.CONTAINER); + avatarUrl = service.uploadFile(container, file); + } catch (IOException e) { + ProjectLogger.log("Exception Occurred while reading file in FileUploadServiceActor", e); + throw e; + } finally { + try { + if (ProjectUtil.isNotNull(fos)) { + fos.close(); + } + if (ProjectUtil.isNotNull(file)) { + file.delete(); + } + } catch (IOException e) { + ProjectLogger.log( + "Exception Occurred while closing fileInputStream in FileUploadServiceActor", e); + } + } + response.put(JsonKey.URL, avatarUrl); + sender().tell(response, self()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/geolocation/GeoLocationManagementActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/geolocation/GeoLocationManagementActor.java new file mode 100644 index 0000000000..6ef0fdde9e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/geolocation/GeoLocationManagementActor.java @@ -0,0 +1,362 @@ +package org.sunbird.learner.actors.geolocation; + +import java.text.SimpleDateFormat; +import java.util.*; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.fcm.Notification; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.telemetry.util.TelemetryUtil; + +/** Class for providing Geo Location for Organisation Created by arvind on 31/10/17. */ +@ActorConfig( + tasks = { + "getGeoLocation", + "createGeoLocation", + "updateGeoLocation", + "deleteGeoLocation", + "sendNotification", + "getUserCount" + }, + asyncTasks = {} +) +public class GeoLocationManagementActor extends BaseActor { + private Util.DbInfo geoLocationDbInfo = Util.dbInfoMap.get(JsonKey.GEO_LOCATION_DB); + private Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.GEO_LOCATION); + if (request.getOperation().equalsIgnoreCase(ActorOperations.CREATE_GEO_LOCATION.getValue())) { + createGeoLocation(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.GET_GEO_LOCATION.getValue())) { + getGeoLocation(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.UPDATE_GEO_LOCATION.getValue())) { + updateGeoLocation(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.DELETE_GEO_LOCATION.getValue())) { + deleteGeoLocation(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.SEND_NOTIFICATION.getValue())) { + sendNotification(request); + } else if (request.getOperation().equalsIgnoreCase(ActorOperations.GET_USER_COUNT.getValue())) { + getUserCount(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void getUserCount(Request actorMessage) { + ProjectLogger.log("sendnotification actor method called."); + List locationIds = (List) actorMessage.getRequest().get(JsonKey.LOCATION_IDS); + List> result = new ArrayList<>(); + List dbIdList = new ArrayList<>(); + Map responseMap = null; + Response response = + cassandraOperation.getRecordsByProperty( + geoLocationDbInfo.getKeySpace(), + geoLocationDbInfo.getTableName(), + JsonKey.ID, + locationIds); + List> list = (List>) response.get(JsonKey.RESPONSE); + for (Map map : list) { + responseMap = new HashMap<>(); + responseMap.put(JsonKey.ID, map.get(JsonKey.ID)); + responseMap.put( + JsonKey.USER_COUNT, + ((map.get(JsonKey.USER_COUNT) == null) ? 0 : map.get(JsonKey.USER_COUNT))); + result.add(responseMap); + dbIdList.add((String) map.get(JsonKey.ID)); + } + // For Invalid Location Id + for (Object str : locationIds) { + if (!dbIdList.contains((String) str)) { + responseMap = new HashMap<>(); + responseMap.put(JsonKey.ID, str); + responseMap.put(JsonKey.USER_COUNT, 0); + result.add(responseMap); + } + } + response = new Response(); + response.getResult().put(JsonKey.LOCATIONS, result); + sender().tell(response, self()); + // Update user count in background + actorMessage.setOperation(BackgroundOperations.updateUserCountToLocationID.name()); + actorMessage.getRequest().put(JsonKey.OPERATION, "GeoLocationManagementActor"); + tellToAnother(actorMessage); + } + + private void sendNotification(Request actorMessage) { + ProjectLogger.log("sendnotification actor method called."); + String topic = (String) actorMessage.getRequest().get(JsonKey.TO); + // Topic name is same as Location id in current system. + // if logic is change then we need to update the matching logic as well + Response response = + cassandraOperation.getRecordById( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), topic); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (list.isEmpty()) { + // throw exception that invalid topic ... + throw new ProjectCommonException( + ResponseCode.invalidTopic.getErrorCode(), + ResponseCode.invalidTopic.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Map notificationData = (Map) actorMessage.getRequest().get(JsonKey.DATA); + String message = Notification.sendNotification(topic, notificationData, Notification.FCM_URL); + ProjectLogger.log("FCM message from Google ==" + message); + response = new Response(); + if (JsonKey.FAILURE.equalsIgnoreCase(message)) { + response.getResult().put(JsonKey.RESPONSE, JsonKey.FAILURE); + } else { + response.getResult().put(JsonKey.RESPONSE, JsonKey.SUCCESS); + response.getResult().put(JsonKey.ID, message); + } + sender().tell(response, self()); + } + + /** + * Delete geo location on basis of location id. + * + * @param actorMessage + */ + private void deleteGeoLocation(Request actorMessage) { + + ProjectLogger.log("GeoLocationManagementActor-updateGeoLocation called"); + + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + String locationId = (String) actorMessage.getRequest().get(JsonKey.LOCATION_ID); + Response finalResponse = new Response(); + + if (StringUtils.isBlank(locationId)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + cassandraOperation.deleteRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locationId); + finalResponse.getResult().put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(finalResponse, self()); + + targetObject = + TelemetryUtil.generateTargetObject(locationId, JsonKey.LOCATION, JsonKey.DELETE, null); + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + } + + /** + * Update geo location on basis of locationId , only location type and + * + * @param actorMessage + */ + private void updateGeoLocation(Request actorMessage) { + + ProjectLogger.log("GeoLocationManagementActor-updateGeoLocation called"); + + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + String requestedBy = (String) actorMessage.getRequest().get(JsonKey.REQUESTED_BY); + String locationId = (String) actorMessage.getRequest().get(JsonKey.LOCATION_ID); + String type = (String) actorMessage.getRequest().get(JsonKey.TYPE); + String location = (String) actorMessage.getRequest().get(JsonKey.LOCATION); + Response finalResponse = new Response(); + + if (StringUtils.isBlank(locationId)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Response response1 = + cassandraOperation.getRecordById( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locationId); + List> list = (List>) response1.get(JsonKey.RESPONSE); + if (list.isEmpty()) { + // throw exception that invalid location id ... + throw new ProjectCommonException( + ResponseCode.invalidLocationId.getErrorCode(), + ResponseCode.invalidLocationId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Map dbResult = list.get(0); + + Map dbMap = new HashMap<>(); + if (!StringUtils.isBlank(type)) { + dbMap.put(JsonKey.TYPE, type); + } + if (!StringUtils.isBlank(location)) { + dbMap.put(JsonKey.LOCATION, location); + } + + dbMap.put(JsonKey.UPDATED_BY, requestedBy); + dbMap.put(JsonKey.UPDATED_DATE, format.format(new Date())); + + dbMap.put(JsonKey.ID, dbResult.get(JsonKey.ID)); + cassandraOperation.updateRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), dbMap); + + finalResponse.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(finalResponse, self()); + + targetObject = + TelemetryUtil.generateTargetObject(locationId, JsonKey.LOCATION, JsonKey.UPDATE, null); + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + } + + /** + * Get geo location on basis of type and id . type should be organisation or location . + * + * @param actorMessage + */ + private void getGeoLocation(Request actorMessage) { + + ProjectLogger.log("GeoLocationManagementActor-getGeoLocation called"); + String id = (String) actorMessage.getRequest().get(JsonKey.ID); + String type = (String) actorMessage.getRequest().get(JsonKey.TYPE); + Response finalResponse = new Response(); + + if (StringUtils.isBlank(id) || StringUtils.isBlank(type)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (type.equalsIgnoreCase(JsonKey.ORGANISATION)) { + Response response1 = + cassandraOperation.getRecordsByProperty( + geoLocationDbInfo.getKeySpace(), + geoLocationDbInfo.getTableName(), + JsonKey.ROOT_ORG_ID, + id); + List> list = (List>) response1.get(JsonKey.RESPONSE); + + finalResponse.put(JsonKey.RESPONSE, list); + + sender().tell(finalResponse, self()); + return; + + } else if (type.equalsIgnoreCase(JsonKey.LOCATION)) { + + Response response1 = + cassandraOperation.getRecordById( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), id); + List> list = (List>) response1.get(JsonKey.RESPONSE); + finalResponse.put(JsonKey.RESPONSE, list); + sender().tell(finalResponse, self()); + return; + } else { + throw new ProjectCommonException( + ResponseCode.invalidTypeValue.getErrorCode(), + ResponseCode.invalidTypeValue.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * Create geo location , and id and topic value will be same . + * + * @param actorMessage + */ + private void createGeoLocation(Request actorMessage) { + ProjectLogger.log("GeoLocationManagementActor-createGeoLocation called"); + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + + List> dataList = + (List>) actorMessage.getRequest().get(JsonKey.DATA); + + Response finalResponse = new Response(); + List> responseList = new ArrayList<>(); + String requestedBy = (String) actorMessage.getRequest().get(JsonKey.REQUESTED_BY); + String rootOrgId = (String) actorMessage.getRequest().get(JsonKey.ROOT_ORG_ID); + + if (StringUtils.isBlank(rootOrgId)) { + // throw invalid ord id ,org id should not be null or empty . + throw new ProjectCommonException( + ResponseCode.invalidOrgId.getErrorCode(), + ResponseCode.invalidOrgId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + // check whether org exist or not + Response result = + cassandraOperation.getRecordById( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), rootOrgId); + List> orglist = (List>) result.get(JsonKey.RESPONSE); + if (orglist.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidOrgId.getErrorCode(), + ResponseCode.invalidOrgId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (dataList.isEmpty()) { + // no need to do anything throw exception invalid request data as list is empty + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + for (Map dataMap : dataList) { + + String location = (String) dataMap.get(JsonKey.LOCATION); + String type = (String) dataMap.get(JsonKey.TYPE); + if (StringUtils.isBlank(location)) { + continue; + } + + String id = ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv()); + + Map dbMap = new HashMap<>(); + + dbMap.put(JsonKey.ID, id); + dbMap.put(JsonKey.CREATED_DATE, format.format(new Date())); + dbMap.put(JsonKey.CREATED_BY, requestedBy); + dbMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + dbMap.put(JsonKey.LOCATION, location); + dbMap.put(JsonKey.TOPIC, id); + dbMap.put(JsonKey.TYPE, type); + + cassandraOperation.insertRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), dbMap); + + Map responseMap = new HashMap<>(); + responseMap.put(JsonKey.ID, id); + responseMap.put(JsonKey.LOCATION, location); + responseMap.put(JsonKey.STATUS, JsonKey.SUCCESS); + responseList.add(responseMap); + + targetObject = TelemetryUtil.generateTargetObject(id, JsonKey.LOCATION, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject(id, JsonKey.LOCATION, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject(rootOrgId, JsonKey.ROOT_ORG, null, correlatedObject); + TelemetryUtil.telemetryProcessingCall( + actorMessage.getRequest(), targetObject, correlatedObject, actorMessage.getContext()); + } + finalResponse.getResult().put(JsonKey.RESPONSE, responseList); + sender().tell(finalResponse, self()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/health/HealthActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/health/HealthActor.java new file mode 100644 index 0000000000..9f8e603043 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/health/HealthActor.java @@ -0,0 +1,220 @@ +/** */ +package org.sunbird.learner.actors.health; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import scala.concurrent.Future; + +/** @author Manzarul */ +@ActorConfig( + tasks = {"healthCheck", "actor", "es", "cassandra"}, + asyncTasks = {} +) +public class HealthActor extends BaseActor { + + @Override + public void onReceive(Request message) throws Throwable { + if (message instanceof Request) { + try { + ProjectLogger.log("AssessmentItemActor onReceive called"); + Request actorMessage = message; + Util.initializeContext(actorMessage, TelemetryEnvKey.USER); + if (actorMessage.getOperation().equalsIgnoreCase(ActorOperations.HEALTH_CHECK.getValue())) { + checkAllComponentHealth(); + } else if (actorMessage.getOperation().equalsIgnoreCase(ActorOperations.ACTOR.getValue())) { + actorhealthCheck(); + } else if (actorMessage.getOperation().equalsIgnoreCase(ActorOperations.ES.getValue())) { + esHealthCheck(); + } else if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.CASSANDRA.getValue())) { + cassandraHealthCheck(); + } else { + ProjectLogger.log("UNSUPPORTED OPERATION"); + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOperationName.getErrorCode(), + ResponseCode.invalidOperationName.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } else { + // Throw exception as message body + ProjectLogger.log("UNSUPPORTED MESSAGE"); + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + } + + /** */ + private void esHealthCheck() { + // check the elastic search + boolean isallHealthy = true; + Map finalResponseMap = new HashMap<>(); + List> responseList = new ArrayList<>(); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ACTOR_SERVICE, false, null)); + try { + Future esResponseF = getEsConnection().healthCheck(); + boolean esResponse = (boolean) ElasticSearchHelper.getResponseFromFuture(esResponseF); + + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ES_SERVICE, esResponse, null)); + isallHealthy = esResponse; + } catch (Exception e) { + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ES_SERVICE, true, e)); + isallHealthy = false; + ProjectLogger.log("Elastic search health Error == ", e); + } + finalResponseMap.put(JsonKey.CHECKS, responseList); + finalResponseMap.put(JsonKey.NAME, "ES health check api"); + if (isallHealthy) { + finalResponseMap.put(JsonKey.Healthy, true); + } else { + finalResponseMap.put(JsonKey.Healthy, false); + } + Response response = new Response(); + response.getResult().put(JsonKey.RESPONSE, finalResponseMap); + sender().tell(response, self()); + } + + /** */ + private void cassandraHealthCheck() { + Map finalResponseMap = new HashMap<>(); + List> responseList = new ArrayList<>(); + boolean isallHealthy = false; + responseList.add(ProjectUtil.createCheckResponse(JsonKey.LEARNER_SERVICE, false, null)); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ACTOR_SERVICE, false, null)); + try { + Util.DbInfo badgesDbInfo = Util.dbInfoMap.get(JsonKey.BADGES_DB); + getCassandraOperation() + .getAllRecords(badgesDbInfo.getKeySpace(), badgesDbInfo.getTableName()); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.CASSANDRA_SERVICE, false, null)); + } catch (Exception e) { + responseList.add(ProjectUtil.createCheckResponse(JsonKey.CASSANDRA_SERVICE, true, e)); + isallHealthy = false; + } + finalResponseMap.put(JsonKey.CHECKS, responseList); + finalResponseMap.put(JsonKey.NAME, "cassandra health check api"); + if (isallHealthy) { + finalResponseMap.put(JsonKey.Healthy, true); + } else { + finalResponseMap.put(JsonKey.Healthy, false); + } + Response response = new Response(); + response.getResult().put(JsonKey.RESPONSE, finalResponseMap); + sender().tell(response, self()); + } + + /** */ + private void actorhealthCheck() { + Map finalResponseMap = new HashMap<>(); + List> responseList = new ArrayList<>(); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.LEARNER_SERVICE, false, null)); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ACTOR_SERVICE, false, null)); + finalResponseMap.put(JsonKey.CHECKS, responseList); + finalResponseMap.put(JsonKey.NAME, "Actor health check api"); + finalResponseMap.put(JsonKey.Healthy, true); + Response response = new Response(); + response.getResult().put(JsonKey.RESPONSE, finalResponseMap); + sender().tell(response, self()); + } + + /** */ + private void checkAllComponentHealth() { + boolean isallHealthy = true; + Map finalResponseMap = new HashMap<>(); + List> responseList = new ArrayList<>(); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.LEARNER_SERVICE, false, null)); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ACTOR_SERVICE, false, null)); + try { + Util.DbInfo badgesDbInfo = Util.dbInfoMap.get(JsonKey.BADGES_DB); + getCassandraOperation() + .getAllRecords(badgesDbInfo.getKeySpace(), badgesDbInfo.getTableName()); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.CASSANDRA_SERVICE, false, null)); + } catch (Exception e) { + responseList.add(ProjectUtil.createCheckResponse(JsonKey.CASSANDRA_SERVICE, true, e)); + isallHealthy = false; + } + // check the elastic search + try { + Future responseF = getEsConnection().healthCheck(); + boolean response = (boolean) ElasticSearchHelper.getResponseFromFuture(responseF); + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ES_SERVICE, !response, null)); + isallHealthy = response; + } catch (Exception e) { + responseList.add(ProjectUtil.createCheckResponse(JsonKey.ES_SERVICE, true, e)); + isallHealthy = false; + } + // check EKStep Util. + try { + String body = "{\"request\":{\"filters\":{\"identifier\":\"test\"}}}"; + Map headers = new HashMap<>(); + headers.put( + JsonKey.AUTHORIZATION, JsonKey.BEARER + System.getenv(JsonKey.EKSTEP_AUTHORIZATION)); + if (StringUtils.isBlank(headers.get(JsonKey.AUTHORIZATION))) { + headers.put( + JsonKey.AUTHORIZATION, + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION)); + headers.put("Content_Type", "application/json; charset=utf-8"); + } + String searchBaseUrl = ProjectUtil.getConfigValue(JsonKey.SEARCH_SERVICE_API_BASE_URL); + String response = + HttpUtil.sendPostRequest( + searchBaseUrl + + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_CONTENT_SEARCH_URL), + body, + headers); + if (response.contains("OK")) { + responseList.add(ProjectUtil.createCheckResponse(JsonKey.EKSTEP_SERVICE, false, null)); + } else { + responseList.add(ProjectUtil.createCheckResponse(JsonKey.EKSTEP_SERVICE, true, null)); + } + } catch (Exception e) { + responseList.add(ProjectUtil.createCheckResponse(JsonKey.EKSTEP_SERVICE, true, null)); + isallHealthy = false; + } + ProjectLogger.log( + "HealthActor:checkAllComponentHealth: EKSTEP URL COMMENTED", LoggerEnum.INFO.name()); + finalResponseMap.put(JsonKey.CHECKS, responseList); + finalResponseMap.put(JsonKey.NAME, "Complete health check api"); + if (isallHealthy) { + finalResponseMap.put(JsonKey.Healthy, true); + } else { + finalResponseMap.put(JsonKey.Healthy, false); + } + Response response = new Response(); + response.getResult().put(JsonKey.RESPONSE, finalResponseMap); + sender().tell(response, self()); + } + + public CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } + + public ElasticSearchService getEsConnection() { + return EsClientFactory.getInstance(JsonKey.REST); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/EmailServiceActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/EmailServiceActor.java new file mode 100644 index 0000000000..ba8c20b4dd --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/EmailServiceActor.java @@ -0,0 +1,426 @@ +package org.sunbird.learner.actors.notificationservice; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.models.util.mail.SendMail; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.notificationservice.dao.EmailTemplateDao; +import org.sunbird.learner.actors.notificationservice.dao.impl.EmailTemplateDaoImpl; +import org.sunbird.learner.util.Util; +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.utils.SMSFactory; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {"emailService"}, + asyncTasks = {"emailService"} +) +public class EmailServiceActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + private EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + if (request.getOperation().equalsIgnoreCase(BackgroundOperations.emailService.name())) { + sendMail(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + @SuppressWarnings({"unchecked"}) + private void sendMail(Request actorMessage) { + Map request = + (Map) actorMessage.getRequest().get(JsonKey.EMAIL_REQUEST); + + List userIds = (List) request.get(JsonKey.RECIPIENT_USERIDS); + if (CollectionUtils.isEmpty(userIds)) { + userIds = new ArrayList<>(); + } + + if (request.get(JsonKey.MODE) != null + && "sms".equalsIgnoreCase((String) request.get(JsonKey.MODE))) { + // Sending sms + List phones = (List) request.get(JsonKey.RECIPIENT_PHONES); + if (CollectionUtils.isNotEmpty(phones)) { + Iterator itr = phones.iterator(); + while (itr.hasNext()) { + String phone = itr.next(); + if (!ProjectUtil.validatePhone(phone, "")) { + ProjectLogger.log( + "EmailServiceActor:sendMail: Removing invalid phone number =" + phone, + LoggerEnum.INFO.name()); + itr.remove(); + } + } + } + sendSMS(phones, userIds, (String) request.get(JsonKey.BODY)); + } else { + // Sending email + List emails = (List) request.get(JsonKey.RECIPIENT_EMAILS); + if (CollectionUtils.isNotEmpty(emails)) { + checkEmailValidity(emails); + } else { + emails = new ArrayList<>(); + } + // Fetch public user emails from Elastic Search based on recipient search query given in + // request. + getUserEmailsFromSearchQuery(request, emails, userIds); + + validateUserIds(userIds, emails); + validateRecipientsLimit(emails); + + Map user = null; + if (CollectionUtils.isNotEmpty(emails)) { + user = getUserInfo(emails.get(0)); + } + + String name = ""; + if (emails.size() == 1) { + name = StringUtils.capitalize((String) user.get(JsonKey.FIRST_NAME)); + if (StringUtils.isBlank(name) && (String) request.get(JsonKey.FIRST_NAME) != null) { + name = StringUtils.capitalize((String) request.get(JsonKey.FIRST_NAME)); + } + } + + // fetch orgname inorder to set in the Template context + String orgName = getOrgName(request, (String) user.get(JsonKey.USER_ID)); + + request.put(JsonKey.NAME, name); + if (orgName != null) { + request.put(JsonKey.ORG_NAME, orgName); + } + + String template = getEmailTemplateFile((String) request.get(JsonKey.EMAIL_TEMPLATE_TYPE)); + + if (1 == emails.size()) { + ProjectLogger.log( + "EmailServiceActor:sendMail: Sending email to = " + emails + " emails", + LoggerEnum.INFO.name()); + } else { + ProjectLogger.log( + "EmailServiceActor:sendMail: Sending email to = " + emails.size() + " emails", + LoggerEnum.INFO.name()); + } + + try { + SendMail.sendMailWithBody( + emails.toArray(new String[emails.size()]), + (String) request.get(JsonKey.SUBJECT), + ProjectUtil.getContext(request), + template); + } catch (Exception e) { + ProjectLogger.log( + "EmailServiceActor:sendMail: Exception occurred with message = " + e.getMessage(), e); + } + } + + Response res = new Response(); + res.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(res, self()); + } + + /** + * This method will send sms to targeted user. + * + * @param phones list of phone numbers + * @param userIds list of userIds + * @param smsText message + */ + private void sendSMS(List phones, List userIds, String smsText) { + ProjectLogger.log( + "EmailServiceActor:sendSMS: method started = " + smsText, LoggerEnum.INFO.name()); + if (CollectionUtils.isEmpty(phones)) { + phones = new ArrayList(); + } + if (CollectionUtils.isNotEmpty(userIds)) { + List> userList = getUsersFromDB(userIds); + if (userIds.size() != userList.size()) { + findMissingUserIds(userIds, userList); + } else { + for (Map userMap : userList) { + String phone = (String) userMap.get(JsonKey.PHONE); + if (StringUtils.isNotBlank(phone)) { + String decryptedPhone = decryptionService.decryptData(phone); + if (!phones.contains(decryptedPhone)) { + phones.add(decryptedPhone); + } + } + } + } + } + + validateRecipientsLimit(phones); + + ProjectLogger.log( + "EmailServiceActor:sendSMS: Sending sendSMS to = " + phones.size() + " phones", + LoggerEnum.INFO.name()); + try { + ISmsProvider smsProvider = SMSFactory.getInstance("91SMS"); + smsProvider.send(phones, smsText); + } catch (Exception e) { + ProjectLogger.log( + "EmailServiceActor:sendSMS: Exception occurred with message = " + e.getMessage(), e); + } + } + + private void validateRecipientsLimit(List recipients) { + if (CollectionUtils.isEmpty(recipients)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.emailNotSentRecipientsZero, + ResponseCode.emailNotSentRecipientsZero.getErrorMessage()); + } + int maxLimit = 100; + try { + maxLimit = + Integer.parseInt(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_EMAIL_MAX_RECEPIENT_LIMIT)); + } catch (Exception exception) { + ProjectLogger.log( + "EmailServiceActor:validateEmailRecipientsLimit: Exception occurred with error message = " + + exception.getMessage(), + LoggerEnum.INFO); + maxLimit = 100; + } + if (recipients.size() > maxLimit) { + ProjectCommonException.throwClientErrorException( + ResponseCode.emailNotSentRecipientsExceededMaxLimit, + MessageFormat.format( + ResponseCode.emailNotSentRecipientsExceededMaxLimit.getErrorMessage(), maxLimit)); + } + } + + private void validateUserIds(List userIds, List emails) { + // Fetch private (masked in Elastic Search) user emails from Cassandra DB + if (CollectionUtils.isNotEmpty(userIds)) { + List> userList = getUsersFromDB(userIds); + if (userIds.size() != userList.size()) { + findMissingUserIds(userIds, userList); + } else { + for (Map userMap : userList) { + String email = (String) userMap.get(JsonKey.EMAIL); + if (StringUtils.isNotBlank(email)) { + String decryptedEmail = decryptionService.decryptData(email); + emails.add(decryptedEmail); + } + } + } + } + } + + private void findMissingUserIds( + List requestedUserIds, List> userListInDB) { + // if requested userId list and cassandra user list size not same , means + // requested userId + // list + // contains some invalid userId + List userIdFromDBList = new ArrayList<>(); + userListInDB.forEach( + user -> { + userIdFromDBList.add((String) user.get(JsonKey.ID)); + }); + requestedUserIds.forEach( + userId -> { + if (!userIdFromDBList.contains(userId)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + userId, + JsonKey.RECIPIENT_USERIDS)); + return; + } + }); + } + + private String getEmailTemplateFile(String templateName) { + EmailTemplateDao emailTemplateDao = EmailTemplateDaoImpl.getInstance(); + String template = emailTemplateDao.getTemplate(templateName); + if (StringUtils.isBlank(template)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + templateName, + JsonKey.EMAIL_TEMPLATE_TYPE)); + } + return template; + } + + private List> getUsersFromDB(List userIds) { + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + List userIdList = new ArrayList<>(userIds); + List fields = new ArrayList<>(); + fields.add(JsonKey.ID); + fields.add(JsonKey.FIRST_NAME); + fields.add(JsonKey.EMAIL); + fields.add(JsonKey.PHONE); + Response response = + cassandraOperation.getRecordsByIdsWithSpecifiedColumns( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), fields, userIdList); + List> userList = (List>) response.get(JsonKey.RESPONSE); + return userList; + } + + private void getUserEmailsFromSearchQuery( + Map request, List emails, List userIds) { + Map recipientSearchQuery = + (Map) request.get(JsonKey.RECIPIENT_SEARCH_QUERY); + if (MapUtils.isNotEmpty(recipientSearchQuery)) { + + if (MapUtils.isEmpty((Map) recipientSearchQuery.get(JsonKey.FILTERS))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + recipientSearchQuery, + JsonKey.RECIPIENT_SEARCH_QUERY)); + return; + } + + List fields = new ArrayList<>(); + fields.add(JsonKey.USER_ID); + fields.add(JsonKey.EMAIL); + recipientSearchQuery.put(JsonKey.FIELDS, fields); + Map esResult = Collections.emptyMap(); + try { + Future> esResultF = + esService.search( + ElasticSearchHelper.createSearchDTO(recipientSearchQuery), + EsType.user.getTypeName()); + esResult = (Map) ElasticSearchHelper.getResponseFromFuture(esResultF); + } catch (Exception ex) { + ProjectLogger.log( + "EmailServiceActor:getUserEmailsFromSearchQuery: Exception occurred with error message = " + + ex.getMessage(), + ex); + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + recipientSearchQuery, + JsonKey.RECIPIENT_SEARCH_QUERY)); + return; + } + if (MapUtils.isNotEmpty(esResult) + && CollectionUtils.isNotEmpty((List) esResult.get(JsonKey.CONTENT))) { + List> usersList = + (List>) esResult.get(JsonKey.CONTENT); + usersList.forEach( + user -> { + if (StringUtils.isNotBlank((String) user.get(JsonKey.EMAIL))) { + String email = decryptionService.decryptData((String) user.get(JsonKey.EMAIL)); + if (ProjectUtil.isEmailvalid(email)) { + emails.add(email); + } else { + ProjectLogger.log( + "EmailServiceActor:sendMail: Email decryption failed for userId = " + + user.get(JsonKey.USER_ID)); + } + } else { + // If email is blank (or private) then fetch email from cassandra + userIds.add((String) user.get(JsonKey.USER_ID)); + } + }); + } + } + } + + private String getOrgName(Map request, String usrId) { + String orgName = (String) request.get(JsonKey.ORG_NAME); + if (StringUtils.isNotBlank(orgName)) { + return orgName; + } + Future> esUserResultF = + esService.getDataByIdentifier(EsType.user.getTypeName(), usrId); + Map esUserResult = + (Map) ElasticSearchHelper.getResponseFromFuture(esUserResultF); + if (null != esUserResult) { + String rootOrgId = (String) esUserResult.get(JsonKey.ROOT_ORG_ID); + if (!(StringUtils.isBlank(rootOrgId))) { + + Future> esOrgResultF = + esService.getDataByIdentifier(EsType.organisation.getTypeName(), rootOrgId); + Map esOrgResult = + (Map) ElasticSearchHelper.getResponseFromFuture(esOrgResultF); + if (null != esOrgResult) { + orgName = + (esOrgResult.get(JsonKey.ORG_NAME) != null + ? (String) esOrgResult.get(JsonKey.ORGANISATION_NAME) + : ""); + } + } + } + return orgName; + } + + @SuppressWarnings("unchecked") + private Map getUserInfo(String email) { + String encryptedMail = ""; + try { + encryptedMail = encryptionService.encryptData(email); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + SearchDTO searchDTO = new SearchDTO(); + Map additionalProperties = new HashMap<>(); + additionalProperties.put(JsonKey.EMAIL, encryptedMail); + searchDTO.addAdditionalProperty(JsonKey.FILTERS, additionalProperties); + Future> esResultF = esService.search(searchDTO, EsType.user.getTypeName()); + Map esResult = + (Map) ElasticSearchHelper.getResponseFromFuture(esResultF); + if (MapUtils.isNotEmpty(esResult) + && CollectionUtils.isNotEmpty((List) esResult.get(JsonKey.CONTENT))) { + return ((List>) esResult.get(JsonKey.CONTENT)).get(0); + } else { + return Collections.EMPTY_MAP; + } + } + + private void checkEmailValidity(List emails) { + for (String email : emails) { + if (!ProjectUtil.isEmailvalid(email)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + email, + JsonKey.RECIPIENT_EMAILS)); + return; + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/dao/EmailTemplateDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/dao/EmailTemplateDao.java new file mode 100644 index 0000000000..8dd7276bed --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/dao/EmailTemplateDao.java @@ -0,0 +1,12 @@ +package org.sunbird.learner.actors.notificationservice.dao; + +public interface EmailTemplateDao { + + /** + * Get email template information for given name. + * + * @param templateName Email template name + * @return String containing email template information + */ + String getTemplate(String templateName); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/dao/impl/EmailTemplateDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/dao/impl/EmailTemplateDaoImpl.java new file mode 100644 index 0000000000..6ca7c4ba0e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/notificationservice/dao/impl/EmailTemplateDaoImpl.java @@ -0,0 +1,53 @@ +package org.sunbird.learner.actors.notificationservice.dao.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.notificationservice.dao.EmailTemplateDao; + +public class EmailTemplateDaoImpl implements EmailTemplateDao { + + static EmailTemplateDao emailTemplateDao; + private static final String EMAIL_TEMPLATE = "email_template"; + private static final String DEFAULT_EMAIL_TEMPLATE_NAME = "default"; + private static final String TEMPLATE = "template"; + + public static EmailTemplateDao getInstance() { + if (emailTemplateDao == null) { + emailTemplateDao = new EmailTemplateDaoImpl(); + } + return emailTemplateDao; + } + + @Override + public String getTemplate(String templateName) { + + List idList = new ArrayList<>(); + if (StringUtils.isBlank(templateName)) { + idList.add(DEFAULT_EMAIL_TEMPLATE_NAME); + } else { + idList.add(templateName); + } + Response response = + getCassandraOperation() + .getRecordsByPrimaryKeys(JsonKey.SUNBIRD, EMAIL_TEMPLATE, idList, JsonKey.NAME); + List> emailTemplateList = + (List>) response.get(JsonKey.RESPONSE); + Map map = Collections.emptyMap(); + if (CollectionUtils.isNotEmpty(emailTemplateList)) { + map = emailTemplateList.get(0); + } + return (String) map.get(TEMPLATE); + } + + private CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/OTPActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/OTPActor.java new file mode 100644 index 0000000000..104054a339 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/OTPActor.java @@ -0,0 +1,239 @@ +package org.sunbird.learner.actors.otp; + +import java.text.MessageFormat; +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.ClientErrorResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.datasecurity.impl.LogMaskServiceImpl; +import org.sunbird.common.request.ExecutionContext; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.actors.otp.service.OTPService; +import org.sunbird.learner.util.OTPUtil; +import org.sunbird.learner.util.Util; +import org.sunbird.ratelimit.limiter.OtpRateLimiter; +import org.sunbird.ratelimit.limiter.RateLimiter; +import org.sunbird.ratelimit.service.RateLimitService; +import org.sunbird.ratelimit.service.RateLimitServiceImpl; + +@ActorConfig( + tasks = {"generateOTP", "verifyOTP"}, + asyncTasks = {} +) +public class OTPActor extends BaseActor { + + private OTPService otpService = new OTPService(); + private static final String SUNBIRD_OTP_ALLOWED_ATTEMPT = "sunbird_otp_allowed_attempt"; + private static final String REMAINING_ATTEMPT = "remainingAttempt"; + private static final String MAX_ALLOWED_ATTEMPT = "maxAllowedAttempt"; + private RateLimitService rateLimitService = new RateLimitServiceImpl(); + private LogMaskServiceImpl logMaskService = new LogMaskServiceImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + ExecutionContext.setRequestId(request.getRequestId()); + if (ActorOperations.GENERATE_OTP.getValue().equals(request.getOperation())) { + generateOTP(request); + } else if (ActorOperations.VERIFY_OTP.getValue().equals(request.getOperation())) { + verifyOTP(request); + } else { + onReceiveUnsupportedOperation("OTPActor"); + } + } + + private String maskOTP(String otp) { + return logMaskService.maskOTP(otp); + } + + private String maskId(String id, String type) { + if (JsonKey.EMAIL.equalsIgnoreCase(type)) { + return logMaskService.maskEmail(id); + } else if (JsonKey.PHONE.equalsIgnoreCase(type)) { + return logMaskService.maskPhone(id); + } + return ""; + } + + private void generateOTP(Request request) { + ProjectLogger.log("OTPActor:generateOTP method call start.", LoggerEnum.INFO.name()); + String type = (String) request.getRequest().get(JsonKey.TYPE); + String key = getKey(type, request); + + String userId = (String) request.getRequest().get(JsonKey.USER_ID); + if (StringUtils.isNotBlank(userId)) { + key = OTPUtil.getEmailPhoneByUserId(userId, type); + type = getType(type); + ProjectLogger.log("OTPActor:OTPUtil.getEmailPhoneByUserId: called for userId = "+userId+" ,key = "+maskId(key,type),LoggerEnum.INFO.name()); + } + + rateLimitService.throttleByKey( + key, new RateLimiter[] {OtpRateLimiter.HOUR, OtpRateLimiter.DAY}); + + String otp = null; + Map details = otpService.getOTPDetails(type, key); + + if (MapUtils.isEmpty(details)) { + otp = OTPUtil.generateOTP(); + ProjectLogger.log( + "OTPActor:generateOTP: inserting otp Key = " + + maskId(key, type) + + " OTP = " + + maskOTP(otp), + LoggerEnum.INFO.name()); + otpService.insertOTPDetails(type, key, otp); + } else { + otp = (String) details.get(JsonKey.OTP); + ProjectLogger.log( + "OTPActor:generateOTP: Re-issuing otp Key = " + + maskId(key, type) + + " OTP = " + + maskOTP(otp), + LoggerEnum.INFO.name()); + } + ProjectLogger.log( + "OTPActor:sendOTP : Calling SendOTPActor for Key = " + maskId(key, type), + LoggerEnum.INFO.name()); + sendOTP(request, otp, key); + + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + } + + private String getType(String type) { + switch (type) { + case JsonKey.PREV_USED_EMAIL: + return JsonKey.EMAIL; + case JsonKey.PREV_USED_PHONE: + return JsonKey.PHONE; + case JsonKey.EMAIL: + return JsonKey.EMAIL; + case JsonKey.PHONE: + return JsonKey.PHONE; + case JsonKey.RECOVERY_EMAIL: + return JsonKey.EMAIL; + case JsonKey.RECOVERY_PHONE: + return JsonKey.PHONE; + default: + return null; + } + } + + private void verifyOTP(Request request) { + String type = (String) request.getRequest().get(JsonKey.TYPE); + String key = getKey(type, request); + String otpInRequest = (String) request.getRequest().get(JsonKey.OTP); + + String userId = (String) request.getRequest().get(JsonKey.USER_ID); + if (StringUtils.isNotBlank(userId)) { + key = OTPUtil.getEmailPhoneByUserId(userId, type); + type = getType(type); + } + Map otpDetails = otpService.getOTPDetails(type, key); + + if (MapUtils.isEmpty(otpDetails)) { + ProjectLogger.log( + "OTPActor:verifyOTP: Details not found for Key = " + + maskId(key, type) + + " type = " + + type, + LoggerEnum.INFO.name()); + ProjectCommonException.throwClientErrorException(ResponseCode.errorInvalidOTP); + } + String otpInDB = (String) otpDetails.get(JsonKey.OTP); + if (StringUtils.isBlank(otpInDB) || StringUtils.isBlank(otpInRequest)) { + ProjectLogger.log( + "OTPActor:verifyOTP: Mismatch for Key = " + + maskId(key, type) + + " otpInRequest = " + + maskOTP(otpInRequest) + + " otpInDB = " + + maskOTP(otpInDB), + LoggerEnum.DEBUG); + ProjectCommonException.throwClientErrorException(ResponseCode.errorInvalidOTP); + } + + if (otpInRequest.equals(otpInDB)) { + ProjectLogger.log( + "OTPActor:verifyOTP: Verified successfully Key = " + maskId(key, type), + LoggerEnum.INFO.name()); + otpService.deleteOtp(type, key); + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + } else { + ProjectLogger.log( + "OTPActor:verifyOTP: Incorrect OTP Key = " + + maskId(key, type) + + " otpInRequest = " + + maskOTP(otpInRequest) + + " otpInDB = " + + maskOTP(otpInDB), + LoggerEnum.INFO.name()); + handleMismatchOtp(type, key, otpDetails); + } + } + + private void handleMismatchOtp(String type, String key, Map otpDetails) { + int remainingCount = getRemainingAttemptedCount(otpDetails); + ProjectLogger.log( + "OTPActor:handleMismatchOtp: Key = " + + maskId(key, type) + + ",remaining attempt is " + + remainingCount, + LoggerEnum.INFO.name()); + int attemptedCount = (int) otpDetails.get(JsonKey.ATTEMPTED_COUNT); + if (remainingCount <= 0) { + otpService.deleteOtp(type, key); + } else { + otpDetails.put(JsonKey.ATTEMPTED_COUNT, attemptedCount + 1); + otpService.updateAttemptCount(otpDetails); + } + ProjectCommonException ex = + new ProjectCommonException( + ResponseCode.otpVerificationFailed.getErrorCode(), + MessageFormat.format( + ResponseCode.otpVerificationFailed.getErrorMessage(), remainingCount), + ResponseCode.CLIENT_ERROR.getResponseCode()); + + ClientErrorResponse response = new ClientErrorResponse(); + response.setException(ex); + response + .getResult() + .put( + MAX_ALLOWED_ATTEMPT, + Integer.parseInt(ProjectUtil.getConfigValue(SUNBIRD_OTP_ALLOWED_ATTEMPT))); + response.getResult().put(REMAINING_ATTEMPT, remainingCount); + sender().tell(response, self()); + } + + private int getRemainingAttemptedCount(Map otpDetails) { + int allowedAttempt = Integer.parseInt(ProjectUtil.getConfigValue(SUNBIRD_OTP_ALLOWED_ATTEMPT)); + int attemptedCount = (int) otpDetails.get(JsonKey.ATTEMPTED_COUNT); + return (allowedAttempt - (attemptedCount + 1)); + } + + private void sendOTP(Request request, String otp, String key) { + Request sendOtpRequest = new Request(); + sendOtpRequest.getRequest().putAll(request.getRequest()); + sendOtpRequest.getRequest().put(JsonKey.KEY, key); + sendOtpRequest.getRequest().put(JsonKey.OTP, otp); + sendOtpRequest.setOperation(ActorOperations.SEND_OTP.getValue()); + tellToAnother(sendOtpRequest); + } + + private String getKey(String type, Request request) { + String key = (String) request.getRequest().get(JsonKey.KEY); + if (JsonKey.EMAIL.equalsIgnoreCase(type) && key != null) { + return key.toLowerCase(); + } + return key; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/SendOTPActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/SendOTPActor.java new file mode 100644 index 0000000000..5f7179ce6e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/SendOTPActor.java @@ -0,0 +1,93 @@ +package org.sunbird.learner.actors.otp; + +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.datasecurity.impl.LogMaskServiceImpl; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.OTPUtil; + +@ActorConfig( + tasks = {}, + asyncTasks = {"sendOTP"} +) +public class SendOTPActor extends BaseActor { + public static final String RESET_PASSWORD = "resetPassword"; + private LogMaskServiceImpl logMaskService = new LogMaskServiceImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + if (ActorOperations.SEND_OTP.getValue().equals(request.getOperation())) { + sendOTP(request); + } else { + onReceiveUnsupportedOperation("SendOTPActor"); + } + } + + private void sendOTP(Request request) { + String type = (String) request.getRequest().get(JsonKey.TYPE); + String key = (String) request.getRequest().get(JsonKey.KEY); + String otp = (String) request.getRequest().get(JsonKey.OTP); + String template = (String) request.getRequest().get(JsonKey.TEMPLATE_ID); + if (JsonKey.EMAIL.equalsIgnoreCase(type) + || JsonKey.PREV_USED_EMAIL.equalsIgnoreCase(type) + || JsonKey.RECOVERY_EMAIL.equalsIgnoreCase(type)) { + String userId = (String) request.get(JsonKey.USER_ID); + ProjectLogger.log( + "SendOTPActor:sendOTP : Sending OTP via email for Key = " + + logMaskService.maskEmail(key) + + " or userId " + + userId, + LoggerEnum.INFO.name()); + sendOTPViaEmail(key, otp, userId, template); + } else if (JsonKey.PHONE.equalsIgnoreCase(type) + || JsonKey.PREV_USED_PHONE.equalsIgnoreCase(type) + || JsonKey.RECOVERY_PHONE.equalsIgnoreCase(type)) { + ProjectLogger.log( + "SendOTPActor:sendOTP : Sending OTP via sms for Key = " + logMaskService.maskPhone(key), + LoggerEnum.INFO.name()); + sendOTPViaSMS(key, otp, template); + } else { + ProjectLogger.log("SendOTPActor:sendOTP : No Email/Phone provided.", LoggerEnum.INFO.name()); + } + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + } + + private void sendOTPViaEmail(String key, String otp, String otpType, String template) { + Map emailTemplateMap = new HashMap<>(); + emailTemplateMap.put(JsonKey.EMAIL, key); + emailTemplateMap.put(JsonKey.OTP, otp); + emailTemplateMap.put(JsonKey.OTP_EXPIRATION_IN_MINUTES, OTPUtil.getOTPExpirationInMinutes()); + emailTemplateMap.put(JsonKey.TEMPLATE_ID, template); + Request emailRequest = null; + if (StringUtils.isBlank(otpType)) { + emailRequest = OTPUtil.sendOTPViaEmail(emailTemplateMap); + } else { + emailRequest = OTPUtil.sendOTPViaEmail(emailTemplateMap, RESET_PASSWORD); + } + ProjectLogger.log( + "SendOTPActor:sendOTP : Calling EmailServiceActor for Key = " + + logMaskService.maskEmail(key), + LoggerEnum.INFO.name()); + tellToAnother(emailRequest); + } + + private void sendOTPViaSMS(String key, String otp, String template) { + Map otpMap = new HashMap<>(); + otpMap.put(JsonKey.PHONE, key); + otpMap.put(JsonKey.OTP, otp); + otpMap.put(JsonKey.TEMPLATE_ID, template); + otpMap.put(JsonKey.OTP_EXPIRATION_IN_MINUTES, OTPUtil.getOTPExpirationInMinutes()); + ProjectLogger.log( + "SendOTPActor:sendOTPViaSMS : Calling OTPUtil.sendOTPViaSMS for Key = " + + logMaskService.maskPhone(key), + LoggerEnum.INFO.name()); + OTPUtil.sendOTPViaSMS(otpMap); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/dao/OTPDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/dao/OTPDao.java new file mode 100644 index 0000000000..ec07d0fed2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/dao/OTPDao.java @@ -0,0 +1,34 @@ +package org.sunbird.learner.actors.otp.dao; + +import java.util.Map; + +public interface OTPDao { + + /** + * Fetch OTP details based on type (phone / email) and key. + * + * @param type Type of key (phone / email) + * @param key Phone number or email address + * @return OTP details + */ + Map getOTPDetails(String type, String key); + + /** + * Insert OTP details for given type (phone / email) and key + * + * @param type Type of key (phone / email) + * @param key Phone number or email address + * @param otp Generated OTP + */ + void insertOTPDetails(String type, String key, String otp); + + /** + * this method will be used to delete the Otp + * + * @param type + * @param key + */ + void deleteOtp(String type, String key); + + void updateAttemptCount(Map otpDetails); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/dao/impl/OTPDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/dao/impl/OTPDaoImpl.java new file mode 100644 index 0000000000..02823e9406 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/dao/impl/OTPDaoImpl.java @@ -0,0 +1,94 @@ +package org.sunbird.learner.actors.otp.dao.impl; + +import java.sql.Timestamp; +import java.util.*; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.otp.dao.OTPDao; +import org.sunbird.learner.util.Util; + +public class OTPDaoImpl implements OTPDao { + + private static final String TABLE_NAME = JsonKey.OTP; + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static volatile OTPDao otpDao; + + public static OTPDao getInstance() { + if (otpDao == null) { + synchronized (OTPDaoImpl.class) { + if (otpDao == null) { + otpDao = new OTPDaoImpl(); + } + } + } + return otpDao; + } + + @Override + @SuppressWarnings("unchecked") + public Map getOTPDetails(String type, String key) { + Map request = new HashMap<>(); + request.put(JsonKey.TYPE, type); + request.put(JsonKey.KEY, key); + List fields = new ArrayList<>(); + fields.add(JsonKey.TYPE); + fields.add(JsonKey.KEY); + fields.add(JsonKey.ATTEMPTED_COUNT); + fields.add(JsonKey.CREATED_ON); + fields.add(JsonKey.OTP); + List ttlFields = new ArrayList<>(); + ttlFields.add(JsonKey.OTP); + Response result = + cassandraOperation.getRecordWithTTLById( + Util.KEY_SPACE_NAME, TABLE_NAME, request, ttlFields, fields); + List> otpMapList = (List>) result.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(otpMapList)) { + return null; + } + return otpMapList.get(0); + } + + @Override + public void insertOTPDetails(String type, String key, String otp) { + Map request = new HashMap<>(); + request.put(JsonKey.TYPE, type); + request.put(JsonKey.KEY, key); + request.put(JsonKey.OTP, otp); + request.put(JsonKey.ATTEMPTED_COUNT, 0); + request.put(JsonKey.CREATED_ON, new Timestamp(Calendar.getInstance().getTimeInMillis())); + String expirationInSeconds = + PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_OTP_EXPIRATION); + int ttl = Integer.valueOf(expirationInSeconds); + cassandraOperation.insertRecordWithTTL(Util.KEY_SPACE_NAME, TABLE_NAME, request, ttl); + } + + @Override + public void deleteOtp(String type, String key) { + Map compositeKeyMap = new HashMap<>(); + compositeKeyMap.put(JsonKey.TYPE, type); + compositeKeyMap.put(JsonKey.KEY, key); + cassandraOperation.deleteRecord(JsonKey.SUNBIRD, TABLE_NAME, compositeKeyMap); + ProjectLogger.log("OTPDaoImpl:deleteOtp:otp deleted", LoggerEnum.INFO.name()); + } + + @Override + public void updateAttemptCount(Map otpDetails) { + Map request = new HashMap<>(); + int ttl = (int) otpDetails.get("otp_ttl"); + otpDetails.remove("otp_ttl"); + request.putAll(otpDetails); + request.remove(JsonKey.KEY); + request.remove(JsonKey.TYPE); + Map compositeKey = new HashMap<>(); + compositeKey.put(JsonKey.TYPE, otpDetails.get(JsonKey.TYPE)); + compositeKey.put(JsonKey.KEY, otpDetails.get(JsonKey.KEY)); + cassandraOperation.updateRecordWithTTL( + Util.KEY_SPACE_NAME, TABLE_NAME, request, compositeKey, ttl); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/service/OTPService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/service/OTPService.java new file mode 100644 index 0000000000..37046bc509 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/otp/service/OTPService.java @@ -0,0 +1,69 @@ +package org.sunbird.learner.actors.otp.service; + +import java.io.StringWriter; +import java.util.Map; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.runtime.parser.node.SimpleNode; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.learner.actors.notificationservice.dao.EmailTemplateDao; +import org.sunbird.learner.actors.notificationservice.dao.impl.EmailTemplateDaoImpl; +import org.sunbird.learner.actors.otp.dao.OTPDao; +import org.sunbird.learner.actors.otp.dao.impl.OTPDaoImpl; + +public class OTPService { + + private static OTPDao otpDao = OTPDaoImpl.getInstance(); + private static EmailTemplateDao emailTemplateDao = EmailTemplateDaoImpl.getInstance(); + + public static String getOTPSMSTemplate(String templateName) { + return emailTemplateDao.getTemplate(templateName); + } + + public Map getOTPDetails(String type, String key) { + return otpDao.getOTPDetails(type, key); + } + + public void insertOTPDetails(String type, String key, String otp) { + otpDao.insertOTPDetails(type, key, otp); + } + + public void deleteOtp(String type, String key) { + otpDao.deleteOtp(type, key); + } + + public static String getSmsBody(String templateFile, Map smsTemplate) { + try { + String sms = getOTPSMSTemplate(templateFile); + RuntimeServices rs = RuntimeSingleton.getRuntimeServices(); + SimpleNode sn = rs.parse(sms, "Sms Information"); + Template t = new Template(); + t.setRuntimeServices(rs); + t.setData(sn); + t.initDocument(); + VelocityContext context = new VelocityContext(); + context.put(JsonKey.OTP, smsTemplate.get(JsonKey.OTP)); + context.put( + JsonKey.OTP_EXPIRATION_IN_MINUTES, smsTemplate.get(JsonKey.OTP_EXPIRATION_IN_MINUTES)); + context.put( + JsonKey.INSTALLATION_NAME, + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_INSTALLATION_DISPLAY_NAME)); + + StringWriter writer = new StringWriter(); + t.merge(context, writer); + return writer.toString(); + } catch (Exception ex) { + ProjectLogger.log( + "OTPService:getSmsBody: Exception occurred with error message = " + ex.getMessage(), ex); + } + return ""; + } + + public void updateAttemptCount(Map otpDetails) { + otpDao.updateAttemptCount(otpDetails); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/dao/RoleDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/dao/RoleDao.java new file mode 100644 index 0000000000..05b20b3a69 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/dao/RoleDao.java @@ -0,0 +1,14 @@ +package org.sunbird.learner.actors.role.dao; + +import java.util.List; +import org.sunbird.models.role.Role; + +public interface RoleDao { + + /** + * Get list of roles. + * + * @return List of all roles. + */ + List getRoles(); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/dao/impl/RoleDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/dao/impl/RoleDaoImpl.java new file mode 100644 index 0000000000..ec0f2a3857 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/dao/impl/RoleDaoImpl.java @@ -0,0 +1,42 @@ +package org.sunbird.learner.actors.role.dao.impl; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import java.util.Map; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.role.dao.RoleDao; +import org.sunbird.learner.util.Util; +import org.sunbird.models.role.Role; + +public class RoleDaoImpl implements RoleDao { + + private static final String TABLE_NAME = "role"; + private ObjectMapper mapper = new ObjectMapper(); + private static RoleDao roleDao; + + public static RoleDao getInstance() { + if (roleDao == null) { + roleDao = new RoleDaoImpl(); + } + return roleDao; + } + + @SuppressWarnings("unchecked") + @Override + public List getRoles() { + Response roleResults = getCassandraOperation().getAllRecords(Util.KEY_SPACE_NAME, TABLE_NAME); + TypeReference> roleMapType = new TypeReference>() {}; + List> roleMapList = + (List>) roleResults.get(JsonKey.RESPONSE); + List roleList = mapper.convertValue(roleMapList, roleMapType); + return roleList; + } + + public CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/dao/RoleGroupDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/dao/RoleGroupDao.java new file mode 100644 index 0000000000..7a88ce5943 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/dao/RoleGroupDao.java @@ -0,0 +1,14 @@ +package org.sunbird.learner.actors.role.group.dao; + +import java.util.List; +import org.sunbird.models.role.group.RoleGroup; + +public interface RoleGroupDao { + + /** + * Get list of role groups. + * + * @return List of role groups. + */ + List getRoleGroups(); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/dao/impl/RoleGroupDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/dao/impl/RoleGroupDaoImpl.java new file mode 100644 index 0000000000..b56f0be5c4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/dao/impl/RoleGroupDaoImpl.java @@ -0,0 +1,42 @@ +package org.sunbird.learner.actors.role.group.dao.impl; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import java.util.Map; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.role.group.dao.RoleGroupDao; +import org.sunbird.models.role.group.RoleGroup; + +public class RoleGroupDaoImpl implements RoleGroupDao { + + private ObjectMapper mapper = new ObjectMapper(); + private static RoleGroupDao roleGroupDao; + private static final String KEYSPACE_NAME = "sunbird"; + private static final String TABLE_NAME = "role_group"; + + public static RoleGroupDao getInstance() { + if (roleGroupDao == null) { + roleGroupDao = new RoleGroupDaoImpl(); + } + return roleGroupDao; + } + + @SuppressWarnings("unchecked") + @Override + public List getRoleGroups() { + Response roleGroupResults = getCassandraOperation().getAllRecords(KEYSPACE_NAME, TABLE_NAME); + TypeReference> roleGroupType = new TypeReference>() {}; + List> roleGroupMapList = + (List>) roleGroupResults.get(JsonKey.RESPONSE); + List roleGroupList = mapper.convertValue(roleGroupMapList, roleGroupType); + return roleGroupList; + } + + public CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/service/RoleGroupService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/service/RoleGroupService.java new file mode 100644 index 0000000000..90bf51f386 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/group/service/RoleGroupService.java @@ -0,0 +1,38 @@ +package org.sunbird.learner.actors.role.group.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.learner.actors.role.group.dao.RoleGroupDao; +import org.sunbird.learner.actors.role.group.dao.impl.RoleGroupDaoImpl; +import org.sunbird.models.role.group.RoleGroup; + +public class RoleGroupService { + + private static RoleGroupDao roleGroupDao = RoleGroupDaoImpl.getInstance(); + + public static Map getRoleGroupMap(String roleName) { + Map response = new HashMap<>(); + List roleGroupList = roleGroupDao.getRoleGroups(); + + if (CollectionUtils.isNotEmpty(roleGroupList)) { + for (RoleGroup roleGroup : roleGroupList) { + if (roleGroup.getId().equals(roleName)) { + response.put(JsonKey.ID, roleGroup.getId()); + response.put(JsonKey.NAME, roleGroup.getName()); + response.put( + JsonKey.URL_ACTION_ID, + roleGroup.getUrlActionIds() != null + ? roleGroup.getUrlActionIds() + : new ArrayList<>()); + return response; + } + } + } + + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/service/RoleService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/service/RoleService.java new file mode 100644 index 0000000000..53f8b8aa43 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/role/service/RoleService.java @@ -0,0 +1,89 @@ +package org.sunbird.learner.actors.role.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.actors.role.dao.RoleDao; +import org.sunbird.learner.actors.role.dao.impl.RoleDaoImpl; +import org.sunbird.learner.actors.role.group.service.RoleGroupService; +import org.sunbird.learner.actors.url.action.service.UrlActionService; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.models.role.Role; + +public class RoleService { + + private static RoleDao roleDao = RoleDaoImpl.getInstance(); + + @SuppressWarnings("unchecked") + public static Response getUserRoles() { + Response response = new Response(); + List> roleMapList = new ArrayList<>(); + List roleList = roleDao.getRoles(); + + if (CollectionUtils.isNotEmpty(roleList)) { + + for (Role role : roleList) { + Map roleMap = new HashMap<>(); + roleMap.put(JsonKey.ID, role.getId()); + roleMap.put(JsonKey.NAME, role.getName()); + List roleGroupIdList = role.getRoleGroupId(); + + List> actionGroupMapList = new ArrayList<>(); + roleMap.put(JsonKey.ACTION_GROUPS, actionGroupMapList); + + Map actionGroupMap = null; + for (String roleGroupId : roleGroupIdList) { + Map roleGroupMap = RoleGroupService.getRoleGroupMap(roleGroupId); + + actionGroupMap = new HashMap<>(); + actionGroupMap.put(JsonKey.ID, roleGroupMap.get(JsonKey.ID)); + actionGroupMap.put(JsonKey.NAME, roleGroupMap.get(JsonKey.NAME)); + + List> urlActionMapList = new ArrayList<>(); + List urlActionIds = (List) roleGroupMap.get(JsonKey.URL_ACTION_ID); + + for (String urlActionId : urlActionIds) { + urlActionMapList.add(UrlActionService.getUrlActionMap(urlActionId)); + } + + if (actionGroupMap.containsKey(JsonKey.ACTIONS)) { + List> actionsMap = + (List>) actionGroupMap.get(JsonKey.ACTIONS); + actionsMap.addAll(urlActionMapList); + } else { + actionGroupMap.put(JsonKey.ACTIONS, urlActionMapList); + } + + actionGroupMapList.add(actionGroupMap); + } + + roleMapList.add(roleMap); + } + } + + response.getResult().put(JsonKey.ROLES, roleMapList); + return response; + } + + public static void validateRoles(List roleList) { + Map roleMap = DataCacheHandler.getRoleMap(); + + if (MapUtils.isNotEmpty(roleMap)) { + for (String role : roleList) { + if (null == roleMap.get(role.trim())) { + throw new ProjectCommonException( + ResponseCode.invalidRole.getErrorCode(), + ResponseCode.invalidRole.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/FuzzyMatcher.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/FuzzyMatcher.java new file mode 100644 index 0000000000..93aa482805 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/FuzzyMatcher.java @@ -0,0 +1,116 @@ +package org.sunbird.learner.actors.search; + +import com.intuit.fuzzymatcher.component.MatchService; +import com.intuit.fuzzymatcher.domain.Document; +import com.intuit.fuzzymatcher.domain.Element; +import com.intuit.fuzzymatcher.domain.ElementType; +import com.intuit.fuzzymatcher.domain.Match; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +public class FuzzyMatcher { + + private static final String nameToBeMatchedId = "0"; + private static final String ENCODING = "UTF-8"; + + public static List matchDoc( + String nameToBeMatched, Map attributesValueMap) { + Document doc = null; + try { + doc = + new Document.Builder(nameToBeMatchedId) + .addElement( + new Element.Builder() + .setType(ElementType.TEXT) + .setValue(URLEncoder.encode(nameToBeMatched, ENCODING)) + .createElement()) + .setThreshold(getFuzzyThreshold()) + .createDocument(); + } catch (UnsupportedEncodingException e) { + ProjectLogger.log( + "FuzzyMatcher:matchDoc: Error occured dueing encoding of data " + e, + LoggerEnum.ERROR.name()); + } + return match(doc, prepareDocumentFromSearchMap(attributesValueMap)); + } + + private static List match(Document doc, List docList) { + List matchedKeys = new ArrayList<>(); + MatchService matchService = new MatchService(); + Map>> map = matchService.applyMatch(doc, docList); + Iterator>>> itr = map.entrySet().iterator(); + List> matchList = null; + while (itr.hasNext()) { + Map.Entry>> entry = itr.next(); + matchList = entry.getValue(); + for (int i = 0; i < matchList.size(); i++) { + Match matchDoc = matchList.get(i); + matchedKeys.add(matchDoc.getMatchedWith().getKey()); + ProjectLogger.log( + String.format( + "%s:%s:document matched doc: %s with id %s", + "FuzzyMatcher", "match", matchDoc, matchDoc.getMatchedWith().getKey()), + LoggerEnum.INFO.name()); + } + } + return matchedKeys; + } + + private static List prepareDocumentFromSearchMap( + Map attributesValueMap) { + List docList = new ArrayList<>(); + attributesValueMap + .entrySet() + .stream() + .forEach( + result -> { + String[] attributes = result.getValue().split(" "); + ProjectLogger.log( + "FuzzyMatcher:prepareDocumentFromSearchMap: the name got for match " + .concat(result.getValue() + "") + .concat("spliited name size is " + attributes.length), + LoggerEnum.INFO.name()); + for (int i = 0; i < attributes.length; i++) { + try { + docList.add( + new Document.Builder(result.getKey()) + .addElement( + new Element.Builder() + .setType(ElementType.TEXT) + .setValue(URLEncoder.encode(attributes[i].trim(), ENCODING)) + .createElement()) + .createDocument()); + } catch (UnsupportedEncodingException e) { + ProjectLogger.log( + "Error occured during prepareDocumentFromSearchMap " + e, + LoggerEnum.ERROR.name()); + } + } + }); + ProjectLogger.log( + String.format( + "%s:%s:document size prepared to be matched is %s ", + "FuzzyMatcher", "prepareDocumentFromSearchMap", docList.size()), + LoggerEnum.INFO.name()); + return docList; + } + + private static float getFuzzyThreshold() { + String threshold = + PropertiesCache.getInstance().readProperty(JsonKey.SUNBIRD_FUZZY_SEARCH_THRESHOLD); + ProjectLogger.log( + String.format( + "%s:%s:the threshold got for Fuzzy search is %s", + "FuzzyMatcher", "getFuzzyThreshold", threshold), + LoggerEnum.INFO.name()); + return Float.parseFloat(threshold); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/FuzzySearchManager.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/FuzzySearchManager.java new file mode 100644 index 0000000000..9b5ab89b06 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/FuzzySearchManager.java @@ -0,0 +1,105 @@ +package org.sunbird.learner.actors.search; + +import java.util.*; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; + +public class FuzzySearchManager { + private Map fuzzySearchMap; + private List> searchMap; + + private FuzzySearchManager( + Map fuzzySearchMap, List> searchMap) { + this.fuzzySearchMap = fuzzySearchMap; + this.searchMap = searchMap; + } + + public static FuzzySearchManager getInstance( + Map fuzzySearchMap, List> searchMap) { + return new FuzzySearchManager(fuzzySearchMap, searchMap); + } + + protected List> startFuzzySearch() { + HashSet resultSet = new HashSet<>(); + fuzzySearchMap + .entrySet() + .forEach( + map -> { + validateKeyInFuzzyMap(map.getKey()); + String[] splittedName = map.getValue().toString().split(" "); + for (int i = 0; i < splittedName.length; i++) { + resultSet.addAll( + FuzzyMatcher.matchDoc( + splittedName[i].trim(), getFuzzyAttributeFromMap(map.getKey()))); + } + }); + ProjectLogger.log( + String.format( + "%s:%s:the size of resultSet i.e number of searches found is %s", + this.getClass().getSimpleName(), "startFuzzySearch", resultSet.size()), + LoggerEnum.INFO.name()); + return prepareResponseList(resultSet); + } + + private void validateKeyInFuzzyMap(String key) { + Map resultMap = searchMap.get(0); + if (!resultMap.keySet().contains(key)) { + ProjectLogger.log( + String.format( + "%s:%s:key not found in searchMap %s", + this.getClass().getSimpleName(), "getFuzzyAttributeFromMap", key), + LoggerEnum.ERROR.name()); + ProjectCommonException.throwClientErrorException(ResponseCode.invalidRequestData); + } + } + + private Map getFuzzyAttributeFromMap(String key) { + Map attributesValueMap = new HashMap<>(); + searchMap + .stream() + .forEach( + result -> { + Map resultMap = (Map) result; + attributesValueMap.put( + (String) resultMap.get(JsonKey.ID), (String) resultMap.get(key)); + }); + ProjectLogger.log( + String.format( + "%s:%s:the prepared Map for fuzzy search %s", + this.getClass().getSimpleName(), + "getFuzzyAttributeFromMap", + Collections.singleton(attributesValueMap.toString())), + LoggerEnum.INFO.name()); + return attributesValueMap; + } + + private List> fetchResultSetFromSearchMap(HashSet fuzzyResultSet) { + + List> responseList = new ArrayList<>(); + + searchMap + .stream() + .forEach( + result -> { + Map resultMap = (Map) result; + if (fuzzyResultSet.contains(resultMap.get(JsonKey.ID))) { + responseList.add(resultMap); + } + }); + ProjectLogger.log( + String.format( + "%s:%s:returning only fuzzy matched result, the size of List of map is %s", + this.getClass().getSimpleName(), "fetchResultSetFromSearchMap", responseList.size()), + LoggerEnum.INFO.name()); + return responseList; + } + + private List> prepareResponseList(HashSet fuzzyResultSet) { + return fuzzyResultSet.size() != 0 + ? fetchResultSetFromSearchMap(fuzzyResultSet) + : new ArrayList<>(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/SearchHandlerActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/SearchHandlerActor.java new file mode 100644 index 0000000000..706bef80ea --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/SearchHandlerActor.java @@ -0,0 +1,344 @@ +package org.sunbird.learner.actors.search; + +import akka.dispatch.Mapper; +import akka.pattern.Patterns; +import java.util.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.actorutil.org.impl.OrganisationClientImpl; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.dto.SearchDTO; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.models.organisation.Organisation; +import org.sunbird.telemetry.util.TelemetryWriter; +import scala.concurrent.Future; + +/** + * This class will handle search operation for all different type of index and types + * + * @author Manzarul + */ +@ActorConfig( + tasks = {"compositeSearch"}, + asyncTasks = {} +) +public class SearchHandlerActor extends BaseActor { + + private OrganisationClient orgClient = new OrganisationClientImpl(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public void onReceive(Request request) throws Throwable { + request.toLower(); + Util.initializeContext(request, TelemetryEnvKey.USER); + if (request.getOperation().equalsIgnoreCase(ActorOperations.COMPOSITE_SEARCH.getValue())) { + Map searchQueryMap = request.getRequest(); + Object objectType = + ((Map) searchQueryMap.get(JsonKey.FILTERS)).remove(JsonKey.OBJECT_TYPE); + String filterObjectType = ""; + if (objectType != null && objectType instanceof List) { + List types = (List) objectType; + filterObjectType = types.get(0); + } + if (EsType.organisation.getTypeName().equalsIgnoreCase(filterObjectType)) { + SearchDTO searchDto = Util.createSearchDto(searchQueryMap); + handleOrgSearchAsyncRequest( + EsType.organisation.getTypeName(), searchDto, request.getContext()); + } else if (EsType.user.getTypeName().equalsIgnoreCase(filterObjectType)) { + handleUserSearch(request, searchQueryMap, filterObjectType); + } + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void handleUserSearch( + Request request, Map searchQueryMap, String filterObjectType) + throws Exception { + UserUtility.encryptUserSearchFilterQueryData(searchQueryMap); + extractOrFilter(searchQueryMap); + SearchDTO searchDto = Util.createSearchDto(searchQueryMap); + searchDto.setExcludedFields(Arrays.asList(ProjectUtil.excludes)); + Future> resultF = esService.search(searchDto, filterObjectType); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + Response response = new Response(); + // this fuzzy search Logic + if (((List>) result.get(JsonKey.CONTENT)).size() != 0 + && isFuzzySearchRequired(searchQueryMap)) { + List> responseList = + getResponseOnFuzzyRequest( + getFuzzyFilterMap(searchQueryMap), + (List>) result.get(JsonKey.CONTENT)); + if (responseList.size() != 0) { + result.replace(JsonKey.COUNT, responseList.size()); + result.replace(JsonKey.CONTENT, responseList); + } else { + throw new ProjectCommonException( + ResponseCode.PARTIAL_SUCCESS_RESPONSE.getErrorCode(), + String.format(ResponseMessage.Message.PARAM_NOT_MATCH, JsonKey.NAME.toUpperCase()), + ResponseCode.PARTIAL_SUCCESS_RESPONSE.getResponseCode()); + } + } + // Decrypt the data + if (EsType.user.getTypeName().equalsIgnoreCase(filterObjectType)) { + List> userMapList = + (List>) result.get(JsonKey.CONTENT); + for (Map userMap : userMapList) { + UserUtility.decryptUserDataFrmES(userMap); + userMap.remove(JsonKey.ENC_EMAIL); + userMap.remove(JsonKey.ENC_PHONE); + } + String requestedFields = (String) request.getContext().get(JsonKey.FIELDS); + updateUserDetailsWithOrgName(requestedFields, userMapList); + } + if (result == null) { + result = new HashMap<>(); + } + response.put(JsonKey.RESPONSE, result); + sender().tell(response, self()); + generateSearchTelemetryEvent(searchDto, filterObjectType, result, request.getContext()); + } + + private void handleOrgSearchAsyncRequest( + String indexType, SearchDTO searchDto, Map context) { + Future> futureResponse = esService.search(searchDto, indexType); + Future response = + futureResponse.map( + new Mapper, Response>() { + @Override + public Response apply(Map responseMap) { + ProjectLogger.log( + "SearchHandlerActor:handleOrgSearchAsyncRequest org search call ", + LoggerEnum.INFO); + Response response = new Response(); + response.put(JsonKey.RESPONSE, responseMap); + return response; + } + }, + getContext().dispatcher()); + Patterns.pipe(response, getContext().dispatcher()).to(sender()); + Request telemetryReq = new Request(); + telemetryReq.getRequest().put("context", context); + telemetryReq.getRequest().put("searchFResponse", response); + telemetryReq.getRequest().put("indexType", indexType); + telemetryReq.getRequest().put("searchDto", searchDto); + telemetryReq.setOperation("generateSearchTelemetry"); + tellToAnother(telemetryReq); + } + + @SuppressWarnings("unchecked") + private void updateUserDetailsWithOrgName( + String requestedFields, List> userMapList) { + Map orgMap = null; + if (StringUtils.isNotBlank(requestedFields)) { + try { + List fields = Arrays.asList(requestedFields.toLowerCase().split(",")); + List filteredRequestedFields = new ArrayList<>(); + List supportedFields = Arrays.asList(JsonKey.ID, JsonKey.ORG_NAME); + fields + .stream() + .forEach( + rField -> { + for (String sField : supportedFields) { + if (sField.equalsIgnoreCase(rField)) { + filteredRequestedFields.add(sField); + break; + } + } + }); + if (filteredRequestedFields.isEmpty()) { + return; + } + if (!filteredRequestedFields.contains(JsonKey.ID)) { + filteredRequestedFields.add(JsonKey.ID); + } + orgMap = fetchOrgDetails(userMapList, filteredRequestedFields); + if (fields.contains(JsonKey.ORG_NAME.toLowerCase())) { + Map filteredOrg = new HashMap<>(orgMap); + userMapList + .stream() + .forEach( + userMap -> { + String rootOrgId = (String) userMap.get(JsonKey.ROOT_ORG_ID); + if (StringUtils.isNotBlank(rootOrgId)) { + Organisation org = filteredOrg.get(rootOrgId); + if (null != org) { + userMap.put(JsonKey.ROOT_ORG_NAME, org.getOrgName()); + } + } + List> userOrgList = + (List>) userMap.get(JsonKey.ORGANISATIONS); + if (CollectionUtils.isNotEmpty(userOrgList)) { + userOrgList + .stream() + .forEach( + userOrg -> { + String userOrgId = (String) userOrg.get(JsonKey.ORGANISATION_ID); + if (StringUtils.isNotBlank(userOrgId)) { + Organisation org = filteredOrg.get(userOrgId); + if (null != org) { + userOrg.put(JsonKey.ORG_NAME, org.getOrgName()); + } + } + }); + } + }); + } + } catch (Exception ex) { + ProjectLogger.log( + "SearchHandlerActor:updateUserDetailsWithOrgName: Exception occurred with error message = " + + ex.getMessage(), + ex); + } + } + } + + @SuppressWarnings("unchecked") + private Map fetchOrgDetails( + List> userMapList, List filteredRequestedFileds) { + Set orgIdList = new HashSet<>(); + userMapList + .stream() + .forEach( + userMap -> { + String rootOrgId = (String) userMap.get(JsonKey.ROOT_ORG_ID); + if (StringUtils.isNotBlank(rootOrgId)) { + orgIdList.add(rootOrgId); + } + List> userOrgList = + (List>) userMap.get(JsonKey.ORGANISATIONS); + if (CollectionUtils.isNotEmpty(userOrgList)) { + userOrgList + .stream() + .forEach( + userOrg -> { + String userOrgId = (String) userOrg.get(JsonKey.ORGANISATION_ID); + if (StringUtils.isNotBlank(userOrgId)) { + orgIdList.add(userOrgId); + } + }); + } + }); + + List orgIds = new ArrayList<>(orgIdList); + List organisations = orgClient.esSearchOrgByIds(orgIds, filteredRequestedFileds); + Map orgMap = new HashMap<>(); + organisations + .stream() + .forEach( + org -> { + orgMap.put(org.getId(), org); + }); + return orgMap; + } + + private void generateSearchTelemetryEvent( + SearchDTO searchDto, String type, Map result, Map context) { + + Map params = new HashMap<>(); + params.put(JsonKey.TYPE, type); + params.put(JsonKey.QUERY, searchDto.getQuery()); + params.put(JsonKey.FILTERS, searchDto.getAdditionalProperties().get(JsonKey.FILTERS)); + params.put(JsonKey.SORT, searchDto.getSortBy()); + params.put(JsonKey.SIZE, result.get(JsonKey.COUNT)); + params.put(JsonKey.TOPN, generateTopnResult(result)); // need to get topn value from + // response + Request req = new Request(); + req.setRequest(telemetryRequestForSearch(context, params)); + TelemetryWriter.write(req); + } + + private List> generateTopnResult(Map result) { + + List> userMapList = (List>) result.get(JsonKey.CONTENT); + Integer topN = + Integer.parseInt(PropertiesCache.getInstance().getProperty(JsonKey.SEARCH_TOP_N)); + + List> list = new ArrayList<>(); + if (topN < userMapList.size()) { + for (int i = 0; i < topN; i++) { + Map m = new HashMap<>(); + m.put(JsonKey.ID, userMapList.get(i).get(JsonKey.ID)); + list.add(m); + } + } else { + + for (int i = 0; i < userMapList.size(); i++) { + Map m = new HashMap<>(); + m.put(JsonKey.ID, userMapList.get(i).get(JsonKey.ID)); + list.add(m); + } + } + return list; + } + + private static Map telemetryRequestForSearch( + Map telemetryContext, Map params) { + Map map = new HashMap<>(); + map.put(JsonKey.CONTEXT, telemetryContext); + map.put(JsonKey.PARAMS, params); + map.put(JsonKey.TELEMETRY_EVENT_TYPE, "SEARCH"); + return map; + } + + /** + * this method will convert the Sunbird required + * fields(source,externalId,userName,provider,loginId,email) into lower case and encrypt PI + * attributes well + * + * @param searchQueryMap + * @throws Exception + */ + private void extractOrFilter(Map searchQueryMap) throws Exception { + Map ORFilterMap = + (Map) + ((Map) (searchQueryMap.get(JsonKey.FILTERS))) + .get(JsonKey.ES_OR_OPERATION); + if (MapUtils.isNotEmpty(ORFilterMap)) { + Arrays.asList( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_API_REQUEST_LOWER_CASE_FIELDS).split(",")) + .stream() + .forEach( + field -> { + if (StringUtils.isNotBlank((String) ORFilterMap.get(field))) { + ORFilterMap.put(field, ((String) ORFilterMap.get(field)).toLowerCase()); + } + }); + UserUtility.encryptUserData(ORFilterMap); + } + } + + private boolean isFuzzySearchRequired(Map searchQueryMap) { + Map fuzzyFilterMap = getFuzzyFilterMap(searchQueryMap); + if (MapUtils.isEmpty(fuzzyFilterMap)) { + return false; + } + return true; + } + + private List> getResponseOnFuzzyRequest( + Map fuzzyFilterMap, List> searchMap) { + return FuzzySearchManager.getInstance(fuzzyFilterMap, searchMap).startFuzzySearch(); + } + + private Map getFuzzyFilterMap(Map searchQueryMap) { + return (Map) + ((Map) (searchQueryMap.get(JsonKey.FILTERS))).get(JsonKey.SEARCH_FUZZY); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/SearchTelemetryGenerator.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/SearchTelemetryGenerator.java new file mode 100644 index 0000000000..61dc13dff4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/search/SearchTelemetryGenerator.java @@ -0,0 +1,120 @@ +package org.sunbird.learner.actors.search; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.dto.SearchDTO; +import org.sunbird.telemetry.util.TelemetryWriter; +import scala.concurrent.Await; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {}, + asyncTasks = {"generateSearchTelemetry"} +) +public class SearchTelemetryGenerator extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + if (request.getOperation().equalsIgnoreCase("generateSearchTelemetry")) { + generateTelemetry(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void generateTelemetry(Request request) { + Future response = (Future) request.getRequest().get("searchFResponse"); + String indexType = (String) request.getRequest().get("indexType"); + SearchDTO searchDto = (SearchDTO) request.getRequest().get("searchDto"); + Map telemetryContext = + (Map) request.getRequest().get("context"); + Response orgSearchResponse = null; + try { + orgSearchResponse = Await.result(response, BaseActor.timeout.duration()); + String[] types = new String[] {indexType}; + Map contentMap = new HashMap<>(); + List contentList = new ArrayList<>(); + if (orgSearchResponse != null + && MapUtils.isNotEmpty(orgSearchResponse.getResult()) + && MapUtils.isNotEmpty( + (Map) orgSearchResponse.getResult().get(JsonKey.RESPONSE))) { + HashMap contentListMap = + (HashMap) orgSearchResponse.getResult().get(JsonKey.RESPONSE); + contentList.add(contentListMap.get(JsonKey.CONTENT)); + if (CollectionUtils.isNotEmpty(contentList)) { + contentMap.put(JsonKey.CONTENT, contentList.get(0)); + contentMap.put( + JsonKey.COUNT, + contentListMap.get(JsonKey.COUNT) != null ? contentListMap.get(JsonKey.COUNT) : 0); + generateSearchTelemetryEvent(searchDto, types, contentMap, telemetryContext); + } + } + } catch (Exception e) { + ProjectLogger.log( + "SearchTelemetryGenerator:generateTelemetry: Error occured in generating Telemetry for orgSearch ", + e, + LoggerEnum.ERROR.name()); + } + } + + private void generateSearchTelemetryEvent( + SearchDTO searchDto, + String[] types, + Map result, + Map telemetryContext) { + + Map params = new HashMap<>(); + params.put(JsonKey.TYPE, String.join(",", types)); + params.put(JsonKey.QUERY, searchDto.getQuery()); + params.put(JsonKey.FILTERS, searchDto.getAdditionalProperties().get(JsonKey.FILTERS)); + params.put(JsonKey.SORT, searchDto.getSortBy()); + params.put(JsonKey.SIZE, result.get(JsonKey.COUNT)); + params.put(JsonKey.TOPN, generateTopnResult(result)); // need to get topn value from + // response + Request req = new Request(); + req.setRequest(telemetryRequestForSearch(telemetryContext, params)); + TelemetryWriter.write(req); + } + + private List> generateTopnResult(Map result) { + + List> userMapList = (List>) result.get(JsonKey.CONTENT); + Integer topN = + Integer.parseInt(PropertiesCache.getInstance().getProperty(JsonKey.SEARCH_TOP_N)); + + List> list = new ArrayList<>(); + if (topN < userMapList.size()) { + for (int i = 0; i < topN; i++) { + Map m = new HashMap<>(); + m.put(JsonKey.ID, userMapList.get(i).get(JsonKey.ID)); + list.add(m); + } + } else { + + for (int i = 0; i < userMapList.size(); i++) { + Map m = new HashMap<>(); + m.put(JsonKey.ID, userMapList.get(i).get(JsonKey.ID)); + list.add(m); + } + } + return list; + } + + private static Map telemetryRequestForSearch( + Map telemetryContext, Map params) { + Map map = new HashMap<>(); + map.put(JsonKey.CONTEXT, telemetryContext); + map.put(JsonKey.PARAMS, params); + map.put(JsonKey.TELEMETRY_EVENT_TYPE, "SEARCH"); + return map; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/UserSkillManagementActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/UserSkillManagementActor.java new file mode 100644 index 0000000000..0652ee2f2c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/UserSkillManagementActor.java @@ -0,0 +1,655 @@ +package org.sunbird.learner.actors.skill; + +import static org.sunbird.learner.util.Util.isNotNull; +import static org.sunbird.learner.util.Util.isNull; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.datasecurity.OneWayHashing; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.skill.dao.UserSkillDao; +import org.sunbird.learner.actors.skill.dao.impl.UserSkillDaoImpl; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.skill.Skill; +import org.sunbird.telemetry.util.TelemetryUtil; +import scala.concurrent.Future; + +/** + * Class to provide functionality for Add and Endorse the user skills . Created by arvind on + * 18/10/17. + */ +@ActorConfig( + tasks = {"addSkill", "getSkill", "getSkillsList", "updateSkill", "addUserSkillEndorsement"}, + asyncTasks = {} +) +public class UserSkillManagementActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static final String REF_SKILLS_DB_ID = "001"; + private UserSkillDao userSkillDao = UserSkillDaoImpl.getInstance(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + Util.initializeContext(request, TelemetryEnvKey.USER); + + switch (operation) { + case "addSkill": + addOrEndorseSkill(request); + break; + case "getSkill": + getSkill(request); + break; + case "getSkillsList": + getSkillsList(); + break; + case "updateSkill": + updateSkill(request); + break; + case "addUserSkillEndorsement": + addUserSkillEndorsement(request); + break; + default: + onReceiveUnsupportedOperation("UserSkillManagementActor"); + } + } + + private void updateSkill(Request actorMessage) { + ProjectLogger.log( + "UserSkillManagementActor: updateSkill called", + actorMessage.getRequest(), + LoggerEnum.DEBUG.name()); + String userId = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY); + getUser(userId, JsonKey.USER_ID); + List newUserSkillsSet = (List) actorMessage.getRequest().get(JsonKey.SKILLS); + + Map result = findUserSkills(userId); + if (result.isEmpty() || ((List>) result.get(JsonKey.CONTENT)).isEmpty()) { + saveUserSkill(newUserSkillsSet, userId); + } else { + List> searchedUserList = + (List>) result.get(JsonKey.CONTENT); + + Map userMap = new HashMap(); + userMap = searchedUserList.get(0); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true); + List> userSkills = + objectMapper.convertValue(userMap.get(JsonKey.SKILLS), List.class); + if (!CollectionUtils.isEmpty(userSkills)) { + List skills = + userSkills + .stream() + .map( + map -> { + return objectMapper.convertValue(map, Skill.class); + }) + .collect(Collectors.toList()); + HashSet currentUserSkillsSet = new HashSet<>(skills); + List commonSkills = + currentUserSkillsSet + .stream() + .flatMap( + skill -> + newUserSkillsSet + .stream() + .filter( + skillName -> { + String id = + OneWayHashing.encryptVal( + userId + + JsonKey.PRIMARY_KEY_DELIMETER + + skillName.toLowerCase()); + return skill.getId().equals(id); + }) + .map(skillName -> skill)) + .collect(Collectors.toList()); + List addedSkillsList = newUserSkillsSet; + HashSet removedSkillsList = currentUserSkillsSet; + + commonSkills.forEach( + skill -> { + if (addedSkillsList.contains(skill.getSkillName())) { + addedSkillsList.remove(skill.getSkillName()); + removedSkillsList.remove(skill); + } + }); + + if (CollectionUtils.isNotEmpty(addedSkillsList)) { + saveUserSkill(addedSkillsList, userId); + } + if (CollectionUtils.isNotEmpty(removedSkillsList)) { + List idList = + removedSkillsList.stream().map(skill -> skill.getId()).collect(Collectors.toList()); + Boolean deleted = userSkillDao.delete(idList); + if (!deleted) { + ProjectLogger.log( + "UserSkillManagementActor:updateSkill: Delete skills failed for " + userId, + idList, + LoggerEnum.ERROR.name()); + } + + updateES(userId); + } + } else { + saveUserSkill(newUserSkillsSet, userId); + } + } + Response response = new Response(); + response.getResult().put(JsonKey.RESULT, "SUCCESS"); + sender().tell(response, self()); + + addTelemetry(userId, actorMessage); + updateMasterSkillsList(newUserSkillsSet); + } + + private void saveUserSkill(List skillSet, String userId) { + for (String skillName : skillSet) { + String id = + OneWayHashing.encryptVal( + userId + JsonKey.PRIMARY_KEY_DELIMETER + skillName.toLowerCase()); + Map userSkillMap = new HashMap<>(); + userSkillMap.put(JsonKey.ID, id); + userSkillMap.put(JsonKey.USER_ID, userId); + userSkillMap.put(JsonKey.SKILL_NAME, skillName); + userSkillMap.put(JsonKey.SKILL_NAME_TO_LOWERCASE, skillName.toLowerCase()); + userSkillMap.put(JsonKey.CREATED_BY, userId); + userSkillMap.put( + JsonKey.CREATED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + userSkillMap.put(JsonKey.LAST_UPDATED_BY, userId); + userSkillMap.put( + JsonKey.LAST_UPDATED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + userSkillMap.put(JsonKey.ENDORSEMENT_COUNT, 0); + userSkillDao.add(userSkillMap); + updateES(userId); + } + } + + private Map findUserSkills(String userId) { + HashMap esDtoMap = new HashMap<>(); + + Map filters = new HashMap<>(); + filters.put(JsonKey.USER_ID, userId); + esDtoMap.put(JsonKey.FILTERS, filters); + List fields = new ArrayList<>(); + fields.add(JsonKey.SKILLS); + esDtoMap.put(JsonKey.FIELDS, fields); + Future> resultF = + esService.search(ElasticSearchHelper.createSearchDTO(esDtoMap), EsType.user.getTypeName()); + return (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + } + + /** Method will return all the list of skills , it is type of reference data ... */ + private void getSkillsList() { + Util.DbInfo skillsListDbInfo = Util.dbInfoMap.get(JsonKey.SKILLS_LIST_DB); + ProjectLogger.log("UserSkillManagementActor:getSkillsList called"); + Map skills = new HashMap<>(); + Response skilldbresponse = + cassandraOperation.getRecordById( + skillsListDbInfo.getKeySpace(), skillsListDbInfo.getTableName(), REF_SKILLS_DB_ID); + List> skillList = + (List>) skilldbresponse.get(JsonKey.RESPONSE); + + if (!skillList.isEmpty()) { + skills = skillList.get(0); + } + Response response = new Response(); + response.getResult().put(JsonKey.SKILLS, skills.get(JsonKey.SKILLS)); + sender().tell(response, self()); + } + + /** + * Method to get the list of skills of the user on basis of UserId ... + * + * @param actorMessage + */ + private void getSkill(Request actorMessage) { + + ProjectLogger.log("UserSkillManagementActor:getSkill called"); + String endorsedUserId = (String) actorMessage.getRequest().get(JsonKey.ENDORSED_USER_ID); + if (StringUtils.isBlank(endorsedUserId)) { + throw new ProjectCommonException( + ResponseCode.endorsedUserIdRequired.getErrorCode(), + ResponseCode.endorsedUserIdRequired.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Map result = findUserSkills(endorsedUserId); + if (result.isEmpty() || ((List>) result.get(JsonKey.CONTENT)).isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidUserId.getErrorCode(), + ResponseCode.invalidUserId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + List> skillList = (List>) result.get(JsonKey.CONTENT); + + Map skillMap = new HashMap(); + if (!skillList.isEmpty()) { + skillMap = skillList.get(0); + } + + Response response = new Response(); + response.getResult().put(JsonKey.SKILLS, skillMap.get(JsonKey.SKILLS)); + sender().tell(response, self()); + } + + /** + * Method to add or endorse the user skill ... + * + * @param actorMessage + */ + private void addOrEndorseSkill(Request actorMessage) { + + ProjectLogger.log("UserSkillManagementActor:endorseSkill called"); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + // object of telemetry event... + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + Util.DbInfo userDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + String endoresedUserId = (String) actorMessage.getRequest().get(JsonKey.ENDORSED_USER_ID); + + List list = (List) actorMessage.getRequest().get(JsonKey.SKILL_NAME); + CopyOnWriteArraySet skillset = new CopyOnWriteArraySet<>(list); + String requestedByUserId = (String) actorMessage.getRequest().get(JsonKey.USER_ID); + if (StringUtils.isBlank(requestedByUserId)) { + requestedByUserId = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY); + } + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: context userId " + + actorMessage.getContext().get(JsonKey.REQUESTED_BY), + LoggerEnum.INFO.name()); + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: context endorsedUserId " + endoresedUserId, + LoggerEnum.INFO.name()); + Response response1 = + cassandraOperation.getRecordById( + userDbInfo.getKeySpace(), userDbInfo.getTableName(), endoresedUserId); + Response response2 = + cassandraOperation.getRecordById( + userDbInfo.getKeySpace(), userDbInfo.getTableName(), requestedByUserId); + List> endoresedList = + (List>) response1.get(JsonKey.RESPONSE); + List> requestedUserList = + (List>) response2.get(JsonKey.RESPONSE); + + // check whether both userid exist or not if not throw exception + if (endoresedList.isEmpty() || requestedUserList.isEmpty()) { + // generate context and params here ... + + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: context Valid User", LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.invalidUserId.getErrorCode(), + ResponseCode.invalidUserId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + Map endoresedMap = endoresedList.get(0); + Map requestedUserMap = requestedUserList.get(0); + + // check whether both belongs to same org or not(check root or id of both users) + // , if not then + // throw exception --- + if (!compareStrings( + (String) endoresedMap.get(JsonKey.ROOT_ORG_ID), + (String) requestedUserMap.get(JsonKey.ROOT_ORG_ID))) { + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: context rootOrg", LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.canNotEndorse.getErrorCode(), + ResponseCode.canNotEndorse.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Util.DbInfo userSkillDbInfo = Util.dbInfoMap.get(JsonKey.USER_SKILL_DB); + for (String skillName : skillset) { + + if (!StringUtils.isBlank(skillName)) { + + // check whether user have already this skill or not - + String id = + OneWayHashing.encryptVal( + endoresedUserId + JsonKey.PRIMARY_KEY_DELIMETER + skillName.toLowerCase()); + Response response = + cassandraOperation.getRecordById( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), id); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + + // prepare correlted object ... + TelemetryUtil.generateCorrelatedObject(id, "skill", null, correlatedObject); + + if (responseList.isEmpty()) { + // means this is first time skill coming so add this one + Map skillMap = new HashMap<>(); + skillMap.put(JsonKey.ID, id); + skillMap.put(JsonKey.USER_ID, endoresedUserId); + skillMap.put(JsonKey.SKILL_NAME, skillName); + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: context skillName " + skillName, + LoggerEnum.INFO.name()); + skillMap.put(JsonKey.SKILL_NAME_TO_LOWERCASE, skillName.toLowerCase()); + // skillMap.put(JsonKey.ADDED_BY, requestedByUserId); + // skillMap.put(JsonKey.ADDED_AT, format.format(new Date())); + Map endoresers = new HashMap<>(); + + List> endorsersList = new ArrayList<>(); + endoresers.put(JsonKey.USER_ID, requestedByUserId); + endoresers.put(JsonKey.ENDORSE_DATE, format.format(new Date())); + endorsersList.add(endoresers); + + skillMap.put(JsonKey.ENDORSERS_LIST, endorsersList); + skillMap.put(JsonKey.ENDORSEMENT_COUNT, 0); + ObjectMapper objectMapper = new ObjectMapper(); + try { + String responseObj = (String) objectMapper.writeValueAsString(skillMap); + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: responseMap while insert" + responseObj, + LoggerEnum.INFO.name()); + + } catch (JsonProcessingException e) { + ProjectLogger.log("Exception while converting", LoggerEnum.INFO); + } + cassandraOperation.insertRecord( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), skillMap); + + updateES(endoresedUserId); + } else { + // skill already exist for user simply update the then check if it is already + // added by + // same user then dont do anything + // otherwise update the existing one ... + + Map responseMap = responseList.get(0); + // check whether requested user has already endoresed to that user or not + List> endoresersList = + (List>) responseMap.get(JsonKey.ENDORSERS_LIST); + boolean flag = false; + for (Map map : endoresersList) { + if (map.get(JsonKey.USER_ID).equalsIgnoreCase(requestedByUserId)) { + flag = true; + break; + } + } + if (flag) { + // donot do anything.. + ProjectLogger.log(requestedByUserId + " has already endorsed the " + endoresedUserId); + } else { + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: context skillName " + skillName, + LoggerEnum.INFO.name()); + Integer endoresementCount = (Integer) responseMap.get(JsonKey.ENDORSEMENT_COUNT) + 1; + Map endorsersMap = new HashMap<>(); + endorsersMap.put(JsonKey.USER_ID, requestedByUserId); + + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: context requestedByUserId " + + requestedByUserId, + LoggerEnum.INFO.name()); + endorsersMap.put(JsonKey.ENDORSE_DATE, format.format(new Date())); + endoresersList.add(endorsersMap); + + responseMap.put(JsonKey.ENDORSERS_LIST, endoresersList); + responseMap.put(JsonKey.ENDORSEMENT_COUNT, endoresementCount); + /* + *Logs + * */ + ObjectMapper objectMapper = new ObjectMapper(); + try { + String responseObj = (String) objectMapper.writeValueAsString(responseMap); + ProjectLogger.log( + "UserSkillManagementActor:endorseSkill: responseMap while update" + responseObj, + LoggerEnum.INFO.name()); + + } catch (JsonProcessingException e) { + ProjectLogger.log("Exception while converting", LoggerEnum.INFO); + } + + cassandraOperation.updateRecord( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), responseMap); + updateES(endoresedUserId); + } + } + } else { + skillset.remove(skillName); + } + } + + Response response3 = new Response(); + response3.getResult().put(JsonKey.RESULT, "SUCCESS"); + sender().tell(response3, self()); + + addTelemetry(endoresedUserId, actorMessage); + + updateMasterSkillsList(new ArrayList<>(skillset)); + } + + private void addUserSkillEndorsement(Request request) { + String skillName = (String) request.getRequest().get(JsonKey.SKILL_NAME); + String endorsedUserId = (String) request.getRequest().get(JsonKey.ENDORSED_USER_ID); + String requestedUserId = (String) request.getRequest().get(JsonKey.USER_ID); + String skillId = + OneWayHashing.encryptVal( + endorsedUserId + JsonKey.PRIMARY_KEY_DELIMETER + skillName.toLowerCase()); + validateUserRootOrg(requestedUserId, endorsedUserId); + Skill skill = userSkillDao.read(skillId); + if (null == skill) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ResponseCode.invalidParameterValue.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + skillName, + JsonKey.SKILL_NAME); + } + String endorsersId = (String) request.getRequest().get(JsonKey.USER_ID); + String endorsedId = (String) request.getRequest().get(JsonKey.ENDORSED_USER_ID); + addEndorsement(skill, endorsedId, endorsersId); + addTelemetry(endorsersId, request); + } + + private void addEndorsement(Skill skill, String endorsedId, String endorsersId) { + + List> endorsersList = skill.getEndorsersList(); + skill = updateEndorsersList(skill, endorsersList, endorsersId, endorsedId); + userSkillDao.update(skill); + updateES(endorsedId); + Response response = new Response(); + response.getResult().put(JsonKey.RESULT, "SUCCESS"); + sender().tell(response, self()); + } + + private Skill updateEndorsersList( + Skill skill, + List> endorsersList, + String endorsersId, + String endorsedId) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + HashMap endorsers = new HashMap<>(); + if (CollectionUtils.isEmpty(endorsersList)) { + endorsers.put(JsonKey.USER_ID, endorsersId); + endorsers.put(JsonKey.ENDORSE_DATE, format.format(new Date())); + skill.setEndorsementCount(1); + endorsersList.add(endorsers); + } else { + boolean foundEndorser = false; + for (Map map : endorsersList) { + if ((map.get(JsonKey.USER_ID)).equalsIgnoreCase(endorsersId)) { + foundEndorser = true; + break; + } + } + if (foundEndorser) { + // donot do anything.. + ProjectLogger.log(endorsersId + " has already endorsed the " + endorsedId); + } else { + endorsers.put(JsonKey.USER_ID, endorsersId); + endorsers.put(JsonKey.ENDORSE_DATE, format.format(new Date())); + skill.setEndorsementCount(skill.getEndorsementCount() + 1); + endorsersList.add(endorsers); + } + } + skill.setEndorsersList(endorsersList); + return skill; + } + + private void updateMasterSkillsList(List skillset) { + Util.DbInfo skillsListDbInfo = Util.dbInfoMap.get(JsonKey.SKILLS_LIST_DB); + Map skills = new HashMap<>(); + List skillsList = null; + Response skilldbresponse = + cassandraOperation.getRecordById( + skillsListDbInfo.getKeySpace(), skillsListDbInfo.getTableName(), REF_SKILLS_DB_ID); + List> list = + (List>) skilldbresponse.get(JsonKey.RESPONSE); + + if (!list.isEmpty()) { + skills = list.get(0); + skillsList = (List) skills.get(JsonKey.SKILLS); + + } else { + // craete new Entry into the + skillsList = new ArrayList<>(); + } + + for (String skillName : skillset) { + if (!skillsList.contains(skillName.toLowerCase())) { + skillsList.add(skillName.toLowerCase()); + } + } + + skills.put(JsonKey.ID, REF_SKILLS_DB_ID); + skills.put(JsonKey.SKILLS, skillsList); + cassandraOperation.upsertRecord( + skillsListDbInfo.getKeySpace(), skillsListDbInfo.getTableName(), skills); + } + + @SuppressWarnings("unchecked") + private void updateES(String userId) { + + // get all records from cassandra as list and add that list to user in + // ElasticSearch ... + Util.DbInfo userSkillDbInfo = Util.dbInfoMap.get(JsonKey.USER_SKILL_DB); + Response response = + cassandraOperation.getRecordsByProperty( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), JsonKey.USER_ID, userId); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + Map esMap = new HashMap<>(); + esMap.put(JsonKey.SKILLS, responseList); + Future> profileF = + esService.getDataByIdentifier(EsType.user.getTypeName(), userId); + Map profile = + (Map) ElasticSearchHelper.getResponseFromFuture(profileF); + if (MapUtils.isNotEmpty(profile)) { + Map visibility = + (Map) profile.get(JsonKey.PROFILE_VISIBILITY); + // Fetching complete private map including global settings + Map privateVisibilityMap = + Util.getCompleteProfileVisibilityPrivateMap( + visibility, getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue())); + if (MapUtils.isNotEmpty(privateVisibilityMap) + && privateVisibilityMap.containsKey(JsonKey.SKILLS)) { + Future> visibilityMapF = + esService.getDataByIdentifier(EsType.userprofilevisibility.getTypeName(), userId); + Map visibilityMap = + (Map) ElasticSearchHelper.getResponseFromFuture(visibilityMapF); + if (MapUtils.isNotEmpty(visibilityMap)) { + visibilityMap.putAll(esMap); + esService.save(EsType.userprofilevisibility.getTypeName(), userId, visibilityMap); + } + } else { + esService.update(EsType.user.getTypeName(), userId, esMap); + } + } + } + + // method will compare two strings and return true id both are same otherwise + // false ... + private boolean compareStrings(String first, String second) { + if (isNull(first) && isNull(second)) { + return true; + } + if ((isNull(first) && isNotNull(second)) || (isNull(second) && isNotNull(first))) { + return false; + } + return first.equalsIgnoreCase(second); + } + + protected SearchDTO createESRequest( + Map filters, Map aggs, List fields) { + SearchDTO searchDTO = new SearchDTO(); + + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + if (ProjectUtil.isNotNull(aggs)) { + searchDTO.getFacets().add(aggs); + } + if (ProjectUtil.isNotNull(fields)) { + searchDTO.setFields(fields); + } + return searchDTO; + } + + private void addTelemetry(String userId, Request request) { + List> correlatedObject = new ArrayList<>(); + Map targetObject; + targetObject = TelemetryUtil.generateTargetObject(userId, JsonKey.USER, JsonKey.UPDATE, null); + TelemetryUtil.generateCorrelatedObject(userId, JsonKey.USER, null, correlatedObject); + TelemetryUtil.telemetryProcessingCall( + request.getRequest(), targetObject, correlatedObject, request.getContext()); + } + + private void validateUserRootOrg(String requestedUserId, String endorsedUserId) { + Map endorsedMap = getUser(endorsedUserId, JsonKey.ENDORSED_USER_ID); + Map requestedUserMap = getUser(requestedUserId, JsonKey.USER_ID); + + if (!compareStrings( + (String) endorsedMap.get(JsonKey.ROOT_ORG_ID), + (String) requestedUserMap.get(JsonKey.ROOT_ORG_ID))) { + throw new ProjectCommonException( + ResponseCode.canNotEndorse.getErrorCode(), + ResponseCode.canNotEndorse.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private Map getUser(String id, String parameter) { + Util.DbInfo userDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response response = + cassandraOperation.getRecordById(userDbInfo.getKeySpace(), userDbInfo.getTableName(), id); + List> responseUserList = + (List>) response.get(JsonKey.RESPONSE); + + if (responseUserList.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ResponseCode.invalidParameterValue.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + id, + parameter); + } + return responseUserList.get(0); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/dao/UserSkillDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/dao/UserSkillDao.java new file mode 100644 index 0000000000..b00bc6ad55 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/dao/UserSkillDao.java @@ -0,0 +1,38 @@ +package org.sunbird.learner.actors.skill.dao; + +import java.util.List; +import java.util.Map; +import org.sunbird.models.user.skill.Skill; + +public interface UserSkillDao { + + /** + * Add user skills. + * + * @param userSkill User skills information + */ + void add(Map userSkill); + + /** + * Delete user skills. + * + * @param identifierList List of identifiers for user skills to be deleted + * @return Status of delete skills operation + */ + boolean delete(List identifierList); + + /** + * Get skill information. + * + * @param id Skill identifier + * @return Skill information + */ + Skill read(String id); + + /** + * Update user skills. + * + * @param skill Skill which needs to be updated + */ + void update(Skill skill); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/dao/impl/UserSkillDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/dao/impl/UserSkillDaoImpl.java new file mode 100644 index 0000000000..d92a227073 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/skill/dao/impl/UserSkillDaoImpl.java @@ -0,0 +1,71 @@ +package org.sunbird.learner.actors.skill.dao.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.skill.dao.UserSkillDao; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.skill.Skill; + +public class UserSkillDaoImpl implements UserSkillDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private Util.DbInfo userSkillDbInfo = Util.dbInfoMap.get(JsonKey.USER_SKILL_DB); + static UserSkillDao userSkillDao; + + public static UserSkillDao getInstance() { + if (userSkillDao == null) { + userSkillDao = new UserSkillDaoImpl(); + } + return userSkillDao; + } + + @Override + public void add(Map userSkill) { + cassandraOperation.insertRecord( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), userSkill); + } + + @Override + public boolean delete(List idList) { + return cassandraOperation.deleteRecords( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), idList); + } + + @Override + public Skill read(String id) { + ObjectMapper objectMapper = new ObjectMapper(); + Response response = + cassandraOperation.getRecordById( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), id); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true); + if (CollectionUtils.isNotEmpty(responseList)) + return objectMapper.convertValue(responseList.get(0), Skill.class); + return null; + } + + @Override + public void update(Skill skill) { + ObjectMapper objectMapper = new ObjectMapper(); + HashMap map = + (HashMap) objectMapper.convertValue(skill, Map.class); + if (map.containsKey(JsonKey.CREATED_ON)) { + map.remove(JsonKey.CREATED_ON); + } + map.put(JsonKey.LAST_UPDATED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + cassandraOperation.updateRecord( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), map); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/EsSyncActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/EsSyncActor.java new file mode 100644 index 0000000000..b0d0849412 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/EsSyncActor.java @@ -0,0 +1,47 @@ +package org.sunbird.learner.actors.syncjobmanager; + +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; + +/** Sync data between Cassandra and Elastic Search. */ +@ActorConfig( + tasks = {"sync"}, + asyncTasks = {} +) +public class EsSyncActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + + if (operation.equalsIgnoreCase(ActorOperations.SYNC.getValue())) { + triggerBackgroundSync(request); + } else { + onReceiveUnsupportedOperation("EsSyncActor"); + } + } + + private void triggerBackgroundSync(Request request) { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + + Request backgroundSyncRequest = new Request(); + backgroundSyncRequest.setOperation(ActorOperations.BACKGROUND_SYNC.getValue()); + backgroundSyncRequest.getRequest().put(JsonKey.DATA, request.getRequest().get(JsonKey.DATA)); + + try { + tellToAnother(backgroundSyncRequest); + } catch (Exception e) { + ProjectLogger.log( + "EsSyncActor:triggerBackgroundSync: Exception occurred with error message = " + + e.getMessage(), + e); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/EsSyncBackgroundActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/EsSyncBackgroundActor.java new file mode 100644 index 0000000000..1d4739a9ce --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/EsSyncBackgroundActor.java @@ -0,0 +1,226 @@ +package org.sunbird.learner.actors.syncjobmanager; + +import java.text.MessageFormat; +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.learner.util.Util.DbInfo; + +/** Background sync of data between Cassandra and Elastic Search. */ +@ActorConfig( + tasks = {}, + asyncTasks = {"backgroundSync"} +) +public class EsSyncBackgroundActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + + if (ActorOperations.BACKGROUND_SYNC.getValue().equalsIgnoreCase(operation)) { + sync(request); + } else { + onReceiveUnsupportedOperation("EsSyncBackgroundActor"); + } + } + + private void sync(Request message) { + ProjectLogger.log("EsSyncBackgroundActor: sync called", LoggerEnum.INFO); + long startTime = System.currentTimeMillis(); + Map req = message.getRequest(); + Map responseMap = new HashMap<>(); + List> reponseList = null; + List> result = new ArrayList<>(); + Map dataMap = (Map) req.get(JsonKey.DATA); + + String objectType = (String) dataMap.get(JsonKey.OBJECT_TYPE); + + List objectIds = new ArrayList<>(); + if (null != dataMap.get(JsonKey.OBJECT_IDS)) { + objectIds = (List) dataMap.get(JsonKey.OBJECT_IDS); + } + Util.DbInfo dbInfo = getDbInfoObj(objectType); + if (null == dbInfo) { + throw new ProjectCommonException( + ResponseCode.invalidObjectType.getErrorCode(), + ResponseCode.invalidObjectType.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + String requestLogMsg = ""; + + if (JsonKey.USER.equals(objectType)) { + handleUserSyncRequest(objectIds); + return; + } + if (CollectionUtils.isNotEmpty(objectIds)) { + requestLogMsg = + MessageFormat.format( + "type = {0} and IDs = {1}", objectType, Arrays.toString(objectIds.toArray())); + + ProjectLogger.log( + "EsSyncBackgroundActor:sync: Fetching data for " + requestLogMsg + " started", + LoggerEnum.INFO); + Response response = + cassandraOperation.getRecordsByProperty( + dbInfo.getKeySpace(), dbInfo.getTableName(), JsonKey.ID, objectIds); + reponseList = (List>) response.get(JsonKey.RESPONSE); + ProjectLogger.log( + "EsSyncBackgroundActor:sync: Fetching data for " + requestLogMsg + " completed", + LoggerEnum.INFO); + } + if (null != reponseList && !reponseList.isEmpty()) { + for (Map map : reponseList) { + responseMap.put((String) map.get(JsonKey.ID), map); + } + } else { + if (objectIds.size() > 0) { + ProjectLogger.log( + "EsSyncBackgroundActor:sync: Skip sync for " + + requestLogMsg + + " as all IDs are invalid", + LoggerEnum.ERROR); + return; + } + + ProjectLogger.log( + "EsSyncBackgroundActor:sync: Sync all data for type = " + + objectType + + " as no IDs provided", + LoggerEnum.INFO); + + Response response = + cassandraOperation.getAllRecords(dbInfo.getKeySpace(), dbInfo.getTableName()); + reponseList = (List>) response.get(JsonKey.RESPONSE); + + ProjectLogger.log( + "EsSyncBackgroundActor:sync: Fetching all data for type = " + objectType + " completed", + LoggerEnum.INFO); + + ProjectLogger.log( + "EsSyncBackgroundActor:sync: Number of entries to sync for type = " + + objectType + + " is " + + reponseList.size(), + LoggerEnum.INFO); + + if (null != reponseList) { + for (Map map : reponseList) { + responseMap.put((String) map.get(JsonKey.ID), map); + } + } + } + + Iterator> itr = responseMap.entrySet().iterator(); + while (itr.hasNext()) { + if (objectType.equals(JsonKey.ORGANISATION)) { + result.add(getOrgDetails(itr.next())); + } + } + esService.bulkInsert(getType(objectType), result); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + + ProjectLogger.log( + "EsSyncBackgroundActor:sync: Total time taken to sync for type = " + + objectType + + " is " + + elapsedTime + + " ms", + LoggerEnum.INFO); + } + + private void handleUserSyncRequest(List objectIds) { + if (CollectionUtils.isEmpty(objectIds)) { + Response response = + cassandraOperation.getRecordsByProperties( + JsonKey.SUNBIRD, JsonKey.USER, null, Arrays.asList(JsonKey.ID)); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + objectIds = responseList.stream().map(i -> i.get(JsonKey.ID)).collect(Collectors.toList()); + } + invokeUserSync(objectIds); + } + + private void invokeUserSync(List objectIds) { + if (CollectionUtils.isNotEmpty(objectIds)) { + for (Object userId : objectIds) { + Request userRequest = new Request(); + userRequest.setOperation(ActorOperations.UPDATE_USER_INFO_ELASTIC.getValue()); + userRequest.getRequest().put(JsonKey.ID, userId); + ProjectLogger.log( + "EsSyncBackgroundActor:invokeUserSync: Trigger sync of user details to ES"); + tellToAnother(userRequest); + } + } + } + + private String getType(String objectType) { + String type = ""; + if (objectType.equals(JsonKey.USER)) { + type = ProjectUtil.EsType.user.getTypeName(); + } else if (objectType.equals(JsonKey.ORGANISATION)) { + type = ProjectUtil.EsType.organisation.getTypeName(); + } + return type; + } + + private Map getOrgDetails(Entry entry) { + ProjectLogger.log("EsSyncBackgroundActor: getOrgDetails called", LoggerEnum.INFO); + Map orgMap = (Map) entry.getValue(); + orgMap.remove(JsonKey.ORG_TYPE); + if (orgMap.containsKey(JsonKey.ADDRESS_ID) + && !StringUtils.isBlank((String) orgMap.get(JsonKey.ADDRESS_ID))) { + orgMap.put( + JsonKey.ADDRESS, + getDetailsById( + Util.dbInfoMap.get(JsonKey.ADDRESS_DB), (String) orgMap.get(JsonKey.ADDRESS_ID))); + } + ProjectLogger.log("EsSyncBackgroundActor: getOrgDetails returned", LoggerEnum.INFO); + return orgMap; + } + + private Map getDetailsById(DbInfo dbInfo, String userId) { + try { + Response response = + cassandraOperation.getRecordById(dbInfo.getKeySpace(), dbInfo.getTableName(), userId); + return ((((List>) response.get(JsonKey.RESPONSE)).isEmpty()) + ? new HashMap<>() + : ((List>) response.get(JsonKey.RESPONSE)).get(0)); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + return null; + } + + private DbInfo getDbInfoObj(String objectType) { + if (objectType.equals(JsonKey.USER)) { + return Util.dbInfoMap.get(JsonKey.USER_DB); + } else if (objectType.equals(JsonKey.ORGANISATION)) { + return Util.dbInfoMap.get(JsonKey.ORG_DB); + } else if (objectType.equals(JsonKey.BATCH)) { + return Util.dbInfoMap.get(JsonKey.COURSE_BATCH_DB); + } else if (objectType.equals(JsonKey.USER_COURSE)) { + return Util.dbInfoMap.get(JsonKey.LEARNER_COURSE_DB); + } + + return null; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/KeyCloakSyncActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/KeyCloakSyncActor.java new file mode 100644 index 0000000000..0a7f2d6da5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/syncjobmanager/KeyCloakSyncActor.java @@ -0,0 +1,143 @@ +package org.sunbird.learner.actors.syncjobmanager; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; + +/** @author Amit Kumar */ +@ActorConfig( + tasks = {"syncKeycloak"}, + asyncTasks = {} +) +public class KeyCloakSyncActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private boolean isSSOEnabled = + Boolean.parseBoolean(PropertiesCache.getInstance().getProperty(JsonKey.IS_SSO_ENABLED)); + private SSOManager ssoManager = SSOServiceFactory.getInstance(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request actorMessage) throws Throwable { + String requestedOperation = actorMessage.getOperation(); + ProjectLogger.log("Operation name is ==" + requestedOperation); + if (requestedOperation.equalsIgnoreCase(ActorOperations.SYNC_KEYCLOAK.getValue())) { + // return SUCCESS to controller and run the sync process in background + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + syncData(actorMessage); + } else { + onReceiveUnsupportedOperation(actorMessage.getOperation()); + } + } + + private void syncData(Request message) { + ProjectLogger.log("USER DB data sync operation to keycloak started "); + long startTime = System.currentTimeMillis(); + Map req = message.getRequest(); + Map responseMap = new HashMap<>(); + List> reponseList = null; + Map dataMap = (Map) req.get(JsonKey.DATA); + List userIds = null; + if (dataMap.containsKey(JsonKey.OBJECT_IDS) && null != dataMap.get(JsonKey.OBJECT_IDS)) { + userIds = (List) dataMap.get(JsonKey.OBJECT_IDS); + } + Util.DbInfo dbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + + if (null != userIds && !userIds.isEmpty()) { + ProjectLogger.log( + "fetching data for user for these ids " + + Arrays.toString(userIds.toArray()) + + " started"); + Response response = + cassandraOperation.getRecordsByProperty( + dbInfo.getKeySpace(), dbInfo.getTableName(), JsonKey.ID, userIds); + reponseList = (List>) response.get(JsonKey.RESPONSE); + ProjectLogger.log( + "fetching data for user for these ids " + Arrays.toString(userIds.toArray()) + " done"); + } + if (null != reponseList && !reponseList.isEmpty()) { + for (Map map : reponseList) { + responseMap.put((String) map.get(JsonKey.ID), map); + } + } else { + ProjectLogger.log("fetching all data for user started"); + Response response = + cassandraOperation.getAllRecords(dbInfo.getKeySpace(), dbInfo.getTableName()); + reponseList = (List>) response.get(JsonKey.RESPONSE); + ProjectLogger.log("fetching all data for user done"); + ProjectLogger.log("total db data to sync for user to keycloak " + reponseList.size()); + if (null != reponseList) { + for (Map map : reponseList) { + responseMap.put((String) map.get(JsonKey.ID), map); + } + } + } + + Iterator> itr = responseMap.entrySet().iterator(); + while (itr.hasNext()) { + updateUserDetails(itr.next()); + } + + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "total time taken to sync db data for user to keycloak " + elapsedTime + " ms."); + } + + private void updateUserDetails(Entry entry) { + String userId = entry.getKey(); + ProjectLogger.log("updating user data started"); + Map userMap = (Map) entry.getValue(); + // Decrypt user data + UserUtility.decryptUserData(userMap); + Util.DbInfo dbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + if (isSSOEnabled) { + try { + String res = ssoManager.syncUserData(userMap); + if (!(!StringUtils.isBlank(res) && res.equalsIgnoreCase(JsonKey.SUCCESS))) { + if (null == userMap.get(JsonKey.EMAIL_VERIFIED)) { + Map map = new HashMap<>(); + if (ssoManager.isEmailVerified(userId)) { + map.put(JsonKey.EMAIL_VERIFIED, true); + map.put(JsonKey.ID, userId); + } else { + map.put(JsonKey.EMAIL_VERIFIED, false); + map.put(JsonKey.ID, userId); + } + cassandraOperation.updateRecord(dbInfo.getKeySpace(), dbInfo.getTableName(), map); + esService.update(ProjectUtil.EsType.user.getTypeName(), userId, map); + } + ProjectLogger.log("User sync failed in KeyCloakSyncActor for userID : " + userId); + } + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + ProjectLogger.log("User sync failed in KeyCloakSyncActor for userID : " + userId); + } + } else { + ProjectLogger.log("SSO is disabled , cann't sync user data to keycloak."); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/tac/UserTnCActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/tac/UserTnCActor.java new file mode 100644 index 0000000000..adbf75d9cc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/tac/UserTnCActor.java @@ -0,0 +1,151 @@ +package org.sunbird.learner.actors.tac; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.sql.Timestamp; +import java.text.MessageFormat; +import java.util.*; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.telemetry.util.TelemetryUtil; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {"userTnCAccept"}, + asyncTasks = {} +) +public class UserTnCActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + if (operation.equalsIgnoreCase(ActorOperations.USER_TNC_ACCEPT.getValue())) { + acceptTNC(request); + } else { + onReceiveUnsupportedOperation("UserTnCActor"); + } + } + + private void acceptTNC(Request request) { + Util.initializeContext(request, JsonKey.USER); + String acceptedTnC = (String) request.getRequest().get(JsonKey.VERSION); + Map userMap = new HashMap(); + String userId = (String) request.getContext().get(JsonKey.REQUESTED_BY); + + // if managedUserId's terms and conditions are accepted, get userId from request + String managedUserId = (String) request.getRequest().get(JsonKey.USER_ID); + boolean isManagedUser = false; + if (StringUtils.isNotBlank(managedUserId)) { + userId = managedUserId; + isManagedUser = true; + } + SystemSettingClient systemSettingClient = SystemSettingClientImpl.getInstance(); + String latestTnC = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + JsonKey.TNC_CONFIG, + JsonKey.LATEST_VERSION, + new TypeReference() {}); + if (!acceptedTnC.equalsIgnoreCase(latestTnC)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), acceptedTnC, JsonKey.VERSION)); + } + // Search user account in ES + Future> resultF = + esService.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (result == null || result.size() == 0) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + + // If user account isManagedUser(passed in request) and managedBy is empty, not a valid scenario + if (isManagedUser + && ProjectUtil.isNotNull(result) + && ProjectUtil.isNull(result.containsKey(JsonKey.MANAGED_BY))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), userId, JsonKey.USER_ID)); + } + + // Check whether user account is locked or not + if (ProjectUtil.isNotNull(result) + && result.containsKey(JsonKey.IS_DELETED) + && ProjectUtil.isNotNull(result.get(JsonKey.IS_DELETED)) + && (Boolean) result.get(JsonKey.IS_DELETED)) { + ProjectCommonException.throwClientErrorException(ResponseCode.userAccountlocked); + } + + String lastAcceptedVersion = (String) result.get(JsonKey.TNC_ACCEPTED_VERSION); + Response response = new Response(); + if (StringUtils.isEmpty(lastAcceptedVersion) + || !lastAcceptedVersion.equalsIgnoreCase(acceptedTnC) + || StringUtils.isEmpty((String) result.get(JsonKey.TNC_ACCEPTED_ON))) { + ProjectLogger.log( + "UserTnCActor:acceptTNC: tc accepted version= " +acceptedTnC+ " accepted on= "+userMap.get(JsonKey.TNC_ACCEPTED_ON)+ + " for userId:" +userId, LoggerEnum.INFO.name()); + userMap.put(JsonKey.ID, userId); + userMap.put(JsonKey.TNC_ACCEPTED_VERSION, acceptedTnC); + userMap.put( + JsonKey.TNC_ACCEPTED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + response = + cassandraOperation.updateRecord( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userMap); + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + syncUserDetails(userMap); + } + sender().tell(response, self()); + generateTelemetry(userMap, lastAcceptedVersion, request.getContext()); + } else { + response.getResult().put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + } + } + + private void generateTelemetry( + Map userMap, String lastAcceptedVersion, Map context) { + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + targetObject = + TelemetryUtil.generateTargetObject( + (String) userMap.get(JsonKey.USER_ID), + JsonKey.USER, + JsonKey.UPDATE, + lastAcceptedVersion); + TelemetryUtil.telemetryProcessingCall(userMap, targetObject, correlatedObject, context); + ProjectLogger.log( + "UserTnCActor:syncUserDetails: Telemetry generation call ended ", LoggerEnum.INFO.name()); + } + + private void syncUserDetails(Map completeUserMap) { + Request userRequest = new Request(); + userRequest.setOperation(ActorOperations.UPDATE_USER_INFO_ELASTIC.getValue()); + userRequest.getRequest().put(JsonKey.ID, completeUserMap.get(JsonKey.ID)); + ProjectLogger.log( + "UserTnCActor:syncUserDetails: Trigger sync of user details to ES", LoggerEnum.INFO.name()); + tellToAnother(userRequest); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/tenantpreference/TenantPreferenceManagementActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/tenantpreference/TenantPreferenceManagementActor.java new file mode 100644 index 0000000000..209f96e79d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/tenantpreference/TenantPreferenceManagementActor.java @@ -0,0 +1,270 @@ +package org.sunbird.learner.actors.tenantpreference; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +/** Class for Tenant preferences . Created by arvind on 27/10/17. */ +@ActorConfig( + tasks = { + "createTanentPreference", + "updateTenantPreference", + "getTenantPreference", + }, + asyncTasks = {} +) +public class TenantPreferenceManagementActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private Util.DbInfo tenantPreferenceDbInfo = Util.dbInfoMap.get(JsonKey.TENANT_PREFERENCE_DB); + private static final String DEFAULT_WILDCARD_ORG_ID = "*"; + + @Override + public void onReceive(Request request) throws Throwable { + if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.CREATE_TENANT_PREFERENCE.getValue())) { + createTenantPreference(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.UPDATE_TENANT_PREFERENCE.getValue())) { + updateTenantPreference(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.GET_TENANT_PREFERENCE.getValue())) { + getTenantPreference(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + /** + * Method to get Tenant preference of the given root org id . + * + * @param actorMessage + */ + @SuppressWarnings("unchecked") + private void getTenantPreference(Request actorMessage) { + String orgId = (String) actorMessage.getRequest().get(JsonKey.ROOT_ORG_ID); + ProjectLogger.log( + "TenantPreferenceManagementActor-getTenantPreference called for org: " + orgId); + validateRequest(actorMessage, false); + List keys = (List) actorMessage.getRequest().get(JsonKey.KEYS); + + Map> orgPrefMap = getPreferenceMap(getPreferencesFromDB(orgId)); + Map> defaultPrefMap = + getPreferenceMap(getPreferencesFromDB(DEFAULT_WILDCARD_ORG_ID)); + + Response finalResponse = new Response(); + List> list = new ArrayList>(); + if (null != keys && !keys.isEmpty()) { + for (String key : keys) { + if (null != orgPrefMap.get(key)) list.add(orgPrefMap.get(key)); + else if (null != defaultPrefMap.get(key)) list.add(defaultPrefMap.get(key)); + } + } else { + if (!orgPrefMap.isEmpty()) list.addAll(orgPrefMap.values()); + else if (!defaultPrefMap.isEmpty()) list.addAll(defaultPrefMap.values()); + } + finalResponse.getResult().put(JsonKey.TENANT_PREFERENCE, list); + sender().tell(finalResponse, self()); + } + + /** + * Method to update the Tenant preference on basis of id or (role and org id). + * + * @param actorMessage + */ + @SuppressWarnings("unchecked") + private void updateTenantPreference(Request actorMessage) { + + String orgId = (String) actorMessage.getRequest().get(JsonKey.ROOT_ORG_ID); + ProjectLogger.log( + "TenantPreferenceManagementActor-updateTenantPreference called for org: " + orgId); + validateRequest(actorMessage, true); + + Response finalResponse = new Response(); + List> responseList = new ArrayList<>(); + List> reqList = + (List>) actorMessage.getRequest().get(JsonKey.TENANT_PREFERENCE); + List> preferencesList = getPreferencesFromDB(orgId); + for (Map map : reqList) { + Map preferenceObj = null; + String key = (String) map.get(JsonKey.KEY); + String data = (String) map.get(JsonKey.DATA); + // skip update if either key or data is empty + if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(data)) { + boolean found = false; + for (Map m : preferencesList) { + // check if preference key exists for the org + if (key.equals(m.get(JsonKey.KEY))) { + preferenceObj = m; + found = true; + break; + } + } + // if preference is not found + if (!found) + responseList.add( + getResponseMap( + orgId, + key, + "Preference setting not found for key: " + key + " for the org: " + orgId)); + // if preference is found + if (null != preferenceObj) { + preferenceObj.put(JsonKey.KEY, key); + preferenceObj.put(JsonKey.DATA, data); + cassandraOperation.updateRecord( + tenantPreferenceDbInfo.getKeySpace(), + tenantPreferenceDbInfo.getTableName(), + preferenceObj); + responseList.add(getResponseMap(orgId, key, null)); + } + } + } + finalResponse.getResult().put(JsonKey.RESPONSE, responseList); + sender().tell(finalResponse, self()); + } + + /** + * Method to create tenant preference for an org , if already exists it will not create new one. + * + * @param actorMessage + */ + @SuppressWarnings("unchecked") + private void createTenantPreference(Request actorMessage) { + + String orgId = (String) actorMessage.getRequest().get(JsonKey.ROOT_ORG_ID); + ProjectLogger.log( + "TenantPreferenceManagementActor-createTenantPreference called for org: " + orgId); + validateRequest(actorMessage, true); + List> preferencesList = getPreferencesFromDB(orgId); + Response finalResponse = new Response(); + List> responseList = new ArrayList<>(); + List> req = + (List>) actorMessage.getRequest().get(JsonKey.TENANT_PREFERENCE); + for (Map map : req) { + String key = (String) map.get(JsonKey.KEY); + boolean skip = false; + + // abort creation of preferences if any of key is empty or blank + if (StringUtils.isBlank(key)) { + responseList.add(getResponseMap(orgId, key, "Preference key is null")); + skip = true; + } + + // check whether already tenant preference exists for the given org id + for (Map m : preferencesList) { + if (key.equalsIgnoreCase((String) m.get(JsonKey.KEY))) { + responseList.add(getResponseMap(orgId, key, "Preference already exists for key: " + key)); + // skip creation of the preference if already exists for the org + skip = true; + break; + } + } + // create the preference if not already exists + if (!skip) { + Map dbMap = new HashMap(); + dbMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv())); + dbMap.put(JsonKey.ORG_ID, orgId); + dbMap.put(JsonKey.KEY, key); + dbMap.put(JsonKey.DATA, map.get(JsonKey.DATA)); + cassandraOperation.insertRecord( + tenantPreferenceDbInfo.getKeySpace(), tenantPreferenceDbInfo.getTableName(), dbMap); + responseList.add(getResponseMap(orgId, key, null)); + finalResponse.getResult().put(key, JsonKey.SUCCESS); + } + } + finalResponse.getResult().put(JsonKey.RESPONSE, responseList); + sender().tell(finalResponse, self()); + } + + private Map getResponseMap(String orgId, String key, String error) { + Map responseMap = new HashMap<>(); + responseMap.put(JsonKey.ROOT_ORG_ID, orgId); + responseMap.put(JsonKey.KEY, key); + if (StringUtils.isNotBlank(error)) { + responseMap.put(JsonKey.STATUS, JsonKey.FAILED); + responseMap.put( + JsonKey.ERROR, "Preference setting not found for key: " + key + " for the org: " + orgId); + } else responseMap.put(JsonKey.STATUS, JsonKey.SUCCESS); + return responseMap; + } + + @SuppressWarnings("unchecked") + private List> getPreferencesFromDB(String orgId) { + Response tenantPreferences = + cassandraOperation.getRecordsByProperty( + tenantPreferenceDbInfo.getKeySpace(), + tenantPreferenceDbInfo.getTableName(), + JsonKey.ORG_ID, + orgId); + List> preferencesList = + (List>) tenantPreferences.get(JsonKey.RESPONSE); + return preferencesList; + } + + @SuppressWarnings("unchecked") + private void validateRequest(Request actorMessage, boolean update) { + + String orgId = (String) actorMessage.getRequest().get(JsonKey.ROOT_ORG_ID); + if (StringUtils.isBlank(orgId)) { + // throw invalid ord id ,org id should not be null or empty . + throw new ProjectCommonException( + ResponseCode.invalidOrgId.getErrorCode(), + ResponseCode.invalidOrgId.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + // skipping this check for now to allow storing of channel based preferences + /* + * // check if the org id is either a valid org in the system or is the default wild card + * org (*) if (!StringUtils.equalsIgnoreCase(DEFAULT_WILDCARD_ORG_ID, orgId)) { // check + * whether org exist or not Response result = + * cassandraOperation.getRecordById(orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), + * orgId); List> orglist = (List>) + * result.get(JsonKey.RESPONSE); if (null == orglist || orglist.isEmpty()) throw new + * ProjectCommonException(ResponseCode.invalidOrgId.getErrorCode(), + * ResponseCode.invalidOrgId.getErrorMessage(), + * ResponseCode.CLIENT_ERROR.getResponseCode()); } + */ + + if (update) { + List> req = + (List>) actorMessage.getRequest().get(JsonKey.TENANT_PREFERENCE); + // no need to do anything throw exception invalid request data as list is empty + if (null == req || req.isEmpty()) + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private Map> getPreferenceMap( + List> preferencesList) { + Map> keyMap = new HashMap>(); + if (null != preferencesList && !preferencesList.isEmpty()) { + for (Map m : preferencesList) { + String key = (String) m.get(JsonKey.KEY); + keyMap.put(key, m); + } + } + return keyMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/dao/UrlActionDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/dao/UrlActionDao.java new file mode 100644 index 0000000000..fe36f0beb7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/dao/UrlActionDao.java @@ -0,0 +1,14 @@ +package org.sunbird.learner.actors.url.action.dao; + +import java.util.List; +import org.sunbird.models.url.action.UrlAction; + +public interface UrlActionDao { + + /** + * Get list of URL actions. + * + * @return List of URL actions. + */ + List getUrlActions(); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/dao/impl/UrlActionDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/dao/impl/UrlActionDaoImpl.java new file mode 100644 index 0000000000..8d34cb8030 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/dao/impl/UrlActionDaoImpl.java @@ -0,0 +1,39 @@ +package org.sunbird.learner.actors.url.action.dao.impl; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import java.util.Map; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.url.action.dao.UrlActionDao; +import org.sunbird.models.url.action.UrlAction; + +public class UrlActionDaoImpl implements UrlActionDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ObjectMapper mapper = new ObjectMapper(); + private static UrlActionDao urlActionDao; + private static final String KEYSPACE_NAME = "sunbird"; + private static final String TABLE_NAME = "url_action"; + + public static UrlActionDao getInstance() { + if (urlActionDao == null) { + urlActionDao = new UrlActionDaoImpl(); + } + return urlActionDao; + } + + @SuppressWarnings("unchecked") + @Override + public List getUrlActions() { + Response urlActionResults = cassandraOperation.getAllRecords(KEYSPACE_NAME, TABLE_NAME); + TypeReference> urlActionType = new TypeReference>() {}; + List> urlActionMapList = + (List>) urlActionResults.get(JsonKey.RESPONSE); + List urlActionList = mapper.convertValue(urlActionMapList, urlActionType); + return urlActionList; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/service/UrlActionService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/service/UrlActionService.java new file mode 100644 index 0000000000..51ffdbb64b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/url/action/service/UrlActionService.java @@ -0,0 +1,35 @@ +package org.sunbird.learner.actors.url.action.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections4.CollectionUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.learner.actors.url.action.dao.UrlActionDao; +import org.sunbird.learner.actors.url.action.dao.impl.UrlActionDaoImpl; +import org.sunbird.models.url.action.UrlAction; + +public class UrlActionService { + + private static UrlActionDao urlActionDao = UrlActionDaoImpl.getInstance(); + + public static Map getUrlActionMap(String urlId) { + Map response = new HashMap<>(); + List urlActionList = urlActionDao.getUrlActions(); + + if (CollectionUtils.isNotEmpty(urlActionList)) { + for (UrlAction urlAction : urlActionList) { + if (urlAction.getId().equals(urlId)) { + response.put(JsonKey.ID, urlAction.getId()); + response.put(JsonKey.NAME, urlAction.getName()); + response.put( + JsonKey.URL, urlAction.getUrl() != null ? urlAction.getUrl() : new ArrayList<>()); + return response; + } + } + } + + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/user/service/UserService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/user/service/UserService.java new file mode 100644 index 0000000000..a87c994dba --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/actors/user/service/UserService.java @@ -0,0 +1,67 @@ +package org.sunbird.learner.actors.user.service; + +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.learner.util.Util.DbInfo; + +public class UserService { + + private DbInfo userDb = Util.dbInfoMap.get(JsonKey.USER_DB); + + public void checkKeyUniqueness(String key, String value, boolean isEncrypted) { + if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) { + ProjectLogger.log( + "UserService:checkKeyUniqueness: Key or value is null. key = " + key + " value= " + value, + LoggerEnum.ERROR.name()); + return; + } + String val = value; + if (isEncrypted) { + try { + val = getEncryptionService().encryptData(val); + } catch (Exception e) { + ProjectLogger.log( + "UserService:checkKeyUniqueness: Exception occurred with error message = " + + e.getMessage(), + e); + } + } + + Response result = + getCassandraOperation() + .getRecordsByIndexedProperty(userDb.getKeySpace(), userDb.getTableName(), key, val); + + List> userMapList = + (List>) result.get(JsonKey.RESPONSE); + + if (!userMapList.isEmpty()) { + ResponseCode responseCode = null; + if (JsonKey.EMAIL.equals(key)) { + responseCode = ResponseCode.emailInUse; + } else if (JsonKey.PHONE.equals(key)) { + responseCode = ResponseCode.PhoneNumberInUse; + } + ProjectCommonException.throwClientErrorException(responseCode, null); + } + } + + private CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } + + private EncryptionService getEncryptionService() { + return org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/datapersistence/DbOperationActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/datapersistence/DbOperationActor.java new file mode 100644 index 0000000000..05e0287d91 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/datapersistence/DbOperationActor.java @@ -0,0 +1,488 @@ +package org.sunbird.learner.datapersistence; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.telemetry.util.TelemetryWriter; +import scala.concurrent.Future; + +@ActorConfig( + tasks = { + "createData", + "updateData", + "deleteData", + "readData", + "readAllData", + "searchData", + "getMetrics" + }, + asyncTasks = {} +) +public class DbOperationActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request actorMessage) throws Throwable { + Util.initializeContext(actorMessage, TelemetryEnvKey.OBJECT_STORE); + if (actorMessage.getOperation().equalsIgnoreCase(ActorOperations.CREATE_DATA.getValue())) { + create(actorMessage); + } else if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.UPDATE_DATA.getValue())) { + update(actorMessage); + } else if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.DELETE_DATA.getValue())) { + delete(actorMessage); + } else if (actorMessage.getOperation().equalsIgnoreCase(ActorOperations.READ_DATA.getValue())) { + read(actorMessage); + } else if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.READ_ALL_DATA.getValue())) { + readAllData(actorMessage); + } else if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.SEARCH_DATA.getValue())) { + search(actorMessage); + } else if (actorMessage + .getOperation() + .equalsIgnoreCase(ActorOperations.GET_METRICS.getValue())) { + getMetrics(actorMessage); + } else { + onReceiveUnsupportedOperation(actorMessage.getOperation()); + } + onReceiveUnsupportedOperation(actorMessage.getOperation()); + } + + private void getMetrics(Request actorMessage) { + try { + String ES_INDEX_NAME = "sunbirdplugin"; + String RAW_QUERY = "rawQuery"; + validateTableName(actorMessage); + Map rawQueryMap = + (Map) actorMessage.getRequest().get(RAW_QUERY); + rawQueryMap.put(JsonKey.SIZE, 0); + ObjectMapper mapper = new ObjectMapper(); + String rawQuery = mapper.writeValueAsString(rawQueryMap); + Response response = esService.searchMetricsData(ES_INDEX_NAME, rawQuery); + sender().tell(response, self()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void search(Request reqObj) { + SearchDTO searchDto = null; + try { + String ENTITY_NAME = "entityName"; + String ES_INDEX_NAME = "sunbirdplugin"; + Response response = new Response(); + String REQUIRED_FIELDS = "requiredFields"; + List requiredFields = null; + if (!StringUtils.isBlank((String) reqObj.getRequest().get(ENTITY_NAME))) { + String esType = (String) reqObj.getRequest().get(ENTITY_NAME); + if (reqObj.getRequest().containsKey(REQUIRED_FIELDS)) { + requiredFields = (List) reqObj.getRequest().get(REQUIRED_FIELDS); + reqObj.getRequest().remove(REQUIRED_FIELDS); + } + + reqObj.getRequest().remove(ENTITY_NAME); + if (null != reqObj.getRequest().get(JsonKey.FILTERS)) { + validateRequestData((Map) reqObj.getRequest().get(JsonKey.FILTERS)); + } + searchDto = Util.createSearchDto(reqObj.getRequest()); + Future> resultF = esService.search(searchDto, ES_INDEX_NAME); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + Map finalResult = new HashMap<>(); + if (!result.isEmpty()) { + // filter the required fields like content or facet etc... + if (null != requiredFields && !requiredFields.isEmpty()) { + for (String attribute : requiredFields) { + finalResult.put(attribute, result.get(attribute)); + } + result = finalResult; + } + if (result.containsKey(JsonKey.CONTENT)) { + List> mapList = + (List>) result.get(JsonKey.CONTENT); + for (Map map : mapList) { + map.remove(JsonKey.IDENTIFIER); + } + } + response.put(JsonKey.RESPONSE, result); + } else { + response.put(JsonKey.RESPONSE, new HashMap<>()); + } + } else { + throw new ProjectCommonException( + ResponseCode.tableOrDocNameError.getErrorCode(), + ResponseCode.tableOrDocNameError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + sender().tell(response, self()); + // create search telemetry event here ... + generateSearchTelemetryEvent( + searchDto, + new String[] {ES_INDEX_NAME}, + (Map) response.get(JsonKey.RESPONSE), + reqObj.getContext()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void readAllData(Request reqObj) { + try { + Response response = null; + validateTableName(reqObj); + String ENTITY_NAME = "entityName"; + if (!StringUtils.isBlank((String) reqObj.getRequest().get(ENTITY_NAME))) { + response = + cassandraOperation.getAllRecords( + JsonKey.SUNBIRD_PLUGIN, (String) reqObj.getRequest().get(ENTITY_NAME)); + } else { + throw new ProjectCommonException( + ResponseCode.tableOrDocNameError.getErrorCode(), + ResponseCode.tableOrDocNameError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + sender().tell(response, self()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void read(Request reqObj) { + try { + String ENTITY_NAME = "entityName"; + Response response = null; + validateTableName(reqObj); + if (!StringUtils.isBlank((String) reqObj.getRequest().get(ENTITY_NAME))) { + response = + cassandraOperation.getRecordById( + JsonKey.SUNBIRD_PLUGIN, + (String) reqObj.getRequest().get(ENTITY_NAME), + (String) reqObj.getRequest().get(JsonKey.ID)); + } else { + throw new ProjectCommonException( + ResponseCode.tableOrDocNameError.getErrorCode(), + ResponseCode.tableOrDocNameError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + sender().tell(response, self()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void delete(Request reqObj) { + try { + validateTableName(reqObj); + String ENTITY_NAME = "entityName"; + String ES_INDEX_NAME = "sunbirdplugin"; + String INDEXED = "indexed"; + Response response = + cassandraOperation.deleteRecord( + JsonKey.SUNBIRD_PLUGIN, + (String) reqObj.getRequest().get(ENTITY_NAME), + (String) reqObj.getRequest().get(JsonKey.ID)); + if (((String) response.get(JsonKey.RESPONSE)).equals(JsonKey.SUCCESS) + && ((boolean) reqObj.getRequest().get(INDEXED))) { + deleteDataFromElastic( + ES_INDEX_NAME, + (String) reqObj.getRequest().get(ENTITY_NAME), + (String) reqObj.getRequest().get(JsonKey.ID)); + } + sender().tell(response, self()); + generateTelemetryObjectStore(reqObj); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void update(Request reqObj) { + try { + String PAYLOAD = "payload"; + String INDEXED = "indexed"; + String ES_INDEX_NAME = "sunbirdplugin"; + validateTableName(reqObj); + Map payload = (Map) reqObj.getRequest().get(PAYLOAD); + validateRequestData(payload); + Response response = null; + boolean esResult = false; + String ENTITY_NAME = "entityName"; + if (!StringUtils.isBlank((String) reqObj.getRequest().get(ENTITY_NAME)) + && ((boolean) reqObj.getRequest().get(INDEXED))) { + esResult = + updateDataToElastic( + ES_INDEX_NAME, + (String) reqObj.getRequest().get(ENTITY_NAME), + (String) payload.get(JsonKey.ID), + payload); + if (esResult) { + response = + cassandraOperation.updateRecord( + JsonKey.SUNBIRD_PLUGIN, (String) reqObj.getRequest().get(ENTITY_NAME), payload); + if (!((String) response.get(JsonKey.RESPONSE)).equals(JsonKey.SUCCESS)) { + deleteDataFromElastic( + ES_INDEX_NAME, + (String) reqObj.getRequest().get(ENTITY_NAME), + (String) payload.get(JsonKey.ID)); + throw new ProjectCommonException( + ResponseCode.esUpdateFailed.getErrorCode(), + ResponseCode.esUpdateFailed.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } else { + throw new ProjectCommonException( + ResponseCode.updateFailed.getErrorCode(), + ResponseCode.updateFailed.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else { + Future> dataF = + esService.getDataByIdentifier(ES_INDEX_NAME, (String) payload.get(JsonKey.ID)); + Map data = + (Map) ElasticSearchHelper.getResponseFromFuture(dataF); + if (data.isEmpty() || ((boolean) reqObj.getRequest().get(INDEXED))) { + response = + cassandraOperation.updateRecord( + JsonKey.SUNBIRD_PLUGIN, (String) reqObj.getRequest().get(ENTITY_NAME), payload); + } else { + throw new ProjectCommonException( + ResponseCode.updateFailed.getErrorCode(), + ResponseCode.updateFailed.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + sender().tell(response, self()); + generateTelemetryObjectStore(reqObj); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void create(Request reqObj) { + try { + String PAYLOAD = "payload"; + String ENTITY_NAME = "entityName"; + String INDEXED = "indexed"; + String ES_INDEX_NAME = "sunbirdplugin"; + validateTableName(reqObj); + Map payload = (Map) reqObj.getRequest().get(PAYLOAD); + validateRequestData(payload); + Response response = + cassandraOperation.insertRecord( + JsonKey.SUNBIRD_PLUGIN, (String) reqObj.getRequest().get(ENTITY_NAME), payload); + if (((String) response.get(JsonKey.RESPONSE)).equals(JsonKey.SUCCESS) + && ((boolean) reqObj.getRequest().get(INDEXED))) { + boolean esResult = false; + if (!StringUtils.isBlank((String) reqObj.getRequest().get(ENTITY_NAME))) { + esResult = + insertDataToElastic( + ES_INDEX_NAME, + (String) reqObj.getRequest().get(ENTITY_NAME), + (String) payload.get(JsonKey.ID), + payload); + if (!esResult) { + deleteRecord( + JsonKey.SUNBIRD_PLUGIN, + (String) reqObj.getRequest().get(ENTITY_NAME), + (String) payload.get(JsonKey.ID)); + throw new ProjectCommonException( + ResponseCode.esUpdateFailed.getErrorCode(), + ResponseCode.esUpdateFailed.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + response.put(JsonKey.DATA, payload); + } + } + sender().tell(response, self()); + generateTelemetryObjectStore(reqObj); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void validateRequestData(Map payload) { + for (Map.Entry entry : payload.entrySet()) { + if (entry.getValue() instanceof BigInteger) { + payload.put(entry.getKey(), Integer.parseInt(String.valueOf(entry.getValue()))); + } + } + } + + private void validateTableName(Request reqObj) { + String ENTITY_NAME = "entityName"; + if (!DataCacheHandler.getSunbirdPluginTableList() + .contains(reqObj.getRequest().get(ENTITY_NAME))) { + throw new ProjectCommonException( + ResponseCode.tableOrDocNameError.getErrorCode(), + ResponseCode.tableOrDocNameError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * Method to insert data to ES . + * + * @param index + * @param type + * @param identifier + * @param data + * @return + */ + private boolean insertDataToElastic( + String index, String type, String identifier, Map data) { + ProjectLogger.log( + "making call to ES for index ,identifier ,data==" + type + " " + identifier + data); + Future responseF = esService.save(index, identifier, data); + String response = (String) ElasticSearchHelper.getResponseFromFuture(responseF); + ProjectLogger.log( + "Getting ES save response for type , identifier==" + + type + + " " + + identifier + + " " + + response); + if (!StringUtils.isBlank(response)) { + ProjectLogger.log("Data is saved successfully ES ." + type + " " + identifier); + return true; + } + ProjectLogger.log( + "unbale to save the data inside ES with identifier " + identifier, LoggerEnum.INFO.name()); + return false; + } + + /** + * Method to update data to ES . + * + * @param indexName + * @param typeName + * @param identifier + * @param data + * @return + */ + private boolean updateDataToElastic( + String indexName, String typeName, String identifier, Map data) { + Future responseF = esService.update(indexName, identifier, data); + boolean response = (boolean) ElasticSearchHelper.getResponseFromFuture(responseF); + if (response) { + return true; + } + ProjectLogger.log( + "unable to save the data inside ES with identifier " + identifier, LoggerEnum.INFO.name()); + return false; + } + + /** + * Method to update data to ES . + * + * @param indexName + * @param typeName + * @param identifier + * @return + */ + private boolean deleteDataFromElastic(String indexName, String typeName, String identifier) { + Future responseF = esService.delete(indexName, identifier); + boolean response = (boolean) ElasticSearchHelper.getResponseFromFuture(responseF); + if (response) { + return true; + } + ProjectLogger.log( + "unable to delete the data from ES with identifier " + identifier, LoggerEnum.INFO.name()); + return false; + } + + private void deleteRecord(String keyspaceName, String tableName, String identifier) { + cassandraOperation.deleteRecord(keyspaceName, tableName, identifier); + } + + private void generateSearchTelemetryEvent( + SearchDTO searchDto, + String[] types, + Map result, + Map context) { + Map params = new HashMap<>(); + params.put(JsonKey.QUERY, searchDto.getQuery()); + params.put(JsonKey.FILTERS, searchDto.getAdditionalProperties().get(JsonKey.FILTERS)); + params.put(JsonKey.SORT, searchDto.getSortBy()); + params.put(JsonKey.TOPN, generateTopNResult(result)); + params.put(JsonKey.SIZE, result.get(JsonKey.COUNT)); + params.put(JsonKey.TYPE, String.join(",", types)); + + Request request = new Request(); + request.setRequest(telemetryRequestForSearch(context, params)); + TelemetryWriter.write(request); + } + + private List> generateTopNResult(Map result) { + List> dataMapList = (List>) result.get(JsonKey.CONTENT); + Integer topN = + Integer.parseInt(PropertiesCache.getInstance().getProperty(JsonKey.SEARCH_TOP_N)); + int count = Math.min(topN, dataMapList.size()); + List> list = new ArrayList<>(); + for (int i = 0; i < count; i++) { + Map m = new HashMap<>(); + m.put(JsonKey.ID, dataMapList.get(i).get(JsonKey.ID)); + list.add(m); + } + return list; + } + + private static Map telemetryRequestForSearch( + Map telemetryContext, Map params) { + Map map = new HashMap<>(); + map.put(JsonKey.CONTEXT, telemetryContext); + map.put(JsonKey.PARAMS, params); + map.put(JsonKey.TELEMETRY_EVENT_TYPE, "SEARCH"); + return map; + } + + private static void generateTelemetryObjectStore(Request reqObj) { + String PAYLOAD = "payload"; + String ENTITY_NAME = "entityName"; + Map targetObject = + TelemetryUtil.generateTargetObject( + (String) ((Map) reqObj.getRequest().get(PAYLOAD)).get(JsonKey.ID), + (String) reqObj.getRequest().get(ENTITY_NAME), + JsonKey.CREATE, + null); + TelemetryUtil.telemetryProcessingCall( + (Map) reqObj.getRequest().get(PAYLOAD), + targetObject, + new ArrayList<>(), + reqObj.getContext()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/organisation/external/identity/service/OrgExternalService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/organisation/external/identity/service/OrgExternalService.java new file mode 100644 index 0000000000..83c0c429a4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/organisation/external/identity/service/OrgExternalService.java @@ -0,0 +1,39 @@ +package org.sunbird.learner.organisation.external.identity.service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; + +public class OrgExternalService { + + private final String KEYSPACE_NAME = "sunbird"; + private final String ORG_EXTERNAL_IDENTITY = "org_external_identity"; + + public String getOrgIdFromOrgExternalIdAndProvider(String externalId, String provider) { + Map dbRequestMap = new HashMap<>(); + dbRequestMap.put(JsonKey.EXTERNAL_ID, externalId.toLowerCase()); + dbRequestMap.put(JsonKey.PROVIDER, provider.toLowerCase()); + Response response = + getCassandraOperation() + .getRecordsByCompositeKey(KEYSPACE_NAME, ORG_EXTERNAL_IDENTITY, dbRequestMap); + List> orgList = + (List>) response.getResult().get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(orgList)) { + Map orgExternalMap = orgList.get(0); + if (MapUtils.isNotEmpty(orgExternalMap)) { + return (String) orgExternalMap.get(JsonKey.ORG_ID); + } + } + return null; + } + + private CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/AdminUtilHandler.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/AdminUtilHandler.java new file mode 100644 index 0000000000..f5da793ebd --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/AdminUtilHandler.java @@ -0,0 +1,83 @@ +package org.sunbird.learner.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.collections4.MapUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.*; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.models.adminutil.AdminUtilParams; +import org.sunbird.models.adminutil.AdminUtilRequestPayload; +import org.sunbird.models.adminutil.AdminUtilRequestData; +import org.sunbird.models.adminutil.AdminUtilRequest; + +import java.io.IOException; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AdminUtilHandler { + + /** + * Prepare payload for admin utils + * @param reqData List + * @return adminUtilsReq AdminUtilRequestPayload + */ + public static AdminUtilRequestPayload prepareAdminUtilPayload(List reqData){ + AdminUtilRequestPayload adminUtilsReq = new AdminUtilRequestPayload(); + adminUtilsReq.setId(JsonKey.EKSTEP_SIGNING_SIGN_PAYLOAD); + adminUtilsReq.setVer(JsonKey.EKSTEP_SIGNING_SIGN_PAYLOAD_VER); + adminUtilsReq.setTs(Calendar.getInstance().getTime().getTime()); + adminUtilsReq.setParams(new AdminUtilParams()); + adminUtilsReq.setRequest(new AdminUtilRequest(reqData)); + return adminUtilsReq; + } + + /** + * Fetch encrypted token list from admin utils + * @param reqObject AdminUtilRequestPayload + * @return encryptedTokenList + */ + public static Map fetchEncryptedToken(AdminUtilRequestPayload reqObject){ + Map data = null; + ObjectMapper mapper = new ObjectMapper(); + try { + + String body = mapper.writeValueAsString(reqObject); + ProjectLogger.log( + "AdminUtilHandler :: fetchEncryptedToken: request payload" + body, + LoggerEnum.DEBUG); + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + String response = HttpUtil.sendPostRequest( + ProjectUtil.getConfigValue(JsonKey.ADMINUTIL_BASE_URL) + + ProjectUtil.getConfigValue(JsonKey.ADMINUTIL_SIGN_ENDPOINT), + body, + headers); + ProjectLogger.log( + "AdminUtilHandler :: fetchEncryptedToken: response payload" + response, + LoggerEnum.DEBUG); + data = mapper.readValue(response, Map.class); + if (MapUtils.isNotEmpty(data)) { + data = (Map) data.get(JsonKey.RESULT); + } + } catch (IOException e) { + ProjectLogger.log( + "AdminUtilHandler:fetchEncryptedToken Exception occurred : " + e.getMessage(), e, null, LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.unableToConnectToAdminUtil.getErrorCode(), + ResponseCode.unableToConnectToAdminUtil.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } catch (Exception e) { + ProjectLogger.log( + "AdminUtilHandler:fetchEncryptedToken Exception occurred : " + e.getMessage(), e, null, LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.unableToParseData.getErrorCode(), + ResponseCode.unableToParseData.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + return data; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/DataCacheHandler.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/DataCacheHandler.java new file mode 100644 index 0000000000..6b491127e0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/DataCacheHandler.java @@ -0,0 +1,276 @@ +/** */ +package org.sunbird.learner.util; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.helper.CassandraConnectionManager; +import org.sunbird.helper.CassandraConnectionMngrFactory; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.role.service.RoleService; + +/** + * This class will handle the data cache. + * + * @author Amit Kumar + */ +public class DataCacheHandler implements Runnable { + + private static Map roleMap = new ConcurrentHashMap<>(); + private static Map telemetryPdata = new ConcurrentHashMap<>(3); + private static Map orgTypeMap = new ConcurrentHashMap<>(); + private static Map configSettings = new ConcurrentHashMap<>(); + private static Map>>> frameworkCategoriesMap = + new ConcurrentHashMap<>(); + private static Map> frameworkFieldsConfig = new ConcurrentHashMap<>(); + private static Map> hashtagIdFrameworkIdMap = new HashMap<>(); + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static final String KEY_SPACE_NAME = Util.KEY_SPACE_NAME; + private static Response roleCacheResponse; + private static List sunbirdPluginTableList = null; + private static Map orderMap; + public static String[] bulkUserAllowedFields = { + JsonKey.FIRST_NAME, + JsonKey.LAST_NAME, + JsonKey.PHONE, + JsonKey.COUNTRY_CODE, + JsonKey.EMAIL, + JsonKey.USERNAME, + JsonKey.PHONE_VERIFIED, + JsonKey.EMAIL_VERIFIED, + JsonKey.ROLES, + JsonKey.POSITION, + JsonKey.GRADE, + JsonKey.LOCATION, + JsonKey.DOB, + JsonKey.GENDER, + JsonKey.LANGUAGE, + JsonKey.PROFILE_SUMMARY, + JsonKey.SUBJECT, + JsonKey.WEB_PAGES, + JsonKey.EXTERNAL_ID_PROVIDER, + JsonKey.EXTERNAL_ID, + JsonKey.EXTERNAL_ID_TYPE, + JsonKey.EXTERNAL_IDS + }; + public static String[] bulkOrgAllowedFields = { + JsonKey.ORGANISATION_NAME, + JsonKey.CHANNEL, + JsonKey.IS_ROOT_ORG, + JsonKey.PROVIDER, + JsonKey.EXTERNAL_ID, + JsonKey.DESCRIPTION, + JsonKey.HOME_URL, + JsonKey.ORG_CODE, + JsonKey.ORG_TYPE, + JsonKey.PREFERRED_LANGUAGE, + JsonKey.THEME, + JsonKey.CONTACT_DETAILS, + JsonKey.LOC_ID, + JsonKey.HASHTAGID, + JsonKey.LOCATION_CODE + }; + + @Override + public void run() { + ProjectLogger.log("DataCacheHandler:run: Cache refresh started.", LoggerEnum.INFO.name()); + roleCache(roleMap); + orgTypeCache(orgTypeMap); + cacheSystemConfig(configSettings); + cacheRoleForRead(); + cacheTelemetryPdata(telemetryPdata); + createSunbirdPluginTableList(); + initLocationOrderMap(); + ProjectLogger.log("DataCacheHandler:run: Cache refresh completed.", LoggerEnum.INFO.name()); + } + + private void initLocationOrderMap() { + if (orderMap == null) { + orderMap = new HashMap<>(); + List subTypeList = + Arrays.asList(ProjectUtil.getConfigValue("sunbird_valid_location_types").split(";")); + for (String str : subTypeList) { + List typeList = + (((Arrays.asList(str.split(","))).stream().map(String::toLowerCase)) + .collect(Collectors.toList())); + for (int i = 0; i < typeList.size(); i++) { + orderMap.put(typeList.get(i), i); + } + } + } + } + + public void createSunbirdPluginTableList() { + try { + CassandraConnectionManager manager = CassandraConnectionMngrFactory.getInstance(); + sunbirdPluginTableList = manager.getTableList(JsonKey.SUNBIRD_PLUGIN); + } catch (Exception e) { + ProjectLogger.log("Error occurred" + e.getMessage(), e); + } + } + + private void cacheTelemetryPdata(Map telemetryPdata) { + telemetryPdata.put("telemetry_pdata_id", ProjectUtil.getConfigValue("telemetry_pdata_id")); + telemetryPdata.put("telemetry_pdata_pid", ProjectUtil.getConfigValue("telemetry_pdata_pid")); + telemetryPdata.put("telemetry_pdata_ver", ProjectUtil.getConfigValue("telemetry_pdata_ver")); + } + + private void cacheRoleForRead() { + roleCacheResponse = RoleService.getUserRoles(); + } + + public static Response getRoleResponse() { + return roleCacheResponse; + } + + public static Map getTelemetryPdata() { + return telemetryPdata; + } + + public static void setRoleResponse(Response response) { + if (response != null) roleCacheResponse = response; + } + + @SuppressWarnings("unchecked") + private void cacheSystemConfig(Map configSettings) { + Response response = + cassandraOperation.getAllRecords(KEY_SPACE_NAME, JsonKey.SYSTEM_SETTINGS_DB); + ProjectLogger.log( + "DataCacheHandler:cacheSystemConfig: Cache system setting fields" + response.getResult(), + LoggerEnum.INFO.name()); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (null != responseList && !responseList.isEmpty()) { + for (Map resultMap : responseList) { + if (((String) resultMap.get(JsonKey.FIELD)).equalsIgnoreCase(JsonKey.PHONE_UNIQUE) + && StringUtils.isBlank((String) resultMap.get(JsonKey.VALUE))) { + configSettings.put(((String) resultMap.get(JsonKey.FIELD)), String.valueOf(false)); + } else if (((String) resultMap.get(JsonKey.FIELD)).equalsIgnoreCase(JsonKey.EMAIL_UNIQUE) + && StringUtils.isBlank((String) resultMap.get(JsonKey.VALUE))) { + configSettings.put(((String) resultMap.get(JsonKey.FIELD)), String.valueOf(false)); + } else { + configSettings.put( + ((String) resultMap.get(JsonKey.FIELD)), (String) resultMap.get(JsonKey.VALUE)); + } + } + } else { + configSettings.put(JsonKey.PHONE_UNIQUE, String.valueOf(false)); + configSettings.put(JsonKey.EMAIL_UNIQUE, String.valueOf(false)); + } + } + + @SuppressWarnings("unchecked") + private void orgTypeCache(Map orgTypeMap) { + Response response = cassandraOperation.getAllRecords(KEY_SPACE_NAME, JsonKey.ORG_TYPE_DB); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (null != responseList && !responseList.isEmpty()) { + for (Map resultMap : responseList) { + orgTypeMap.put( + ((String) resultMap.get(JsonKey.NAME)).toLowerCase(), + (String) resultMap.get(JsonKey.ID)); + } + } + } + + @SuppressWarnings("unchecked") + private void roleCache(Map roleMap) { + Response response = cassandraOperation.getAllRecords(KEY_SPACE_NAME, JsonKey.ROLE_GROUP); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (null != responseList && !responseList.isEmpty()) { + for (Map resultMap : responseList) { + roleMap.put((String) resultMap.get(JsonKey.ID), resultMap.get(JsonKey.NAME)); + } + } + Response response2 = cassandraOperation.getAllRecords(KEY_SPACE_NAME, JsonKey.ROLE); + List> responseList2 = + (List>) response2.get(JsonKey.RESPONSE); + if (null != responseList2 && !responseList2.isEmpty()) { + for (Map resultMap2 : responseList2) { + roleMap.put((String) resultMap2.get(JsonKey.ID), resultMap2.get(JsonKey.NAME)); + } + } + } + /** @return the roleMap */ + public static Map getRoleMap() { + return roleMap; + } + + /** @param roleMap the roleMap to set */ + public static void setRoleMap(Map roleMap) { + DataCacheHandler.roleMap = roleMap; + } + + /** @return the orgTypeMap */ + public static Map getOrgTypeMap() { + return orgTypeMap; + } + + /** @param orgTypeMap the orgTypeMap to set */ + public static void setOrgTypeMap(Map orgTypeMap) { + DataCacheHandler.orgTypeMap = orgTypeMap; + } + + /** @return the configSettings */ + public static Map getConfigSettings() { + return configSettings; + } + + /** @param configSettings the configSettings to set */ + public static void setConfigSettings(Map configSettings) { + DataCacheHandler.configSettings = configSettings; + } + + public static Map>>> getFrameworkCategoriesMap() { + return frameworkCategoriesMap; + } + + public static void setFrameworkCategoriesMap( + Map>>> frameworkCategoriesMap) { + DataCacheHandler.frameworkCategoriesMap = frameworkCategoriesMap; + } + + public static void setFrameworkFieldsConfig(Map> frameworkFieldsConfig) { + DataCacheHandler.frameworkFieldsConfig = frameworkFieldsConfig; + } + + public static Map> getFrameworkFieldsConfig() { + return frameworkFieldsConfig; + } + + public static void updateFrameworkCategoriesMap( + String frameworkId, Map>> frameworkCacheMap) { + DataCacheHandler.frameworkCategoriesMap.put(frameworkId, frameworkCacheMap); + } + + public static void setHashtagIdFrameworkIdMap(Map> hashtagIdFrameworkIdMap) { + DataCacheHandler.hashtagIdFrameworkIdMap = hashtagIdFrameworkIdMap; + } + + public static Map> getHashtagIdFrameworkIdMap() { + return hashtagIdFrameworkIdMap; + } + + public static void updateHashtagIdFrameworkIdMap(String hashtagId, List frameworkIds) { + DataCacheHandler.hashtagIdFrameworkIdMap.put(hashtagId, frameworkIds); + } + + public static List getSunbirdPluginTableList() { + return sunbirdPluginTableList; + } + + public static Map getLocationOrderMap() { + return orderMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/EkStepRequestUtil.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/EkStepRequestUtil.java new file mode 100644 index 0000000000..232ee93146 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/EkStepRequestUtil.java @@ -0,0 +1,90 @@ +/** */ +package org.sunbird.learner.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import javax.ws.rs.core.MediaType; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHeaders; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; + +/** + * This class will make the call to EkStep content search + * + * @author Manzarul + */ +public final class EkStepRequestUtil { + + private static ObjectMapper mapper = new ObjectMapper(); + + private EkStepRequestUtil() {} + + /** + * @param params String + * @param headers Map + * @return Map + */ + public static Map searchContent(String params, Map headers) { + Map resMap = new HashMap<>(); + try { + String baseSearchUrl = ProjectUtil.getConfigValue(JsonKey.SEARCH_SERVICE_API_BASE_URL); + headers.put( + JsonKey.AUTHORIZATION, JsonKey.BEARER + System.getenv(JsonKey.EKSTEP_AUTHORIZATION)); + headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + headers.remove(HttpHeaders.ACCEPT_ENCODING.toLowerCase()); + headers.put(HttpHeaders.ACCEPT_ENCODING.toLowerCase(), "UTF-8"); + if (StringUtils.isBlank(headers.get(JsonKey.AUTHORIZATION))) { + headers.put( + JsonKey.AUTHORIZATION, + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION)); + } + ProjectLogger.log("making call for content search ==" + params, LoggerEnum.INFO.name()); + String response = + HttpUtil.sendPostRequest( + baseSearchUrl + + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_CONTENT_SEARCH_URL), + params, + headers); + ProjectLogger.log("Content serach response is ==" + response, LoggerEnum.INFO.name()); + Map data = mapper.readValue(response, Map.class); + if (MapUtils.isNotEmpty(data)) { + String resmsgId = (String) ((Map) data.get("params")).get("resmsgid"); + String apiId = (String) data.get("id"); + data = (Map) data.get(JsonKey.RESULT); + ProjectLogger.log( + "Total number of content fetched from Ekstep while assembling page data : " + + data.get("count"), + LoggerEnum.INFO.name()); + if (MapUtils.isNotEmpty(data)) { + Object contentList = data.get(JsonKey.CONTENT); + Map param = new HashMap<>(); + param.put(JsonKey.RES_MSG_ID, resmsgId); + param.put(JsonKey.API_ID, apiId); + resMap.put(JsonKey.PARAMS, param); + resMap.put(JsonKey.CONTENTS, contentList); + Iterator> itr = data.entrySet().iterator(); + while (itr.hasNext()) { + Map.Entry entry = itr.next(); + if (!JsonKey.CONTENT.equals(entry.getKey())) { + resMap.put(entry.getKey(), entry.getValue()); + } + } + } + } else { + ProjectLogger.log("EkStepRequestUtil:searchContent No data found", LoggerEnum.INFO.name()); + } + } catch (IOException e) { + ProjectLogger.log("Error found during contnet search parse==" + e.getMessage(), e); + } + return resMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/ExecutorManager.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/ExecutorManager.java new file mode 100644 index 0000000000..2928260475 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/ExecutorManager.java @@ -0,0 +1,33 @@ +package org.sunbird.learner.util; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +/** + * This class will manage execute service thread. + * + * @author Manzarul.Haque + */ +public final class ExecutorManager { + + private static final int MAX_EXECUTOR_THREAD = 2; + /* + * service ScheduledExecutorService object + */ + private static ScheduledExecutorService service = null; + + private ExecutorManager() {} + + static { + service = Executors.newScheduledThreadPool(MAX_EXECUTOR_THREAD); + } + + /** + * This method will send executor service object. + * + * @return + */ + public static ScheduledExecutorService getExecutorService() { + return service; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/OTPUtil.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/OTPUtil.java new file mode 100644 index 0000000000..63edec8d9d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/OTPUtil.java @@ -0,0 +1,171 @@ +package org.sunbird.learner.util; + +import com.warrenstrange.googleauth.GoogleAuthenticator; +import com.warrenstrange.googleauth.GoogleAuthenticatorConfig; +import com.warrenstrange.googleauth.GoogleAuthenticatorKey; +import com.warrenstrange.googleauth.KeyRepresentation; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.otp.service.OTPService; +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.utils.SMSFactory; + +public final class OTPUtil { + + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static DecryptionService decService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + + private static final int MINIMUM_OTP_LENGTH = 6; + private static final int SECONDS_IN_MINUTES = 60; + + private OTPUtil() {} + + public static String generateOTP() { + String otpSize = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_OTP_LENGTH); + int codeDigits = StringUtils.isBlank(otpSize) ? MINIMUM_OTP_LENGTH : Integer.valueOf(otpSize); + GoogleAuthenticatorConfig config = + new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder() + .setCodeDigits(codeDigits) + .setKeyRepresentation(KeyRepresentation.BASE64) + .build(); + GoogleAuthenticator gAuth = new GoogleAuthenticator(config); + GoogleAuthenticatorKey key = gAuth.createCredentials(); + String secret = key.getKey(); + int code = gAuth.getTotpPassword(secret); + return String.valueOf(code); + } + + public static void sendOTPViaSMS(Map otpMap) { + if (StringUtils.isBlank((String) otpMap.get(JsonKey.PHONE))) { + return; + } + + Map smsTemplate = new HashMap<>(); + String template = (String) otpMap.get(JsonKey.TEMPLATE_ID); + smsTemplate.put(JsonKey.OTP, (String) otpMap.get(JsonKey.OTP)); + smsTemplate.put( + JsonKey.OTP_EXPIRATION_IN_MINUTES, (String) otpMap.get(JsonKey.OTP_EXPIRATION_IN_MINUTES)); + smsTemplate.put( + JsonKey.INSTALLATION_NAME, + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_INSTALLATION_DISPLAY_NAME)); + String sms = null; + if (StringUtils.isBlank(template)) { + sms = OTPService.getSmsBody(JsonKey.VERIFY_PHONE_OTP_TEMPLATE, smsTemplate); + } else if (StringUtils.isNotBlank(template) && StringUtils.equals(template, JsonKey.WARD_LOGIN_OTP_TEMPLATE_ID)) { + sms = OTPService.getSmsBody(JsonKey.OTP_PHONE_WARD_LOGIN_TEMPLATE, smsTemplate); + } else { + sms = OTPService.getSmsBody(JsonKey.OTP_PHONE_RESET_PASSWORD_TEMPLATE, smsTemplate); + } + ProjectLogger.log("OTPUtil:sendOTPViaSMS: SMS text = " + sms, LoggerEnum.INFO.name()); + + String countryCode = ""; + if (StringUtils.isBlank((String) otpMap.get(JsonKey.COUNTRY_CODE))) { + countryCode = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_DEFAULT_COUNTRY_CODE); + } else { + countryCode = (String) otpMap.get(JsonKey.COUNTRY_CODE); + } + ISmsProvider smsProvider = SMSFactory.getInstance("91SMS"); + + ProjectLogger.log( + "OTPUtil:sendOTPViaSMS: SMS OTP text = " + + sms + + " with phone = " + + (String) otpMap.get(JsonKey.PHONE), + LoggerEnum.INFO.name()); + + boolean response = smsProvider.send((String) otpMap.get(JsonKey.PHONE), countryCode, sms); + + ProjectLogger.log( + "OTPUtil:sendOTPViaSMS: OTP sent successfully to phone :" + + otpMap.get(JsonKey.PHONE) + + "is " + + response, + LoggerEnum.INFO.name()); + } + + /** + * This method will return either email or phone value of user based on the asked type in request + * + * @param userId + * @param type value can be email, phone, prevUsedEmail or prevUsedPhone + * @return + */ + public static String getEmailPhoneByUserId(String userId, String type) { + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response response = + cassandraOperation.getRecordById(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userId); + List> userList = (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(userList)) { + Map user = userList.get(0); + String emailPhone = decService.decryptData((String) user.get(type)); + if (StringUtils.isBlank(emailPhone)) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidRequestData); + } + return emailPhone; + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.userNotFound); + } + return null; + } + + public static Request sendOTPViaEmail(Map emailTemplateMap, String otpType) { + Request request = null; + if ((StringUtils.isBlank((String) emailTemplateMap.get(JsonKey.EMAIL)))) { + return request; + } + String envName = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_INSTALLATION_DISPLAY_NAME); + String emailSubject = null; + if ("resetPassword".equalsIgnoreCase(otpType)) { + emailSubject = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_RESET_PASS_MAIL_SUBJECT); + } else { + // default fallback for all other otpType + emailSubject = ProjectUtil.getConfigValue(JsonKey.ONBOARDING_MAIL_SUBJECT); + } + emailTemplateMap.put(JsonKey.SUBJECT, ProjectUtil.formatMessage(emailSubject, envName)); + List reciptientsMail = new ArrayList<>(); + reciptientsMail.add((String) emailTemplateMap.get(JsonKey.EMAIL)); + emailTemplateMap.put(JsonKey.RECIPIENT_EMAILS, reciptientsMail); + if (StringUtils.isBlank((String) emailTemplateMap.get(JsonKey.TEMPLATE_ID))) { + emailTemplateMap.put(JsonKey.EMAIL_TEMPLATE_TYPE, JsonKey.OTP); + } else if (StringUtils.isNotBlank((String) emailTemplateMap.get(JsonKey.TEMPLATE_ID)) && StringUtils.equals((String) emailTemplateMap.get(JsonKey.TEMPLATE_ID), JsonKey.WARD_LOGIN_OTP_TEMPLATE_ID)) { + emailTemplateMap.put(JsonKey.EMAIL_TEMPLATE_TYPE, JsonKey.OTP_EMAIL_WARD_LOGIN_TEMPLATE); + } else { + // send otp to email while reseting password from portal + emailTemplateMap.put(JsonKey.EMAIL_TEMPLATE_TYPE, JsonKey.OTP_EMAIL_RESET_PASSWORD_TEMPLATE); + } + emailTemplateMap.put(JsonKey.INSTALLATION_NAME, envName); + request = new Request(); + request.setOperation(BackgroundOperations.emailService.name()); + request.put(JsonKey.EMAIL_REQUEST, emailTemplateMap); + return request; + } + + public static Request sendOTPViaEmail(Map emailTemplateMap) { + return sendOTPViaEmail(emailTemplateMap, null); + } + + public static String getOTPExpirationInMinutes() { + String expirationInSeconds = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_OTP_EXPIRATION); + int otpExpiration = Integer.valueOf(expirationInSeconds); + int otpExpirationInMinutes = Math.floorDiv(otpExpiration, SECONDS_IN_MINUTES); + return String.valueOf(otpExpirationInMinutes); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SchedulerManager.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SchedulerManager.java new file mode 100644 index 0000000000..21f03ee8c9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SchedulerManager.java @@ -0,0 +1,26 @@ +/** */ +package org.sunbird.learner.util; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; + +/** @author Manzarul All the scheduler job will be handle by this class. */ +public class SchedulerManager { + + private static final int TTL = 4; + + /* + * service ScheduledExecutorService object + */ + public static ScheduledExecutorService service = ExecutorManager.getExecutorService(); + + /** all scheduler job will be configure here. */ + public static void schedule() { + service.scheduleWithFixedDelay(new DataCacheHandler(), 0, TTL, TimeUnit.HOURS); + ProjectLogger.log( + "SchedulerManager:schedule: Started scheduler job for cache refresh.", + LoggerEnum.INFO.name()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SearchTelemetryUtil.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SearchTelemetryUtil.java new file mode 100644 index 0000000000..691c428978 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SearchTelemetryUtil.java @@ -0,0 +1,62 @@ +/* +package org.sunbird.learner.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.request.Request; +import org.sunbird.dto.SearchDTO; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.telemetry.util.TelemetryWriter; + +public class SearchTelemetryUtil { + private SearchTelemetryUtil() {} + + public static void generateSearchTelemetryEvent( + SearchDTO searchDto, String[] types, Map result) { + try { + Map telemetryContext = TelemetryUtil.getTelemetryContext(); + Map params = new HashMap<>(); + params.put(JsonKey.QUERY, searchDto.getQuery()); + params.put(JsonKey.FILTERS, searchDto.getAdditionalProperties().get(JsonKey.FILTERS)); + params.put(JsonKey.SORT, searchDto.getSortBy()); + params.put(JsonKey.TOPN, generateTopNResult(result)); + params.put(JsonKey.SIZE, result.get(JsonKey.COUNT)); + params.put(JsonKey.TYPE, String.join(",", types)); + + Request request = new Request(); + request.setRequest(telemetryRequestForSearch(telemetryContext, params)); + TelemetryWriter.write(request); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + private static List> generateTopNResult(Map result) { + List> dataMapList = (List>) result.get(JsonKey.CONTENT); + Integer topN = + Integer.parseInt(PropertiesCache.getInstance().getProperty(JsonKey.SEARCH_TOP_N)); + int count = Math.min(topN, dataMapList.size()); + List> list = new ArrayList<>(); + for (int i = 0; i < count; i++) { + Map m = new HashMap<>(); + m.put(JsonKey.ID, dataMapList.get(i).get(JsonKey.ID)); + list.add(m); + } + return list; + } + + private static Map telemetryRequestForSearch( + Map telemetryContext, Map params) { + Map map = new HashMap<>(); + map.put(JsonKey.CONTEXT, telemetryContext); + map.put(JsonKey.PARAMS, params); + map.put(JsonKey.TELEMETRY_EVENT_TYPE, "SEARCH"); + return map; + } +} +*/ diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SocialMediaType.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SocialMediaType.java new file mode 100644 index 0000000000..2175601779 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/SocialMediaType.java @@ -0,0 +1,201 @@ +package org.sunbird.learner.util; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; + +public class SocialMediaType { + + private static Map mediaTypes = new HashMap<>(); + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static Util.DbInfo mediaTypeDB = Util.dbInfoMap.get(JsonKey.MEDIA_TYPE_DB); + private static Map invalidUrls = new HashMap<>(); + + static { + initInvalidUrlMap(); + } + + public static Map getMediaTypes() { + if (null == mediaTypes || mediaTypes.isEmpty()) { + updateCache(); + } + return mediaTypes; + } + + public void addMediaType(String id, String name) { + Map queryMap = new HashMap<>(); + queryMap.put(JsonKey.ID, id); + queryMap.put(JsonKey.NAME, name); + Response response = + cassandraOperation.insertRecord( + mediaTypeDB.getKeySpace(), mediaTypeDB.getTableName(), queryMap); + if (ResponseCode.success.getResponseCode() == response.getResponseCode().getResponseCode()) { + mediaTypes.put(id, name); + } + } + + public static Response getMediaTypeFromDB() { + return cassandraOperation.getAllRecords(mediaTypeDB.getKeySpace(), mediaTypeDB.getTableName()); + } + + @SuppressWarnings("unchecked") + private static void updateCache() { + Response response = getMediaTypeFromDB(); + Map mediaMap = new HashMap<>(); + List> list = ((List>) response.get(JsonKey.RESPONSE)); + if (!list.isEmpty()) { + for (Map data : list) { + mediaMap.put((String) data.get(JsonKey.ID), (String) data.get(JsonKey.NAME)); + } + } + mediaTypes = mediaMap; + } + + private static String validateMediaURL(String type, String url) { + String pattern = ""; + + if (StringUtils.isBlank(url)) { + return url; + } + if (validateUrls(url)) { + return ""; + } + switch (type) { + case "fb": + if (url.contains("http")) { + pattern = + "http(?:s)?:\\/\\/(?:www.)?facebook.com\\/(?:(?:\\w\\.)*#!\\/)?(?:pages\\/)?(?:[\\w\\-\\.]*\\/)*([\\w\\-\\.]*)?(?:profile.php\\?id=(?=\\d.*))?([\\w\\-\\.]*)?"; + if (!isMatch(url, pattern)) { + url = ""; + } + } else { + if (url.contains("facebook.com/")) { + url = StringUtils.substringAfter(url, "facebook.com/"); + } + url = "https://www.facebook.com/" + url; + } + return url; + + case "twitter": + if (url.contains("http")) { + pattern = "http(?:s)?:\\/\\/(?:www.)?twitter\\.com\\/([a-zA-Z0-9_]+)"; + if (!isMatch(url, pattern)) { + url = ""; + } + } else { + if (url.contains("twitter.com/")) { + url = StringUtils.substringAfter(url, "twitter.com/"); + } + url = "https://twitter.com/" + url; + } + return url; + + case "in": + if (url.contains("http")) { + pattern = "http(?:s)?:\\/\\/(?:www.)?linkedin+\\.[a-zA-Z0-9/~\\-_,&=\\?\\.;]+[^\\.,\\s<]"; + if (!isMatch(url, pattern)) { + url = ""; + } + } else { + if (url.contains("linkedin.com/in/")) { + url = StringUtils.substringAfter(url, "linkedin.com/in/"); + } + url = "https://www.linkedin.com/in/" + url; + } + return url; + + case "blog": + pattern = "http(?:s)?://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"; + if (!isMatch(url, pattern)) { + url = ""; + } + return url; + + default: + pattern = "\\b(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"; + if (!isMatch(url, pattern)) { + url = ""; + } + return url; + } + } + + private static boolean validateUrls(String url) { + return invalidUrls.containsKey(url.toLowerCase()); + } + + private static void initInvalidUrlMap() { + invalidUrls.put("www.facebook.com", true); + invalidUrls.put("www.facebook.com/", true); + + invalidUrls.put("https://www.facebook.com", true); + invalidUrls.put("https://www.facebook.com/", true); + invalidUrls.put("http://www.facebook.com/", true); + invalidUrls.put("http://www.facebook.com", true); + + invalidUrls.put("https://www.linkedin.com", true); + invalidUrls.put("https://www.linkedin.com/", true); + invalidUrls.put("http://www.linkedin.com", true); + invalidUrls.put("http://www.linkedin.com/", true); + invalidUrls.put("www.linkedin.com", true); + invalidUrls.put("www.linkedin.com/", true); + + invalidUrls.put("https://twitter.com/", true); + invalidUrls.put("https://twitter.com", true); + invalidUrls.put("http://twitter.com/", true); + invalidUrls.put("http://twitter.com", true); + invalidUrls.put("www.twitter.com", true); + invalidUrls.put("www.twitter.com/", true); + } + + private static boolean isMatch(String s, String pattern) { + try { + Pattern patt = Pattern.compile(pattern); + Matcher matcher = patt.matcher(s); + return matcher.matches(); + } catch (RuntimeException e) { + return false; + } + } + + public static void validateSocialMedia(List> socialMediaList) { + for (Map socialMedia : socialMediaList) { + if (null == socialMedia || socialMedia.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidWebPageData.getErrorCode(), + ResponseCode.invalidWebPageData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + String mediaType = socialMedia.get(JsonKey.TYPE); + if (!SocialMediaType.getMediaTypes().containsKey(mediaType)) { + SocialMediaType.updateCache(); + if (!SocialMediaType.getMediaTypes().containsKey(mediaType)) { + throw new ProjectCommonException( + ResponseCode.invalidMediaType.getErrorCode(), + ResponseCode.invalidMediaType.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + String mediaUrl = SocialMediaType.validateMediaURL(mediaType, socialMedia.get(JsonKey.URL)); + if (StringUtils.isBlank(mediaUrl)) { + throw new ProjectCommonException( + ResponseCode.invalidWebPageUrl.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidWebPageUrl.getErrorMessage(), getMediaTypes().get(mediaType)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else { + socialMedia.put(JsonKey.URL, mediaUrl); + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserFlagEnum.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserFlagEnum.java new file mode 100644 index 0000000000..c10444f8e6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserFlagEnum.java @@ -0,0 +1,30 @@ +package org.sunbird.learner.util; + +import org.sunbird.common.models.util.JsonKey; + +/** + * UserFlagEnum provides all the flags of user type It contains flagtype and corresponding value in + * decimal format value should be bit enabled and equivalent to decimal format. If any flag is + * added, please add value as 2 pow (position-1) + */ +public enum UserFlagEnum { + PHONE_VERIFIED(JsonKey.PHONE_VERIFIED, 1), + EMAIL_VERIFIED(JsonKey.EMAIL_VERIFIED, 2), + STATE_VALIDATED(JsonKey.STATE_VALIDATED, 4); + + private String userFlagType; + private int userFlagValue; + + UserFlagEnum(String userFlagType, int userFlagValue) { + this.userFlagType = userFlagType; + this.userFlagValue = userFlagValue; + } + + public int getUserFlagValue() { + return userFlagValue; + } + + public String getUserFlagType() { + return userFlagType; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserFlagUtil.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserFlagUtil.java new file mode 100644 index 0000000000..fcbeb9d624 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserFlagUtil.java @@ -0,0 +1,60 @@ +package org.sunbird.learner.util; + +import java.util.HashMap; +import java.util.Map; +import org.sunbird.common.models.util.JsonKey; + +public class UserFlagUtil { + + /** + * This method return int value of the boolean flag + * + * @param userFlagType + * @param flagEnabled + * @return + */ + public static int getFlagValue(String userFlagType, boolean flagEnabled) { + int decimalValue = 0; + // if phone is verified flag should be true then only return flagvalue + if (userFlagType.equals(UserFlagEnum.PHONE_VERIFIED.getUserFlagType()) && flagEnabled) { + decimalValue = UserFlagEnum.PHONE_VERIFIED.getUserFlagValue(); + } else if (userFlagType.equals(UserFlagEnum.EMAIL_VERIFIED.getUserFlagType()) && flagEnabled) { + // if email is verified flag should be true then only return flagvalue + decimalValue = UserFlagEnum.EMAIL_VERIFIED.getUserFlagValue(); + } else if (userFlagType.equals(UserFlagEnum.STATE_VALIDATED.getUserFlagType()) && flagEnabled) { + // if user is state-validated flag should be true then only return flagvalue + decimalValue = UserFlagEnum.STATE_VALIDATED.getUserFlagValue(); + } + return decimalValue; + } + + /** + * This method returns boolean flags of user for the flagValue + * + * @param flagsValue + * @return + */ + public static Map assignUserFlagValues(int flagsValue) { + Map userFlagMap = new HashMap<>(); + setDefaultValues(userFlagMap); + if ((flagsValue & UserFlagEnum.PHONE_VERIFIED.getUserFlagValue()) + == UserFlagEnum.PHONE_VERIFIED.getUserFlagValue()) { + userFlagMap.put(UserFlagEnum.PHONE_VERIFIED.getUserFlagType(), true); + } + if ((flagsValue & UserFlagEnum.EMAIL_VERIFIED.getUserFlagValue()) + == UserFlagEnum.EMAIL_VERIFIED.getUserFlagValue()) { + userFlagMap.put(UserFlagEnum.EMAIL_VERIFIED.getUserFlagType(), true); + } + if ((flagsValue & UserFlagEnum.STATE_VALIDATED.getUserFlagValue()) + == UserFlagEnum.STATE_VALIDATED.getUserFlagValue()) { + userFlagMap.put(UserFlagEnum.STATE_VALIDATED.getUserFlagType(), true); + } + return userFlagMap; + } + + private static void setDefaultValues(Map userFlagMap) { + userFlagMap.put(JsonKey.EMAIL_VERIFIED, false); + userFlagMap.put(JsonKey.PHONE_VERIFIED, false); + userFlagMap.put(JsonKey.STATE_VALIDATED, false); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserUtility.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserUtility.java new file mode 100644 index 0000000000..39d4e16251 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/UserUtility.java @@ -0,0 +1,224 @@ +package org.sunbird.learner.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.models.util.datasecurity.impl.ServiceFactory; + +/** + * This class is for utility methods for encrypting user data. + * + * @author Amit Kumar + */ +public final class UserUtility { + + private static List userKeyToEncrypt; + private static List addressKeyToEncrypt; + private static List userKeyToDecrypt; + private static List userKeysToMasked; + private static DecryptionService decryptionService; + private static DataMaskingService maskingService; + private static List phoneMaskedAttributes; + private static List emailMaskedAttributes; + + static { + init(); + } + + private UserUtility() {} + + public static Map encryptUserData(Map userMap) throws Exception { + return encryptSpecificUserData(userMap, userKeyToEncrypt); + } + + @SuppressWarnings("unchecked") + public static Map encryptSpecificUserData( + Map userMap, List fieldsToEncrypt) throws Exception { + EncryptionService service = ServiceFactory.getEncryptionServiceInstance(null); + // Encrypt user basic info + for (String key : fieldsToEncrypt) { + if (userMap.containsKey(key)) { + userMap.put(key, service.encryptData((String) userMap.get(key))); + } + } + // Encrypt user address Info + if (userMap.containsKey(JsonKey.ADDRESS)) { + List> addressList = + (List>) userMap.get(JsonKey.ADDRESS); + for (Map map : addressList) { + for (String key : addressKeyToEncrypt) { + if (map.containsKey(key)) { + map.put(key, service.encryptData((String) map.get(key))); + } + } + } + } + return userMap; + } + + public static List> encryptUserAddressData( + List> addressList) throws Exception { + EncryptionService service = ServiceFactory.getEncryptionServiceInstance(null); + // Encrypt user address Info + for (Map map : addressList) { + for (String key : addressKeyToEncrypt) { + if (map.containsKey(key)) { + map.put(key, service.encryptData((String) map.get(key))); + } + } + } + return addressList; + } + + public static Map decryptUserData(Map userMap) { + return decryptSpecificUserData(userMap, userKeyToEncrypt); + } + + public static Map decryptSpecificUserData( + Map userMap, List fieldsToDecrypt) { + DecryptionService service = ServiceFactory.getDecryptionServiceInstance(null); + // Decrypt user basic info + for (String key : fieldsToDecrypt) { + if (userMap.containsKey(key)) { + userMap.put(key, service.decryptData((String) userMap.get(key))); + } + } + + // Decrypt user address Info + if (userMap.containsKey(JsonKey.ADDRESS)) { + List> addressList = + (List>) userMap.get(JsonKey.ADDRESS); + for (Map map : addressList) { + for (String key : addressKeyToEncrypt) { + if (map.containsKey(key)) { + map.put(key, service.decryptData((String) map.get(key))); + } + } + } + } + return userMap; + } + + public static Map decryptUserDataFrmES(Map userMap) { + DecryptionService service = ServiceFactory.getDecryptionServiceInstance(null); + // Decrypt user basic info + for (String key : userKeyToDecrypt) { + if (userMap.containsKey(key)) { + if (userKeysToMasked.contains(key)) { + userMap.put(key, maskEmailOrPhone((String) userMap.get(key), key)); + } else { + userMap.put(key, service.decryptData((String) userMap.get(key))); + } + } + } + // Decrypt user address Info + if (userMap.containsKey(JsonKey.ADDRESS)) { + List> addressList = + (List>) userMap.get(JsonKey.ADDRESS); + for (Map map : addressList) { + for (String key : addressKeyToEncrypt) { + if (map.containsKey(key)) { + map.put(key, service.decryptData((String) map.get(key))); + } + } + } + } + return userMap; + } + + public static List> decryptUserAddressData( + List> addressList) { + DecryptionService service = ServiceFactory.getDecryptionServiceInstance(null); + // Decrypt user address info + for (Map map : addressList) { + for (String key : addressKeyToEncrypt) { + if (map.containsKey(key)) { + map.put(key, service.decryptData((String) map.get(key))); + } + } + } + return addressList; + } + + public static Map encryptUserSearchFilterQueryData(Map map) + throws Exception { + Map filterMap = (Map) map.get(JsonKey.FILTERS); + EncryptionService service = ServiceFactory.getEncryptionServiceInstance(null); + // Encrypt user basic info + for (String key : userKeyToEncrypt) { + if (filterMap.containsKey(key)) { + filterMap.put(key, service.encryptData((String) filterMap.get(key))); + } + } + // Encrypt user address Info + for (String key : addressKeyToEncrypt) { + if ((filterMap).containsKey((JsonKey.ADDRESS + "." + key))) { + filterMap.put( + (JsonKey.ADDRESS + "." + key), + service.encryptData((String) filterMap.get(JsonKey.ADDRESS + "." + key))); + } + } + return filterMap; + } + + public static String encryptData(String data) throws Exception { + EncryptionService service = ServiceFactory.getEncryptionServiceInstance(null); + return service.encryptData(data); + } + + public static String maskEmailOrPhone(String encryptedEmailOrPhone, String type) { + if (StringUtils.isEmpty(encryptedEmailOrPhone)) { + return StringUtils.EMPTY; + } + if (phoneMaskedAttributes.contains(type)) { + return maskingService.maskPhone(decryptionService.decryptData(encryptedEmailOrPhone)); + } else if (emailMaskedAttributes.contains(type)) { + return maskingService.maskEmail(decryptionService.decryptData(encryptedEmailOrPhone)); + } + return StringUtils.EMPTY; + } + + private static void init() { + decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getDecryptionServiceInstance(null); + maskingService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getMaskingServiceInstance( + null); + String userKey = PropertiesCache.getInstance().getProperty("userkey.encryption"); + userKeyToEncrypt = new ArrayList<>(Arrays.asList(userKey.split(","))); + ProjectLogger.log( + "UserUtility:init:user encrypt attributes got".concat(userKey + ""), + LoggerEnum.INFO.name()); + String addressKey = PropertiesCache.getInstance().getProperty("addresskey.encryption"); + ProjectLogger.log( + "UserUtility:init:user address encrypt attributes got".concat(addressKey + ""), + LoggerEnum.INFO.name()); + addressKeyToEncrypt = new ArrayList<>(Arrays.asList(addressKey.split(","))); + String userKeyDecrypt = PropertiesCache.getInstance().getProperty("userkey.decryption"); + String userKeyToMasked = PropertiesCache.getInstance().getProperty("userkey.masked"); + userKeyToDecrypt = new ArrayList<>(Arrays.asList(userKeyDecrypt.split(","))); + userKeysToMasked = new ArrayList<>(Arrays.asList(userKeyToMasked.split(","))); + String emailTypeAttributeKey = + PropertiesCache.getInstance().getProperty("userkey.emailtypeattributes"); + String phoneTypeAttributeKey = + PropertiesCache.getInstance().getProperty("userkey.phonetypeattributes"); + emailMaskedAttributes = new ArrayList<>(Arrays.asList(emailTypeAttributeKey.split(","))); + ProjectLogger.log( + "UserUtility:init:email masked attributes got".concat(emailTypeAttributeKey + ""), + LoggerEnum.INFO.name()); + phoneMaskedAttributes = new ArrayList<>(Arrays.asList(phoneTypeAttributeKey.split(","))); + ProjectLogger.log( + "UserUtility:init:phone masked attributes got".concat(phoneTypeAttributeKey + ""), + LoggerEnum.INFO.name()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/Util.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/Util.java new file mode 100644 index 0000000000..af7bd3b25d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/learner/util/Util.java @@ -0,0 +1,1588 @@ +package org.sunbird.learner.util; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.typesafe.config.Config; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.util.*; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.ProjectUtil.OrgStatus; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.models.util.url.URLShortner; +import org.sunbird.common.models.util.url.URLShortnerImpl; +import org.sunbird.common.quartz.scheduler.SchedulerManager; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.common.services.ProfileCompletenessService; +import org.sunbird.common.services.impl.ProfileCompletenessFactory; +import org.sunbird.common.util.ConfigUtil; +import org.sunbird.common.util.KeycloakRequiredActionLinkUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.CassandraConnectionManager; +import org.sunbird.helper.CassandraConnectionMngrFactory; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.models.systemsetting.SystemSetting; +import org.sunbird.models.user.User; +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.utils.SMSFactory; +import scala.concurrent.Future; + +/** + * Utility class for actors + * + * @author arvind . + */ +public final class Util { + + public static final Map dbInfoMap = new HashMap<>(); + private static PropertiesCache propertiesCache = PropertiesCache.getInstance(); + public static final int DEFAULT_ELASTIC_DATA_LIMIT = 10000; + public static final String KEY_SPACE_NAME = "sunbird"; + private static Properties prop = new Properties(); + private static Map headers = new HashMap<>(); + private static Map> orgStatusTransition = new HashMap<>(); + private static final String SUNBIRD_WEB_URL = "sunbird_web_url"; + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + private static DecryptionService decService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + private static DataMaskingService maskingService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getMaskingServiceInstance( + null); + private static ObjectMapper mapper = new ObjectMapper(); + private static ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + static { + initializeOrgStatusTransition(); + initializeDBProperty(); // EkStep HttpClient headers init + headers.put("content-type", "application/json"); + headers.put("accept", "application/json"); + new Thread( + new Runnable() { + + @Override + public void run() { + SchedulerManager.getInstance(); + } + }) + .start(); + } + + private Util() {} + + /** + * This method will a map of organization state transaction. which will help us to move the + * organization status from one Valid state to another state. + */ + private static void initializeOrgStatusTransition() { + orgStatusTransition.put( + OrgStatus.ACTIVE.getValue(), + Arrays.asList( + OrgStatus.ACTIVE.getValue(), + OrgStatus.INACTIVE.getValue(), + OrgStatus.BLOCKED.getValue(), + OrgStatus.RETIRED.getValue())); + orgStatusTransition.put( + OrgStatus.INACTIVE.getValue(), + Arrays.asList(OrgStatus.ACTIVE.getValue(), OrgStatus.INACTIVE.getValue())); + orgStatusTransition.put( + OrgStatus.BLOCKED.getValue(), + Arrays.asList( + OrgStatus.ACTIVE.getValue(), + OrgStatus.BLOCKED.getValue(), + OrgStatus.RETIRED.getValue())); + orgStatusTransition.put( + OrgStatus.RETIRED.getValue(), Arrays.asList(OrgStatus.RETIRED.getValue())); + orgStatusTransition.put( + null, + Arrays.asList( + OrgStatus.ACTIVE.getValue(), + OrgStatus.INACTIVE.getValue(), + OrgStatus.BLOCKED.getValue(), + OrgStatus.RETIRED.getValue())); + } + + /** This method will initialize the cassandra data base property */ + private static void initializeDBProperty() { + // setting db info (keyspace , table) into static map + // this map will be used during cassandra data base interaction. + // this map will have each DB name and it's corresponding keyspace and table + // name. + dbInfoMap.put(JsonKey.USER_DB, getDbInfoObject(KEY_SPACE_NAME, "user")); + dbInfoMap.put(JsonKey.USER_AUTH_DB, getDbInfoObject(KEY_SPACE_NAME, "user_auth")); + dbInfoMap.put(JsonKey.ORG_DB, getDbInfoObject(KEY_SPACE_NAME, "organisation")); + dbInfoMap.put(JsonKey.ADDRESS_DB, getDbInfoObject(KEY_SPACE_NAME, "address")); + dbInfoMap.put(JsonKey.EDUCATION_DB, getDbInfoObject(KEY_SPACE_NAME, "user_education")); + dbInfoMap.put(JsonKey.JOB_PROFILE_DB, getDbInfoObject(KEY_SPACE_NAME, "user_job_profile")); + dbInfoMap.put(JsonKey.USR_ORG_DB, getDbInfoObject(KEY_SPACE_NAME, "user_org")); + dbInfoMap.put(JsonKey.USR_EXT_ID_DB, getDbInfoObject(KEY_SPACE_NAME, "user_external_identity")); + + dbInfoMap.put(JsonKey.ORG_MAP_DB, getDbInfoObject(KEY_SPACE_NAME, "org_mapping")); + dbInfoMap.put(JsonKey.ORG_TYPE_DB, getDbInfoObject(KEY_SPACE_NAME, "org_type")); + dbInfoMap.put(JsonKey.ROLE, getDbInfoObject(KEY_SPACE_NAME, "role")); + dbInfoMap.put(JsonKey.MASTER_ACTION, getDbInfoObject(KEY_SPACE_NAME, "master_action")); + dbInfoMap.put(JsonKey.URL_ACTION, getDbInfoObject(KEY_SPACE_NAME, "url_action")); + dbInfoMap.put(JsonKey.ACTION_GROUP, getDbInfoObject(KEY_SPACE_NAME, "action_group")); + dbInfoMap.put(JsonKey.USER_ACTION_ROLE, getDbInfoObject(KEY_SPACE_NAME, "user_action_role")); + dbInfoMap.put(JsonKey.ROLE_GROUP, getDbInfoObject(KEY_SPACE_NAME, "role_group")); + dbInfoMap.put(JsonKey.USER_ORG_DB, getDbInfoObject(KEY_SPACE_NAME, "user_org")); + dbInfoMap.put(JsonKey.BULK_OP_DB, getDbInfoObject(KEY_SPACE_NAME, "bulk_upload_process")); + dbInfoMap.put(JsonKey.REPORT_TRACKING_DB, getDbInfoObject(KEY_SPACE_NAME, "report_tracking")); + dbInfoMap.put(JsonKey.BADGES_DB, getDbInfoObject(KEY_SPACE_NAME, "badge")); + dbInfoMap.put(JsonKey.USER_BADGES_DB, getDbInfoObject(KEY_SPACE_NAME, "user_badge")); + dbInfoMap.put(JsonKey.USER_NOTES_DB, getDbInfoObject(KEY_SPACE_NAME, "user_notes")); + dbInfoMap.put(JsonKey.MEDIA_TYPE_DB, getDbInfoObject(KEY_SPACE_NAME, "media_type")); + dbInfoMap.put(JsonKey.USER_SKILL_DB, getDbInfoObject(KEY_SPACE_NAME, "user_skills")); + dbInfoMap.put(JsonKey.SKILLS_LIST_DB, getDbInfoObject(KEY_SPACE_NAME, "skills")); + dbInfoMap.put( + JsonKey.TENANT_PREFERENCE_DB, getDbInfoObject(KEY_SPACE_NAME, "tenant_preference")); + dbInfoMap.put(JsonKey.GEO_LOCATION_DB, getDbInfoObject(KEY_SPACE_NAME, "geo_location")); + + dbInfoMap.put(JsonKey.CLIENT_INFO_DB, getDbInfoObject(KEY_SPACE_NAME, "client_info")); + dbInfoMap.put(JsonKey.SYSTEM_SETTINGS_DB, getDbInfoObject(KEY_SPACE_NAME, "system_settings")); + + dbInfoMap.put( + BadgingJsonKey.USER_BADGE_ASSERTION_DB, + getDbInfoObject(KEY_SPACE_NAME, "user_badge_assertion")); + dbInfoMap.put(JsonKey.USER_CERT, getDbInfoObject(KEY_SPACE_NAME, JsonKey.USER_CERT)); + dbInfoMap.put(JsonKey.USER_FEED_DB, getDbInfoObject(KEY_SPACE_NAME, JsonKey.USER_FEED_DB)); + } + + /** + * This method will take org current state and next state and check is it possible to move + * organization from current state to next state if possible to move then return true else false. + * + * @param currentState String + * @param nextState String + * @return boolean + */ + @SuppressWarnings("rawtypes") + public static boolean checkOrgStatusTransition(Integer currentState, Integer nextState) { + List list = orgStatusTransition.get(currentState); + if (null == list) { + return false; + } + return list.contains(nextState); + } + + /** + * This method will check the cassandra data base connection. first it will try to established the + * data base connection from provided environment variable , if environment variable values are + * not set then connection will be established from property file. + */ + public static void checkCassandraDbConnections() { + CassandraConnectionManager cassandraConnectionManager = + CassandraConnectionMngrFactory.getInstance(); + String nodes = System.getenv(JsonKey.SUNBIRD_CASSANDRA_IP); + String[] hosts = null; + if (StringUtils.isNotBlank(nodes)) { + hosts = nodes.split(","); + } else { + hosts = new String[] {"localhost"}; + } + cassandraConnectionManager.createConnection(hosts); + } + + public static String getProperty(String key) { + return prop.getProperty(key); + } + + private static DbInfo getDbInfoObject(String keySpace, String table) { + + DbInfo dbInfo = new DbInfo(); + + dbInfo.setKeySpace(keySpace); + dbInfo.setTableName(table); + + return dbInfo; + } + + /** class to hold cassandra db info. */ + public static class DbInfo { + private String keySpace; + private String tableName; + private String userName; + private String password; + private String ip; + private String port; + + /** + * @param keySpace + * @param tableName + * @param userName + * @param password + */ + DbInfo( + String keySpace, + String tableName, + String userName, + String password, + String ip, + String port) { + this.keySpace = keySpace; + this.tableName = tableName; + this.userName = userName; + this.password = password; + this.ip = ip; + this.port = port; + } + + /** No-arg constructor */ + DbInfo() {} + + @Override + public boolean equals(Object obj) { + if (obj instanceof DbInfo) { + DbInfo ob = (DbInfo) obj; + if (this.ip.equals(ob.getIp()) + && this.port.equals(ob.getPort()) + && this.keySpace.equals(ob.getKeySpace())) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return 1; + } + + public String getKeySpace() { + return keySpace; + } + + public void setKeySpace(String keySpace) { + this.keySpace = keySpace; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getIp() { + return ip; + } + + public String getPort() { + return port; + } + } + + /** + * This method will take searchQuery map and internally it will convert map to SearchDto object. + * + * @param searchQueryMap Map + * @return SearchDTO + */ + @SuppressWarnings("unchecked") + public static SearchDTO createSearchDto(Map searchQueryMap) { + SearchDTO search = new SearchDTO(); + if (searchQueryMap.containsKey(JsonKey.QUERY)) { + search.setQuery((String) searchQueryMap.get(JsonKey.QUERY)); + } + if (searchQueryMap.containsKey(JsonKey.QUERY_FIELDS)) { + search.setQueryFields((List) searchQueryMap.get(JsonKey.QUERY_FIELDS)); + } + if (searchQueryMap.containsKey(JsonKey.FACETS)) { + search.setFacets((List>) searchQueryMap.get(JsonKey.FACETS)); + } + if (searchQueryMap.containsKey(JsonKey.FIELDS)) { + search.setFields((List) searchQueryMap.get(JsonKey.FIELDS)); + } + if (searchQueryMap.containsKey(JsonKey.FILTERS)) { + search.getAdditionalProperties().put(JsonKey.FILTERS, searchQueryMap.get(JsonKey.FILTERS)); + } + if (searchQueryMap.containsKey(JsonKey.EXISTS)) { + search.getAdditionalProperties().put(JsonKey.EXISTS, searchQueryMap.get(JsonKey.EXISTS)); + } + if (searchQueryMap.containsKey(JsonKey.NOT_EXISTS)) { + search + .getAdditionalProperties() + .put(JsonKey.NOT_EXISTS, searchQueryMap.get(JsonKey.NOT_EXISTS)); + } + if (searchQueryMap.containsKey(JsonKey.SORT_BY)) { + search + .getSortBy() + .putAll((Map) searchQueryMap.get(JsonKey.SORT_BY)); + } + if (searchQueryMap.containsKey(JsonKey.OFFSET)) { + if ((searchQueryMap.get(JsonKey.OFFSET)) instanceof Integer) { + search.setOffset((int) searchQueryMap.get(JsonKey.OFFSET)); + } else { + search.setOffset(((BigInteger) searchQueryMap.get(JsonKey.OFFSET)).intValue()); + } + } + if (searchQueryMap.containsKey(JsonKey.LIMIT)) { + if ((searchQueryMap.get(JsonKey.LIMIT)) instanceof Integer) { + search.setLimit((int) searchQueryMap.get(JsonKey.LIMIT)); + } else { + search.setLimit(((BigInteger) searchQueryMap.get(JsonKey.LIMIT)).intValue()); + } + } + if (search.getLimit() > DEFAULT_ELASTIC_DATA_LIMIT) { + search.setLimit(DEFAULT_ELASTIC_DATA_LIMIT); + } + if (search.getLimit() + search.getOffset() > DEFAULT_ELASTIC_DATA_LIMIT) { + search.setLimit(DEFAULT_ELASTIC_DATA_LIMIT - search.getOffset()); + } + if (searchQueryMap.containsKey(JsonKey.GROUP_QUERY)) { + search + .getGroupQuery() + .addAll( + (Collection>) searchQueryMap.get(JsonKey.GROUP_QUERY)); + } + if (searchQueryMap.containsKey(JsonKey.SOFT_CONSTRAINTS)) { + search.setSoftConstraints( + (Map) searchQueryMap.get(JsonKey.SOFT_CONSTRAINTS)); + } + return search; + } + + /** + * if Object is null then it will return true else false. + * + * @param obj Object + * @return boolean + */ + public static boolean isNull(Object obj) { + return null == obj ? true : false; + } + + /** + * if Object is not null then it will return true else false. + * + * @param obj Object + * @return boolean + */ + public static boolean isNotNull(Object obj) { + return null != obj ? true : false; + } + + /** + * This method will provide user name based on user id if user not found then it will return null. + * + * @param userId String + * @return String + */ + @SuppressWarnings("unchecked") + public static String getUserNamebyUserId(String userId) { + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Util.DbInfo userdbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response result = + cassandraOperation.getRecordById( + userdbInfo.getKeySpace(), userdbInfo.getTableName(), userId); + List> list = (List>) result.get(JsonKey.RESPONSE); + if (!(list.isEmpty())) { + return (String) (list.get(0).get(JsonKey.USERNAME)); + } + return null; + } + + /** + * This method will provide user details map based on user id if user not found then it will + * return null. + * + * @param userId userId of the user + * @return userDbRecord of the user from cassandra + */ + @SuppressWarnings("unchecked") + public static Map getUserbyUserId(String userId) { + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Util.DbInfo userdbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response result = + cassandraOperation.getRecordById( + userdbInfo.getKeySpace(), userdbInfo.getTableName(), userId); + List> list = (List>) result.get(JsonKey.RESPONSE); + if (!(list.isEmpty())) { + return list.get(0); + } + return null; + } + + public static String getHashTagIdFromOrgId(String orgId) { + String hashTagId = ""; + Map organisation = getOrgDetails(orgId); + hashTagId = + StringUtils.isNotEmpty((String) organisation.get(JsonKey.HASHTAGID)) + ? (String) organisation.get(JsonKey.HASHTAGID) + : (String) organisation.get(JsonKey.ID); + return hashTagId; + } + + private static Map elasticSearchComplexSearch( + Map filters, String index, String type) { + + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + + Future> mapF = esService.search(searchDTO, type); + return (Map) ElasticSearchHelper.getResponseFromFuture(mapF); + } + + public static String validateRoles(List roleList) { + Map roleMap = DataCacheHandler.getRoleMap(); + if (null != roleMap && !roleMap.isEmpty()) { + for (String role : roleList) { + if (null == roleMap.get(role.trim())) { + return role + " is not a valid role."; + } + } + } else { + ProjectLogger.log("Roles are not cached.Please Cache it."); + } + return JsonKey.SUCCESS; + } + + /** @param req Map */ + public static boolean registerChannel(Map req) { + ProjectLogger.log( + "channel registration for hashTag Id = " + req.get(JsonKey.HASHTAGID) + "", + LoggerEnum.INFO.name()); + Map headerMap = new HashMap<>(); + String header = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(header)) { + header = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } else { + header = JsonKey.BEARER + header; + } + headerMap.put(JsonKey.AUTHORIZATION, header); + headerMap.put("Content-Type", "application/json"); + headerMap.put("user-id", ""); + String reqString = ""; + String regStatus = ""; + try { + ProjectLogger.log( + "start call for registering the channel for hashTag id ==" + req.get(JsonKey.HASHTAGID), + LoggerEnum.INFO.name()); + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(ekStepBaseUrl)) { + ekStepBaseUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + Map map = new HashMap<>(); + Map reqMap = new HashMap<>(); + Map channelMap = new HashMap<>(); + channelMap.put(JsonKey.NAME, req.get(JsonKey.CHANNEL)); + channelMap.put(JsonKey.DESCRIPTION, req.get(JsonKey.DESCRIPTION)); + channelMap.put(JsonKey.CODE, req.get(JsonKey.HASHTAGID)); + if (req.containsKey(JsonKey.LICENSE) + && StringUtils.isNotBlank((String) req.get(JsonKey.LICENSE))) { + channelMap.put(JsonKey.DEFAULT_LICENSE, req.get(JsonKey.LICENSE)); + } + + String defaultFramework = (String) req.get(JsonKey.DEFAULT_FRAMEWORK); + if (StringUtils.isNotBlank(defaultFramework)) + channelMap.put(JsonKey.DEFAULT_FRAMEWORK, defaultFramework); + reqMap.put(JsonKey.CHANNEL, channelMap); + map.put(JsonKey.REQUEST, reqMap); + + reqString = mapper.writeValueAsString(map); + ProjectLogger.log( + "Util:registerChannel: Channel registration request data = " + reqString, + LoggerEnum.DEBUG.name()); + regStatus = + HttpUtil.sendPostRequest( + (ekStepBaseUrl + + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_CHANNEL_REG_API_URL)), + reqString, + headerMap); + ProjectLogger.log( + "end call for channel registration for hashTag id ==" + req.get(JsonKey.HASHTAGID), + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log( + "Exception occurred while registarting channel in ekstep." + e.getMessage(), + LoggerEnum.ERROR.name()); + } + + return regStatus.contains("OK"); + } + + /** @param req Map */ + public static boolean updateChannel(Map req) { + ProjectLogger.log( + "channel update for hashTag Id = " + req.get(JsonKey.HASHTAGID) + "", + LoggerEnum.INFO.name()); + Map headerMap = new HashMap<>(); + String header = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(header)) { + header = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } else { + header = JsonKey.BEARER + header; + } + headerMap.put(JsonKey.AUTHORIZATION, header); + headerMap.put("Content-Type", "application/json"); + headerMap.put("user-id", ""); + String reqString = ""; + String regStatus = ""; + try { + ProjectLogger.log( + "start call for updateChannel for hashTag id ==" + req.get(JsonKey.HASHTAGID), + LoggerEnum.INFO.name()); + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(ekStepBaseUrl)) { + ekStepBaseUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + Map map = new HashMap<>(); + Map reqMap = new HashMap<>(); + Map channelMap = new HashMap<>(); + channelMap.put(JsonKey.NAME, req.get(JsonKey.CHANNEL)); + channelMap.put(JsonKey.DESCRIPTION, req.get(JsonKey.DESCRIPTION)); + channelMap.put(JsonKey.CODE, req.get(JsonKey.HASHTAGID)); + String license = (String) req.get(JsonKey.LICENSE); + if (StringUtils.isNotBlank(license)) { + channelMap.put(JsonKey.DEFAULT_LICENSE, license); + } + reqMap.put(JsonKey.CHANNEL, channelMap); + map.put(JsonKey.REQUEST, reqMap); + + reqString = mapper.writeValueAsString(map); + + regStatus = + HttpUtil.sendPatchRequest( + (ekStepBaseUrl + + PropertiesCache.getInstance() + .getProperty(JsonKey.EKSTEP_CHANNEL_UPDATE_API_URL)) + + "/" + + req.get(JsonKey.HASHTAGID), + reqString, + headerMap); + ProjectLogger.log( + "end call for channel update for hashTag id ==" + req.get(JsonKey.HASHTAGID), + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log( + "Exception occurred while updating channel in ekstep. " + e.getMessage(), + LoggerEnum.ERROR.name()); + } + + return regStatus.contains("SUCCESS"); + } + + public static void initializeContext(Request request, String env) { + Map requestContext = request.getContext(); + env = StringUtils.isNotBlank(env) ? env : ""; + requestContext.put(JsonKey.ENV, env); + requestContext.put(JsonKey.REQUEST_TYPE, JsonKey.API_CALL); + + if (JsonKey.USER.equalsIgnoreCase((String) request.getContext().get(JsonKey.ACTOR_TYPE))) { + Future> resultF = + esService.getDataByIdentifier( + EsType.user.getTypeName(), (String) request.getContext().get(JsonKey.REQUESTED_BY)); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + + if (result != null) { + String rootOrgId = (String) result.get(JsonKey.ROOT_ORG_ID); + + if (StringUtils.isNotBlank(rootOrgId)) { + Map rollup = new HashMap<>(); + + rollup.put("l1", rootOrgId); + requestContext.put(JsonKey.ROLLUP, rollup); + } + } + } + } + + public static String getSunbirdWebUrlPerTenent(Map userMap) { + StringBuilder webUrl = new StringBuilder(); + String slug = ""; + if (StringUtils.isBlank(System.getenv(SUNBIRD_WEB_URL))) { + webUrl.append(propertiesCache.getProperty(SUNBIRD_WEB_URL)); + } else { + webUrl.append(System.getenv(SUNBIRD_WEB_URL)); + } + if (!StringUtils.isBlank((String) userMap.get(JsonKey.ROOT_ORG_ID))) { + Map orgMap = getOrgDetails((String) userMap.get(JsonKey.ROOT_ORG_ID)); + slug = (String) orgMap.get(JsonKey.SLUG); + } + if (!StringUtils.isBlank(slug)) { + webUrl.append("/" + slug); + } + return webUrl.toString(); + } + + /** + * As per requirement this page need to be redirect to /resources always. + * + * @return url of login page + */ + public static String getSunbirdLoginUrl() { + StringBuilder webUrl = new StringBuilder(); + String slug = "/resources"; + if (StringUtils.isBlank(System.getenv(SUNBIRD_WEB_URL))) { + webUrl.append(propertiesCache.getProperty(SUNBIRD_WEB_URL)); + } else { + webUrl.append(System.getenv(SUNBIRD_WEB_URL)); + } + webUrl.append(slug); + return webUrl.toString(); + } + + public static Map getOrgDetails(String identifier) { + DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + Response response = + cassandraOperation.getRecordById( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), identifier); + List> res = (List>) response.get(JsonKey.RESPONSE); + if (null != res && !res.isEmpty()) { + return res.get(0); + } + return Collections.emptyMap(); + } + + /** + * This method will check the uniqueness for externalId and provider combination. + * + * @param user + */ + public static void checkExternalIdUniqueness(User user, String operation) { + if (CollectionUtils.isNotEmpty(user.getExternalIds())) { + for (Map externalId : user.getExternalIds()) { + if (StringUtils.isNotBlank(externalId.get(JsonKey.ID)) + && StringUtils.isNotBlank(externalId.get(JsonKey.PROVIDER)) + && StringUtils.isNotBlank(externalId.get(JsonKey.ID_TYPE))) { + Map externalIdReq = new HashMap<>(); + externalIdReq.put(JsonKey.PROVIDER, externalId.get(JsonKey.PROVIDER)); + externalIdReq.put(JsonKey.ID_TYPE, externalId.get(JsonKey.ID_TYPE)); + externalIdReq.put(JsonKey.EXTERNAL_ID, encryptData(externalId.get(JsonKey.ID))); + Response response = + cassandraOperation.getRecordsByProperties( + KEY_SPACE_NAME, JsonKey.USR_EXT_IDNT_TABLE, externalIdReq); + List> externalIdsRecord = + (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(externalIdsRecord)) { + if (JsonKey.CREATE.equalsIgnoreCase(operation)) { + throwUserAlreadyExistsException( + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)); + } else if (JsonKey.UPDATE.equalsIgnoreCase(operation)) { + // If end user will try to add,edit or remove other user extIds throw exception + String userId = (String) externalIdsRecord.get(0).get(JsonKey.USER_ID); + if (!(user.getUserId().equalsIgnoreCase(userId))) { + if (JsonKey.ADD.equalsIgnoreCase(externalId.get(JsonKey.OPERATION)) + || StringUtils.isBlank(externalId.get(JsonKey.OPERATION))) { + throw new ProjectCommonException( + ResponseCode.externalIdAssignedToOtherUser.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.externalIdAssignedToOtherUser.getErrorMessage(), + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else { + throwExternalIDNotFoundException( + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)); + } + } + } + } else { + // if user will try to delete non existing extIds + if (JsonKey.UPDATE.equalsIgnoreCase(operation) + && JsonKey.REMOVE.equalsIgnoreCase(externalId.get(JsonKey.OPERATION))) { + throwExternalIDNotFoundException( + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)); + } + } + } + } + } + } + + public static String encryptData(String value) { + try { + return encryptionService.encryptData(value); + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + private static void throwExternalIDNotFoundException( + String externalId, String idType, String provider) { + throw new ProjectCommonException( + ResponseCode.externalIdNotFound.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.externalIdNotFound.getErrorMessage(), externalId, idType, provider), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + private static void throwUserAlreadyExistsException( + String externalId, String idType, String provider) { + throw new ProjectCommonException( + ResponseCode.userAlreadyExists.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.userAlreadyExists.getErrorMessage(), + ProjectUtil.formatMessage( + ResponseMessage.Message.EXTERNAL_ID_FORMAT, externalId, idType, provider)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + /** + * This method will search in ES for user with given search query + * + * @param searchQueryMap Query filters as Map. + * @return List List of User object. + */ + public static List searchUser(Map searchQueryMap) { + List userList = new ArrayList<>(); + Map searchRequestMap = new HashMap<>(); + searchRequestMap.put(JsonKey.FILTERS, searchQueryMap); + SearchDTO searchDto = Util.createSearchDto(searchRequestMap); + Future> resultf = + esService.search(searchDto, ProjectUtil.EsType.user.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultf); + if (MapUtils.isNotEmpty(result)) { + List> searchResult = + (List>) result.get(JsonKey.CONTENT); + if (CollectionUtils.isNotEmpty(searchResult)) { + userList = + searchResult + .stream() + .map(s -> mapper.convertValue(s, User.class)) + .collect(Collectors.toList()); + } + } + return userList; + } + + public static String getLoginId(Map userMap) { + String loginId; + if (StringUtils.isNotBlank((String) userMap.get(JsonKey.CHANNEL))) { + loginId = + (String) userMap.get(JsonKey.USERNAME) + "@" + (String) userMap.get(JsonKey.CHANNEL); + } else { + loginId = (String) userMap.get(JsonKey.USERNAME); + } + return loginId; + } + + public static void addUserExtIds(Map requestMap) { + List> externalIds = + (List>) requestMap.get(JsonKey.EXTERNAL_IDS); + if (CollectionUtils.isNotEmpty(externalIds)) { + for (Map extIdsMap : externalIds) { + if (StringUtils.isBlank(extIdsMap.get(JsonKey.OPERATION)) + || JsonKey.ADD.equalsIgnoreCase(extIdsMap.get(JsonKey.OPERATION))) { + upsertUserExternalIdentityData(extIdsMap, requestMap, JsonKey.CREATE); + } + } + } + } + + private static void upsertUserExternalIdentityData( + Map extIdsMap, Map requestMap, String operation) { + try { + Map map = new HashMap<>(); + map.put(JsonKey.EXTERNAL_ID, encryptData(extIdsMap.get(JsonKey.ID))); + map.put( + JsonKey.ORIGINAL_EXTERNAL_ID, encryptData(extIdsMap.get(JsonKey.ORIGINAL_EXTERNAL_ID))); + map.put(JsonKey.PROVIDER, extIdsMap.get(JsonKey.PROVIDER)); + map.put(JsonKey.ORIGINAL_PROVIDER, extIdsMap.get(JsonKey.ORIGINAL_PROVIDER)); + map.put(JsonKey.ID_TYPE, extIdsMap.get(JsonKey.ID_TYPE)); + map.put(JsonKey.ORIGINAL_ID_TYPE, extIdsMap.get(JsonKey.ORIGINAL_ID_TYPE)); + map.put(JsonKey.USER_ID, requestMap.get(JsonKey.USER_ID)); + if (JsonKey.CREATE.equalsIgnoreCase(operation)) { + map.put(JsonKey.CREATED_BY, requestMap.get(JsonKey.CREATED_BY)); + map.put(JsonKey.CREATED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + } else { + map.put(JsonKey.LAST_UPDATED_BY, requestMap.get(JsonKey.UPDATED_BY)); + map.put(JsonKey.LAST_UPDATED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + } + cassandraOperation.upsertRecord(KEY_SPACE_NAME, JsonKey.USR_EXT_IDNT_TABLE, map); + } catch (Exception ex) { + ProjectLogger.log("Util:upsertUserExternalIdentityData : Exception occurred", ex); + } + } + + private static List> getUserExternalIds(Map requestMap) { + List> dbResExternalIds = new ArrayList<>(); + Response response = + cassandraOperation.getRecordsByIndexedProperty( + KEY_SPACE_NAME, + JsonKey.USR_EXT_IDNT_TABLE, + JsonKey.USER_ID, + requestMap.get(JsonKey.USER_ID)); + if (null != response && null != response.getResult()) { + dbResExternalIds = (List>) response.getResult().get(JsonKey.RESPONSE); + } + return dbResExternalIds; + } + + public static void updateUserExtId(Map requestMap) { + List> dbResExternalIds = getUserExternalIds(requestMap); + List> externalIds = + (List>) requestMap.get(JsonKey.EXTERNAL_IDS); + if (CollectionUtils.isNotEmpty(externalIds)) { + // will not allow user to update idType value, if user will try to update idType will + // ignore + // user will have only one entry for a idType for given provider so get extId based on idType + // List of idType values for a user will distinct and unique + for (Map extIdMap : externalIds) { + Optional> extMap = checkExternalID(dbResExternalIds, extIdMap); + Map map = extMap.orElse(null); + // Allowed operation type for externalIds ("add", "remove", "edit") + if (JsonKey.ADD.equalsIgnoreCase(extIdMap.get(JsonKey.OPERATION)) + || StringUtils.isBlank(extIdMap.get(JsonKey.OPERATION))) { + if (MapUtils.isEmpty(map)) { + upsertUserExternalIdentityData(extIdMap, requestMap, JsonKey.CREATE); + } else { + // if external Id with same provider and idType exist then delete first then update + // to update user externalId first we need to delete the record as externalId is the + // part of composite key + deleteUserExternalId(requestMap, map); + upsertUserExternalIdentityData(extIdMap, requestMap, JsonKey.UPDATE); + } + } else { + // operation is either edit or remove + if (MapUtils.isNotEmpty(map)) { + if (JsonKey.REMOVE.equalsIgnoreCase(extIdMap.get(JsonKey.OPERATION))) { + if (StringUtils.isNotBlank(map.get(JsonKey.ID_TYPE)) + && StringUtils.isNotBlank((String) requestMap.get(JsonKey.USER_ID)) + && StringUtils.isNotBlank(map.get(JsonKey.PROVIDER))) { + deleteUserExternalId(requestMap, map); + } + } else if (JsonKey.EDIT.equalsIgnoreCase(extIdMap.get(JsonKey.OPERATION))) { + // to update user externalId first we need to delete the record as externalId is the + // part of composite key + deleteUserExternalId(requestMap, map); + upsertUserExternalIdentityData(extIdMap, requestMap, JsonKey.UPDATE); + } + } else { + throwExternalIDNotFoundException( + extIdMap.get(JsonKey.ID), + extIdMap.get(JsonKey.ID_TYPE), + extIdMap.get(JsonKey.PROVIDER)); + } + } + } + } + } + + private static Optional> checkExternalID( + List> dbResExternalIds, Map extIdMap) { + Optional> extMap = + dbResExternalIds + .stream() + .filter( + s -> { + if (((s.get(JsonKey.ID_TYPE)).equalsIgnoreCase(extIdMap.get(JsonKey.ID_TYPE))) + && ((s.get(JsonKey.PROVIDER)) + .equalsIgnoreCase(extIdMap.get(JsonKey.PROVIDER)))) { + return true; + } else { + return false; + } + }) + .findFirst(); + return extMap; + } + + private static void deleteUserExternalId( + Map requestMap, Map map) { + map.remove(JsonKey.LAST_UPDATED_BY); + map.remove(JsonKey.CREATED_BY); + map.remove(JsonKey.LAST_UPDATED_ON); + map.remove(JsonKey.CREATED_ON); + map.remove(JsonKey.EXTERNAL_ID); + map.remove(JsonKey.ORIGINAL_EXTERNAL_ID); + map.remove(JsonKey.ORIGINAL_ID_TYPE); + map.remove(JsonKey.ORIGINAL_PROVIDER); + cassandraOperation.deleteRecord(KEY_SPACE_NAME, JsonKey.USR_EXT_IDNT_TABLE, map); + } + + public static void registerUserToOrg(Map userMap) { + Map reqMap = new WeakHashMap<>(); + reqMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(1)); + reqMap.put(JsonKey.USER_ID, userMap.get(JsonKey.ID)); + if (null != userMap.get(JsonKey.ROLES)) { + reqMap.put(JsonKey.ROLES, userMap.get(JsonKey.ROLES)); + } + reqMap.put(JsonKey.ORGANISATION_ID, userMap.get(JsonKey.ORGANISATION_ID)); + reqMap.put(JsonKey.ORG_JOIN_DATE, ProjectUtil.getFormattedDate()); + reqMap.put(JsonKey.IS_DELETED, false); + if (StringUtils.isNotEmpty((String) userMap.get(JsonKey.HASHTAGID))) { + reqMap.put(JsonKey.HASHTAGID, userMap.get(JsonKey.HASHTAGID)); + } + Util.DbInfo usrOrgDb = Util.dbInfoMap.get(JsonKey.USR_ORG_DB); + try { + cassandraOperation.insertRecord(usrOrgDb.getKeySpace(), usrOrgDb.getTableName(), reqMap); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + public static String getChannel(String rootOrgId) { + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + String channel = null; + Response resultFrRootOrg = + cassandraOperation.getRecordById( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), rootOrgId); + if (CollectionUtils.isNotEmpty( + (List>) resultFrRootOrg.get(JsonKey.RESPONSE))) { + Map rootOrg = + ((List>) resultFrRootOrg.get(JsonKey.RESPONSE)).get(0); + channel = (String) rootOrg.get(JsonKey.CHANNEL); + } + return channel; + } + + @SuppressWarnings("unchecked") + public static void upsertUserOrgData(Map userMap) { + Util.DbInfo usrOrgDb = Util.dbInfoMap.get(JsonKey.USR_ORG_DB); + Map map = new WeakHashMap<>(); + map.put(JsonKey.USER_ID, userMap.get(JsonKey.ID)); + map.put(JsonKey.ORGANISATION_ID, userMap.get(JsonKey.ORGANISATION_ID)); + Response response = + cassandraOperation.getRecordsByProperties( + usrOrgDb.getKeySpace(), usrOrgDb.getTableName(), map); + List> resList = (List>) response.get(JsonKey.RESPONSE); + if (!resList.isEmpty()) { + Map res = resList.get(0); + Map reqMap = new WeakHashMap<>(); + reqMap.put(JsonKey.ID, res.get(JsonKey.ID)); + if (null != userMap.get(JsonKey.ROLES)) { + reqMap.put(JsonKey.ROLES, userMap.get(JsonKey.ROLES)); + } + reqMap.put(JsonKey.UPDATED_BY, userMap.get(JsonKey.UPDATED_BY)); + reqMap.put(JsonKey.IS_DELETED, false); + reqMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + if (StringUtils.isNotEmpty((String) userMap.get(JsonKey.HASHTAGID))) { + reqMap.put(JsonKey.HASHTAGID, userMap.get(JsonKey.HASHTAGID)); + } + try { + cassandraOperation.updateRecord(usrOrgDb.getKeySpace(), usrOrgDb.getTableName(), reqMap); + } catch (Exception e) { + ProjectLogger.log("Util:upsertUserOrgData exception : " + e.getMessage(), e); + } + } else { + Util.registerUserToOrg(userMap); + } + } + + @SuppressWarnings("unchecked") + public static Map getUserDetails(String userId, ActorRef actorRef) { + ProjectLogger.log("get user profile method call started user Id : " + userId); + Util.DbInfo userDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response response = null; + List> userList = null; + Map userDetails = null; + try { + response = + cassandraOperation.getRecordById( + userDbInfo.getKeySpace(), userDbInfo.getTableName(), userId); + userList = (List>) response.getResult().get(JsonKey.RESPONSE); + ProjectLogger.log( + "Util:getUserProfile: collecting user data to save for userId : " + userId, + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + String username = ""; + if (!(userList.isEmpty())) { + userDetails = userList.get(0); + username = (String) userDetails.get(JsonKey.USERNAME); + ProjectLogger.log("Util:getUserDetails: userId = " + userId, LoggerEnum.INFO.name()); + userDetails.put(JsonKey.ADDRESS, getAddressDetails(userId, null)); + userDetails.put(JsonKey.EDUCATION, getUserEducationDetails(userId)); + userDetails.put(JsonKey.JOB_PROFILE, getJobProfileDetails(userId)); + userDetails.put(JsonKey.ORGANISATIONS, getUserOrgDetails(userId)); + userDetails.put(JsonKey.BADGE_ASSERTIONS, getUserBadge(userId)); + userDetails.put(JsonKey.SKILLS, getUserSkills(userId)); + Map orgMap = getOrgDetails((String) userDetails.get(JsonKey.ROOT_ORG_ID)); + if (!MapUtils.isEmpty(orgMap)) { + userDetails.put(JsonKey.ROOT_ORG_NAME, orgMap.get(JsonKey.ORG_NAME)); + } else { + userDetails.put(JsonKey.ROOT_ORG_NAME, ""); + } + // save masked email and phone number + addMaskEmailAndPhone(userDetails); + checkProfileCompleteness(userDetails); + if (actorRef != null) { + checkUserProfileVisibility(userDetails, actorRef); + } + userDetails.remove(JsonKey.PASSWORD); + addEmailAndPhone(userDetails); + checkEmailAndPhoneVerified(userDetails); + } else { + ProjectLogger.log( + "Util:getUserProfile: User data not available to save in ES for userId : " + userId, + LoggerEnum.INFO.name()); + } + userDetails.put(JsonKey.USERNAME, username); + return userDetails; + } + + public static Map getUserDetails( + Map userDetails, Map orgMap) { + String userId = (String) userDetails.get(JsonKey.USER_ID); + ProjectLogger.log("get user profile method call started user Id : " + userId); + List> orgList = new ArrayList>(); + orgList.add(orgMap); + ProjectLogger.log("Util:getUserDetails: userId = " + userId, LoggerEnum.INFO.name()); + userDetails.put(JsonKey.ORGANISATIONS, orgList); + Map rootOrg = getOrgDetails((String) userDetails.get(JsonKey.ROOT_ORG_ID)); + if (!MapUtils.isEmpty(rootOrg)) { + userDetails.put(JsonKey.ROOT_ORG_NAME, orgMap.get(JsonKey.ORG_NAME)); + } else { + userDetails.put(JsonKey.ROOT_ORG_NAME, ""); + } + // save masked email and phone number + addMaskEmailAndPhone(userDetails); + userDetails.remove(JsonKey.PASSWORD); + addEmailAndPhone(userDetails); + checkEmailAndPhoneVerified(userDetails); + return userDetails; + } + + public static void addEmailAndPhone(Map userDetails) { + userDetails.put(JsonKey.PHONE, userDetails.remove(JsonKey.ENC_PHONE)); + userDetails.put(JsonKey.EMAIL, userDetails.remove(JsonKey.ENC_EMAIL)); + } + + public static void checkEmailAndPhoneVerified(Map userDetails) { + int flagsValue = Integer.parseInt(userDetails.get(JsonKey.FLAGS_VALUE).toString()); + Map userFlagMap = UserFlagUtil.assignUserFlagValues(flagsValue); + userDetails.putAll(userFlagMap); + } + + public static void checkProfileCompleteness(Map userMap) { + ProfileCompletenessService profileService = ProfileCompletenessFactory.getInstance(); + Map profileResponse = profileService.computeProfile(userMap); + userMap.putAll(profileResponse); + } + + public static void checkUserProfileVisibility(Map userMap, ActorRef actorRef) { + ProjectLogger.log( + "Util:checkUserProfileVisibility: userId = " + userMap.get(JsonKey.USER_ID), + LoggerEnum.INFO.name()); + Map userProfileVisibilityMap = + (Map) userMap.get(JsonKey.PROFILE_VISIBILITY); + Map completeProfileVisibilityMap = + getCompleteProfileVisibilityMap(userProfileVisibilityMap, actorRef); + ProjectLogger.log( + "Util:checkUserProfileVisibility: completeProfileVisibilityMap is " + + completeProfileVisibilityMap, + LoggerEnum.INFO.name()); + ProjectLogger.log( + "Util:checkUserProfileVisibility: userMap contains username and the encrypted value before removing" + + userMap.get(JsonKey.USER_NAME), + LoggerEnum.INFO.name()); + if (MapUtils.isNotEmpty(completeProfileVisibilityMap)) { + Map privateFieldsMap = new HashMap<>(); + for (String field : completeProfileVisibilityMap.keySet()) { + if (JsonKey.PRIVATE.equalsIgnoreCase(completeProfileVisibilityMap.get(field))) { + privateFieldsMap.put(field, userMap.remove(field)); + } + } + ProjectLogger.log( + "Util:checkUserProfileVisibility: private fields key are " + privateFieldsMap.keySet(), + LoggerEnum.INFO.name()); + ProjectLogger.log( + "Util:checkUserProfileVisibility: userMap contains username and the encrypted value after removing" + + userMap.get(JsonKey.USER_NAME), + LoggerEnum.INFO.name()); + esService.upsert( + ProjectUtil.EsType.userprofilevisibility.getTypeName(), + (String) userMap.get(JsonKey.USER_ID), + privateFieldsMap); + } else { + userMap.put(JsonKey.PROFILE_VISIBILITY, new HashMap()); + } + } + + public static Map getCompleteProfileVisibilityPrivateMap( + Map userProfileVisibilityMap, ActorRef actorRef) { + Map completeProfileVisibilityMap = + getCompleteProfileVisibilityMap(userProfileVisibilityMap, actorRef); + Map completeProfileVisibilityPrivateMap = new HashMap(); + for (String key : completeProfileVisibilityMap.keySet()) { + if (JsonKey.PRIVATE.equalsIgnoreCase(completeProfileVisibilityMap.get(key))) { + completeProfileVisibilityPrivateMap.put(key, JsonKey.PRIVATE); + } + } + return completeProfileVisibilityPrivateMap; + } + + public static Map getCompleteProfileVisibilityMap( + Map userProfileVisibilityMap, ActorRef actorRef) { + String defaultProfileVisibility = + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_USER_PROFILE_FIELD_DEFAULT_VISIBILITY); + if (!(JsonKey.PUBLIC.equalsIgnoreCase(defaultProfileVisibility) + || JsonKey.PRIVATE.equalsIgnoreCase(defaultProfileVisibility))) { + ProjectLogger.log( + "Util:getCompleteProfileVisibilityMap: Invalid configuration - " + + defaultProfileVisibility + + " - for default profile visibility (public / private)", + LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException(ResponseCode.invaidConfiguration, ""); + } + + Config userProfileConfig = getUserProfileConfig(actorRef); + List userDataFields = userProfileConfig.getStringList(JsonKey.FIELDS); + List publicFields = userProfileConfig.getStringList(JsonKey.PUBLIC_FIELDS); + List privateFields = userProfileConfig.getStringList(JsonKey.PRIVATE_FIELDS); + + // Order of preference - public/private fields settings, user settings, global settings + Map completeProfileVisibilityMap = new HashMap(); + for (String field : userDataFields) { + completeProfileVisibilityMap.put(field, defaultProfileVisibility); + } + completeProfileVisibilityMap.putAll(userProfileVisibilityMap); + for (String field : publicFields) { + completeProfileVisibilityMap.put(field, JsonKey.PUBLIC); + } + for (String field : privateFields) { + completeProfileVisibilityMap.put(field, JsonKey.PRIVATE); + } + + return completeProfileVisibilityMap; + } + + public static void addMaskEmailAndPhone(Map userMap) { + String phone = (String) userMap.get(JsonKey.PHONE); + String email = (String) userMap.get(JsonKey.EMAIL); + userMap.put(JsonKey.ENC_PHONE, phone); + userMap.put(JsonKey.ENC_EMAIL, email); + if (!StringUtils.isBlank(phone)) { + userMap.put(JsonKey.PHONE, maskingService.maskPhone(decService.decryptData(phone))); + } + if (!StringUtils.isBlank(email)) { + userMap.put(JsonKey.EMAIL, maskingService.maskEmail(decService.decryptData(email))); + } + } + + public static List> getUserSkills(String userId) { + Util.DbInfo userSkillDbInfo = Util.dbInfoMap.get(JsonKey.USER_SKILL_DB); + Response skillresponse = + cassandraOperation.getRecordsByIndexedProperty( + userSkillDbInfo.getKeySpace(), userSkillDbInfo.getTableName(), JsonKey.USER_ID, userId); + List> responseList = + (List>) skillresponse.get(JsonKey.RESPONSE); + return responseList; + } + + public static List> getUserBadge(String userId) { + DbInfo badgeDbInfo = Util.dbInfoMap.get(JsonKey.USER_BADGE_ASSERTION_DB); + List> badges = new ArrayList<>(); + try { + Response result = + cassandraOperation.getRecordsByIndexedProperty( + badgeDbInfo.getKeySpace(), badgeDbInfo.getTableName(), JsonKey.USER_ID, userId); + badges = (List>) result.get(JsonKey.RESPONSE); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return badges; + } + + public static List> getUserOrgDetails(String userId) { + List> userOrgList = null; + List> userOrganisations = new ArrayList<>(); + try { + Map reqMap = new WeakHashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + reqMap.put(JsonKey.IS_DELETED, false); + Util.DbInfo orgUsrDbInfo = Util.dbInfoMap.get(JsonKey.USER_ORG_DB); + Response result = + cassandraOperation.getRecordsByProperties( + orgUsrDbInfo.getKeySpace(), orgUsrDbInfo.getTableName(), reqMap); + userOrgList = (List>) result.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(userOrgList)) { + List organisationIds = + userOrgList + .stream() + .map(m -> (String) m.get(JsonKey.ORGANISATION_ID)) + .distinct() + .collect(Collectors.toList()); + List fields = Arrays.asList(JsonKey.ORG_NAME, JsonKey.PARENT_ORG_ID, JsonKey.ID); + + Future>> orgInfoMapF = + esService.getEsResultByListOfIds( + organisationIds, fields, EsType.organisation.getTypeName()); + Map> orgInfoMap = + (Map>) + ElasticSearchHelper.getResponseFromFuture(orgInfoMapF); + + for (Map userOrg : userOrgList) { + Map esOrgMap = orgInfoMap.get(userOrg.get(JsonKey.ORGANISATION_ID)); + esOrgMap.remove(JsonKey.ID); + userOrg.putAll(esOrgMap); + userOrganisations.add(userOrg); + } + } + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return userOrganisations; + } + + public static List> getJobProfileDetails(String userId) { + Util.DbInfo jobProDbInfo = Util.dbInfoMap.get(JsonKey.JOB_PROFILE_DB); + List> userJobProfileList = new ArrayList<>(); + Response jobProfileResponse; + try { + ProjectLogger.log("collecting user jobprofile user Id : " + userId); + jobProfileResponse = + cassandraOperation.getRecordsByIndexedProperty( + jobProDbInfo.getKeySpace(), jobProDbInfo.getTableName(), JsonKey.USER_ID, userId); + userJobProfileList = + (List>) jobProfileResponse.getResult().get(JsonKey.RESPONSE); + ProjectLogger.log("collecting user jobprofile collection completed userId : " + userId); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + for (Map jobProfile : userJobProfileList) { + String addressId = (String) jobProfile.get(JsonKey.ADDRESS_ID); + if (!StringUtils.isBlank(addressId)) { + List> addrList = getAddressDetails(null, addressId); + if (CollectionUtils.isNotEmpty(addrList)) jobProfile.put(JsonKey.ADDRESS, addrList.get(0)); + } + } + return userJobProfileList; + } + + public static List> getUserEducationDetails(String userId) { + Util.DbInfo eduDbInfo = Util.dbInfoMap.get(JsonKey.EDUCATION_DB); + List> userEducationList = new ArrayList<>(); + Response eduResponse = null; + try { + eduResponse = + cassandraOperation.getRecordsByIndexedProperty( + eduDbInfo.getKeySpace(), eduDbInfo.getTableName(), JsonKey.USER_ID, userId); + userEducationList = (List>) eduResponse.getResult().get(JsonKey.RESPONSE); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + for (Map eduMap : userEducationList) { + String addressId = (String) eduMap.get(JsonKey.ADDRESS_ID); + if (!StringUtils.isBlank(addressId)) { + List> addrList = getAddressDetails(null, addressId); + if (CollectionUtils.isNotEmpty(addrList)) eduMap.put(JsonKey.ADDRESS, addrList.get(0)); + } + } + return userEducationList; + } + + public static List> getAddressDetails(String userId, String addressId) { + Util.DbInfo addrDbInfo = Util.dbInfoMap.get(JsonKey.ADDRESS_DB); + List> userAddressList = new ArrayList<>(); + Response addrResponse = null; + try { + if (StringUtils.isNotBlank(userId)) { + ProjectLogger.log("collecting user address operation user Id : " + userId); + String encUserId = encryptData(userId); + addrResponse = + cassandraOperation.getRecordsByIndexedProperty( + addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), JsonKey.USER_ID, encUserId); + } else { + addrResponse = + cassandraOperation.getRecordById( + addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), addressId); + } + userAddressList = (List>) addrResponse.getResult().get(JsonKey.RESPONSE); + ProjectLogger.log("collecting user address operation completed user Id : " + userId); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return userAddressList; + } + + public static Request sendOnboardingMail(Map emailTemplateMap) { + Request request = null; + if ((StringUtils.isNotBlank((String) emailTemplateMap.get(JsonKey.EMAIL)))) { + String envName = propertiesCache.getProperty(JsonKey.SUNBIRD_INSTALLATION_DISPLAY_NAME); + String welcomeSubject = propertiesCache.getProperty(JsonKey.ONBOARDING_MAIL_SUBJECT); + emailTemplateMap.put(JsonKey.SUBJECT, ProjectUtil.formatMessage(welcomeSubject, envName)); + List reciptientsMail = new ArrayList<>(); + reciptientsMail.add((String) emailTemplateMap.get(JsonKey.EMAIL)); + emailTemplateMap.put(JsonKey.RECIPIENT_EMAILS, reciptientsMail); + emailTemplateMap.put( + JsonKey.BODY, propertiesCache.getProperty(JsonKey.ONBOARDING_WELCOME_MAIL_BODY)); + emailTemplateMap.put(JsonKey.NOTE, propertiesCache.getProperty(JsonKey.MAIL_NOTE)); + emailTemplateMap.put(JsonKey.ORG_NAME, envName); + String welcomeMessage = propertiesCache.getProperty(JsonKey.ONBOARDING_MAIL_MESSAGE); + emailTemplateMap.put( + JsonKey.WELCOME_MESSAGE, ProjectUtil.formatMessage(welcomeMessage, envName)); + + emailTemplateMap.put(JsonKey.EMAIL_TEMPLATE_TYPE, "welcome"); + setRequiredActionLink(emailTemplateMap); + if (StringUtils.isBlank((String) emailTemplateMap.get(JsonKey.SET_PASSWORD_LINK)) + && StringUtils.isBlank((String) emailTemplateMap.get(JsonKey.VERIFY_EMAIL_LINK))) { + ProjectLogger.log( + "Util:sendOnboardingMail: Email not sent as generated link is empty", LoggerEnum.ERROR); + return null; + } + + request = new Request(); + request.setOperation(BackgroundOperations.emailService.name()); + request.put(JsonKey.EMAIL_REQUEST, emailTemplateMap); + } + return request; + } + + private static void setRequiredActionLink(Map templateMap) { + String setPasswordLink = (String) templateMap.get(JsonKey.SET_PASSWORD_LINK); + String verifyEmailLink = (String) templateMap.get(JsonKey.VERIFY_EMAIL_LINK); + if (StringUtils.isNotBlank(setPasswordLink)) { + templateMap.put(JsonKey.LINK, setPasswordLink); + templateMap.put(JsonKey.SET_PW_LINK, "true"); + } else if (StringUtils.isNotBlank(verifyEmailLink)) { + templateMap.put(JsonKey.LINK, verifyEmailLink); + templateMap.put(JsonKey.SET_PW_LINK, null); + } + } + + public static String getUserRequiredActionLink( + Map templateMap, boolean isUrlShortRequired) { + URLShortner urlShortner = new URLShortnerImpl(); + String redirectUri = + StringUtils.isNotBlank((String) templateMap.get(JsonKey.REDIRECT_URI)) + ? ((String) templateMap.get(JsonKey.REDIRECT_URI)) + : null; + ProjectLogger.log( + "Util:getUserRequiredActionLink redirectURI = " + redirectUri, LoggerEnum.INFO.name()); + if (StringUtils.isBlank((String) templateMap.get(JsonKey.PASSWORD))) { + String url = + KeycloakRequiredActionLinkUtil.getLink( + (String) templateMap.get(JsonKey.USERNAME), + redirectUri, + KeycloakRequiredActionLinkUtil.UPDATE_PASSWORD); + + templateMap.put( + JsonKey.SET_PASSWORD_LINK, isUrlShortRequired ? urlShortner.shortUrl(url) : url); + return isUrlShortRequired ? urlShortner.shortUrl(url) : url; + + } else { + String url = + KeycloakRequiredActionLinkUtil.getLink( + (String) templateMap.get(JsonKey.USERNAME), + redirectUri, + KeycloakRequiredActionLinkUtil.VERIFY_EMAIL); + templateMap.put( + JsonKey.VERIFY_EMAIL_LINK, isUrlShortRequired ? urlShortner.shortUrl(url) : url); + return isUrlShortRequired ? urlShortner.shortUrl(url) : url; + } + } + + public static void getUserRequiredActionLink(Map templateMap) { + getUserRequiredActionLink(templateMap, true); + } + + public static void sendSMS(Map userMap) { + if (StringUtils.isNotBlank((String) userMap.get(JsonKey.PHONE))) { + String envName = propertiesCache.getProperty(JsonKey.SUNBIRD_INSTALLATION_DISPLAY_NAME); + setRequiredActionLink(userMap); + if (StringUtils.isBlank((String) userMap.get(JsonKey.SET_PASSWORD_LINK)) + && StringUtils.isBlank((String) userMap.get(JsonKey.VERIFY_EMAIL_LINK))) { + ProjectLogger.log( + "Util:sendSMS: SMS not sent as generated link is empty", LoggerEnum.ERROR); + return; + } + Map smsTemplate = new HashMap<>(); + smsTemplate.put("instanceName", envName); + smsTemplate.put(JsonKey.LINK, (String) userMap.get(JsonKey.LINK)); + smsTemplate.put(JsonKey.SET_PW_LINK, (String) userMap.get(JsonKey.SET_PW_LINK)); + String sms = ProjectUtil.getSMSBody(smsTemplate); + if (StringUtils.isBlank(sms)) { + sms = PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_DEFAULT_WELCOME_MSG); + } + ProjectLogger.log("SMS text : " + sms, LoggerEnum.INFO); + String countryCode = ""; + if (StringUtils.isBlank((String) userMap.get(JsonKey.COUNTRY_CODE))) { + countryCode = + PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_DEFAULT_COUNTRY_CODE); + } else { + countryCode = (String) userMap.get(JsonKey.COUNTRY_CODE); + } + ISmsProvider smsProvider = SMSFactory.getInstance("91SMS"); + ProjectLogger.log( + "SMS text : " + sms + " with phone " + (String) userMap.get(JsonKey.PHONE), + LoggerEnum.INFO.name()); + boolean response = smsProvider.send((String) userMap.get(JsonKey.PHONE), countryCode, sms); + ProjectLogger.log("Response from smsProvider : " + response, LoggerEnum.INFO); + if (response) { + ProjectLogger.log( + "Welcome Message sent successfully to ." + (String) userMap.get(JsonKey.PHONE), + LoggerEnum.INFO.name()); + } else { + ProjectLogger.log( + "Welcome Message failed for ." + (String) userMap.get(JsonKey.PHONE), + LoggerEnum.INFO.name()); + } + } + } + + /* + * Get user profile configuration from system settings + * + * @param getSystemSetting actor reference + * @return user profile configuration + */ + public static Config getUserProfileConfig(ActorRef actorRef) { + SystemSetting userProfileConfigSetting = + getSystemSettingByField(JsonKey.USER_PROFILE_CONFIG, actorRef); + String userProfileConfigString = userProfileConfigSetting.getValue(); + Config userProfileConfig = + ConfigUtil.getConfigFromJsonString(userProfileConfigString, JsonKey.USER_PROFILE_CONFIG); + validateUserProfileConfig(userProfileConfig); + return userProfileConfig; + } + + private static void validateUserProfileConfig(Config userProfileConfig) { + if (CollectionUtils.isEmpty(userProfileConfig.getStringList(JsonKey.FIELDS))) { + ProjectLogger.log( + "Util:validateUserProfileConfig: User profile fields is not configured.", + LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException(ResponseCode.invaidConfiguration, ""); + } + List publicFields = null; + List privateFields = null; + try { + publicFields = userProfileConfig.getStringList(JsonKey.PUBLIC_FIELDS); + privateFields = userProfileConfig.getStringList(JsonKey.PRIVATE_FIELDS); + } catch (Exception e) { + ProjectLogger.log( + "Util:validateUserProfileConfig: Invalid configuration for public / private fields.", + LoggerEnum.ERROR.name()); + } + + if (CollectionUtils.isNotEmpty(privateFields) && CollectionUtils.isNotEmpty(publicFields)) { + for (String field : publicFields) { + if (privateFields.contains(field)) { + ProjectLogger.log( + "Field " + + field + + " in user configuration is conflicting in publicFields and privateFields.", + LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException( + ResponseCode.errorConflictingFieldConfiguration, + ProjectUtil.formatMessage( + ResponseCode.errorConflictingFieldConfiguration.getErrorMessage(), + field, + JsonKey.USER, + JsonKey.PUBLIC_FIELDS, + JsonKey.PRIVATE_FIELDS)); + } + } + } + } + + /* + * Method to fetch a system setting based on given system setting field + * + * @param system setting field + * @param getSystemSetting actor reference + * @return system setting + */ + public static SystemSetting getSystemSettingByField( + String systemSettingField, ActorRef actorRef) { + SystemSetting systemSetting = null; + try { + SystemSettingClient client = SystemSettingClientImpl.getInstance(); + systemSetting = client.getSystemSettingByField(actorRef, systemSettingField); + if (null == systemSetting || null == systemSetting.getValue()) { + throw new Exception(); + } + } catch (Exception e) { + ProjectLogger.log( + "Util:getSystemSettingByField: System setting not found for field - " + + systemSettingField, + e); + ProjectCommonException.throwServerErrorException( + ResponseCode.errorSystemSettingNotFound, + ProjectUtil.formatMessage( + ResponseCode.errorSystemSettingNotFound.getErrorMessage(), systemSettingField)); + } + return systemSetting; + } + + public static Request sendResetPassMail(Map emailTemplateMap) { + Request request = null; + if (StringUtils.isBlank((String) emailTemplateMap.get(JsonKey.SET_PASSWORD_LINK))) { + ProjectLogger.log( + "Util:sendResetPassMail: Email not sent as generated link is empty", + LoggerEnum.ERROR.name()); + return null; + } else if ((StringUtils.isNotBlank((String) emailTemplateMap.get(JsonKey.EMAIL)))) { + String envName = propertiesCache.getProperty(JsonKey.SUNBIRD_INSTALLATION_DISPLAY_NAME); + String welcomeSubject = propertiesCache.getProperty(JsonKey.SUNBIRD_RESET_PASS_MAIL_SUBJECT); + emailTemplateMap.put(JsonKey.SUBJECT, ProjectUtil.formatMessage(welcomeSubject, envName)); + List reciptientsMail = new ArrayList<>(); + reciptientsMail.add((String) emailTemplateMap.get(JsonKey.EMAIL)); + emailTemplateMap.put(JsonKey.RECIPIENT_EMAILS, reciptientsMail); + emailTemplateMap.put(JsonKey.ORG_NAME, envName); + emailTemplateMap.put(JsonKey.EMAIL_TEMPLATE_TYPE, "resetPassword"); + setRequiredActionLink(emailTemplateMap); + } else if (StringUtils.isNotBlank((String) emailTemplateMap.get(JsonKey.PHONE))) { + emailTemplateMap.put( + JsonKey.BODY, + ProjectUtil.formatMessage( + propertiesCache.getProperty("sunbird_reset_pass_msg"), + (String) emailTemplateMap.get(JsonKey.SET_PASSWORD_LINK))); + emailTemplateMap.put(JsonKey.MODE, "SMS"); + List phoneList = new ArrayList(); + phoneList.add((String) emailTemplateMap.get(JsonKey.PHONE)); + emailTemplateMap.put(JsonKey.RECIPIENT_PHONES, phoneList); + } else { + ProjectLogger.log( + "Util:sendResetPassMail: requested data is neither having email nor phone ", + LoggerEnum.ERROR.name()); + return null; + } + request = new Request(); + request.setOperation(BackgroundOperations.emailService.name()); + request.put(JsonKey.EMAIL_REQUEST, emailTemplateMap); + return request; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/BaseMetricsActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/BaseMetricsActor.java new file mode 100644 index 0000000000..bed10df82b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/BaseMetricsActor.java @@ -0,0 +1,505 @@ +package org.sunbird.metrics.actors; + +import static org.sunbird.common.models.util.ProjectUtil.isNotNull; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.HttpClientBuilder; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; + +public abstract class BaseMetricsActor extends BaseActor { + + private static ObjectMapper mapper = new ObjectMapper(); + public static final String STARTDATE = "startDate"; + public static final String ENDDATE = "endDate"; + public static final String START_TIME_MILLIS = "startTimeMillis"; + public static final String END_TIME_MILLIS = "endTimeMillis"; + public static final String LTE = "<="; + public static final String LT = "<"; + public static final String GTE = ">="; + public static final String GT = ">"; + public static final String KEY = "key"; + public static final String KEYNAME = "key_name"; + public static final String GROUP_ID = "group_id"; + public static final String VALUE = "value"; + public static final String INTERVAL = "interval"; + public static final String FORMAT = "format"; + protected static final String USER_ID = "user_id"; + protected static final String FOLDERPATH = "/data/"; + protected static final String FILENAMESEPARATOR = "_"; + private static final String CHARSETS_UTF_8 = "UTF-8"; + + protected Map addSnapshot( + String keyName, String name, Object value, String timeUnit) { + Map snapshot = new LinkedHashMap<>(); + snapshot.put(JsonKey.NAME, name); + snapshot.put(VALUE, value); + if (!StringUtils.isBlank(timeUnit)) { + snapshot.put(JsonKey.TIME_UNIT, timeUnit); + } + return snapshot; + } + + /** + * This method will provide date day range period. It will take parameter as "xd" where x is an + * int value. Based on passed parameter it will provide startDate and endDate range. EndDate will + * be calculated excluding current date. + * + * @param period Date range in format of "xd" EX: 7d + * @return Map having keys ENDDATE,END_TIME_MILLIS,INTERVAL,FORMAT,STARTDATE,START_TIME_MILLIS + */ + protected static Map getStartAndEndDateForDay(String period) { + Map dateMap = new HashMap<>(); + int days = getDaysByPeriod(period); + Date endDateValue = null; + Calendar calendar = Calendar.getInstance(); + calendar.setTimeZone(TimeZone.getTimeZone("GMT")); + calendar.set( + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH), + 23, + 59, + 59); + calendar.add(Calendar.DATE, -1); + calendar.add(Calendar.HOUR, -5); + calendar.add(Calendar.MINUTE, -30); + endDateValue = calendar.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(endDateValue.getTime()); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + cal.add(Calendar.DATE, -(days)); + cal.add(Calendar.SECOND, +1); + String startDateStr = sdf.format(cal.getTimeInMillis()); + String endDateStr = sdf.format(endDateValue.getTime()); + dateMap.put(INTERVAL, "1d"); + dateMap.put(FORMAT, "yyyy-MM-dd"); + dateMap.put(STARTDATE, startDateStr); + dateMap.put(ENDDATE, endDateStr); + dateMap.put(START_TIME_MILLIS, cal.getTimeInMillis()); + dateMap.put(END_TIME_MILLIS, endDateValue.getTime()); + return dateMap; + } + + protected static Map getStartAndEndDate(String period) { + if ("5w".equalsIgnoreCase(period)) { + return getStartAndEndDateForWeek(period); + } else { + return getStartAndEndDateForDay(period); + } + } + + /** + * This method will provide date week range. it will take request param as "xw" where x is a int. + * Example if user pass "5w" ,it means this method will calculate 5 calendar week from now and + * provide start date of first week and end data of 5th week. + * + * @param period number of week in "xw" format , where x is an int value. + * @return Map having keys ENDDATE,END_TIME_MILLIS,INTERVAL,FORMAT,STARTDATE,START_TIME_MILLIS + */ + protected static Map getStartAndEndDateForWeek(String period) { + Map dateMap = new HashMap<>(); + Map periodMap = getDaysByPeriodStr(period); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeZone(TimeZone.getTimeZone("GMT")); + int firstDayOfWeek = calendar.getFirstDayOfWeek(); + calendar.add(Calendar.DATE, -(calendar.get(Calendar.DAY_OF_WEEK) - firstDayOfWeek)); + calendar.add(Calendar.WEEK_OF_YEAR, 1); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + String endDateStr = sdf.format(calendar.getTime()); + dateMap.put(ENDDATE, endDateStr); + dateMap.put(END_TIME_MILLIS, calendar.getTimeInMillis()); + calendar.add(periodMap.get(KEY), -(periodMap.get(VALUE))); + calendar.add(Calendar.DATE, 1); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + dateMap.put(INTERVAL, "1w"); + dateMap.put(FORMAT, "yyyy-ww"); + String startDateStr = sdf.format(calendar.getTime()); + dateMap.put(STARTDATE, startDateStr); + dateMap.put(START_TIME_MILLIS, calendar.getTimeInMillis()); + return dateMap; + } + + protected static int getDaysByPeriod(String period) { + int days = 0; + switch (period) { + case "7d": + days = 7; + break; + + case "14d": + days = 14; + break; + + case "5w": + days = 35; + break; + + default: + days = 0; + break; + } + if (days == 0) { + throw new ProjectCommonException( + ResponseCode.invalidPeriod.getErrorCode(), + ResponseCode.invalidPeriod.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return days; + } + + protected static Map getDaysByPeriodStr(String period) { + Map dayPeriod = new HashMap<>(); + switch (period) { + case "7d": + dayPeriod.put(KEY, Calendar.DATE); + dayPeriod.put(VALUE, 7); + break; + + case "14d": + dayPeriod.put(KEY, Calendar.DATE); + dayPeriod.put(VALUE, 14); + break; + + case "5w": + dayPeriod.put(KEY, Calendar.WEEK_OF_YEAR); + dayPeriod.put(VALUE, 5); + break; + } + if (dayPeriod.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.invalidPeriod.getErrorCode(), + ResponseCode.invalidPeriod.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return dayPeriod; + } + + protected static String getEkstepPeriod(String period) { + String days = ""; + switch (period) { + case "7d": + days = "LAST_7_DAYS"; + break; + + case "14d": + days = "LAST_14_DAYS"; + break; + + case "5w": + days = "LAST_5_WEEKS"; + break; + + default: + throw new ProjectCommonException( + ResponseCode.invalidPeriod.getErrorCode(), + ResponseCode.invalidPeriod.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return days; + } + + protected List> createBucketStrForWeek(String periodStr) { + Map periodMap = getStartAndEndDateForWeek(periodStr); + String date = (String) periodMap.get(STARTDATE); + List> bucket = new ArrayList<>(); + Calendar cal = Calendar.getInstance(); + for (int day = 0; day < 5; day++) { + Map bucketData = new LinkedHashMap<>(); + String keyName = ""; + String key = ""; + Date dateValue = null; + try { + keyName = formatKeyNameString(date); + dateValue = new SimpleDateFormat("yyyy-MM-dd").parse(date); + cal.setTime(dateValue); + int week = cal.get(Calendar.WEEK_OF_YEAR); + key = cal.get(Calendar.YEAR) + Integer.toString(week); + date = keyName.toLowerCase().split("to")[1]; + date = date.trim(); + dateValue = new SimpleDateFormat("yyyy-MM-dd").parse(date); + cal.setTime(dateValue); + cal.add(Calendar.DATE, +1); + date = new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime()); + } catch (ParseException e) { + ProjectLogger.log("Error occurred", e); + } + bucketData.put(KEY, key); + bucketData.put(KEYNAME, keyName); + bucketData.put(VALUE, 0); + bucket.add(bucketData); + } + return bucket; + } + + protected List> createBucketStructure(String periodStr) { + if ("5w".equalsIgnoreCase(periodStr)) { + return createBucketStrForWeek(periodStr); + } else { + return createBucketStructureDays(periodStr); + } + } + + protected List> createBucketStructureDays(String periodStr) { + int days = getDaysByPeriod(periodStr); + Date date = null; + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DATE, -1); + date = calendar.getTime(); + List> bucket = new ArrayList<>(); + for (int day = days - 1; day >= 0; day--) { + Map bucketData = new LinkedHashMap<>(); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(date.getTime()); + cal.add(Calendar.DATE, -(day)); + bucketData.put(KEY, cal.getTimeInMillis()); + bucketData.put(KEYNAME, new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime())); + bucketData.put(VALUE, 0); + bucket.add(bucketData); + } + return bucket; + } + + protected static String postDataEkstep(String apiUrl, String request) { + Map headers = new HashMap<>(); + String response = null; + try { + String baseSearchUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(baseSearchUrl)) { + baseSearchUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + headers.put( + JsonKey.AUTHORIZATION, JsonKey.BEARER + System.getenv(JsonKey.EKSTEP_AUTHORIZATION)); + if (StringUtils.isBlank(headers.get(JsonKey.AUTHORIZATION))) { + headers.put( + JsonKey.AUTHORIZATION, + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION)); + headers.put("Content_Type", "application/json; charset=utf-8"); + } + response = + HttpUtil.sendPostRequest( + baseSearchUrl + PropertiesCache.getInstance().getProperty(apiUrl), request, headers); + + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + throw new ProjectCommonException( + ResponseCode.unableToConnect.getErrorCode(), + ResponseCode.unableToConnect.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return response; + } + + protected static String getDataFromEkstep(String apiUrl) { + Map headers = new HashMap<>(); + String response = null; + try { + String baseSearchUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(baseSearchUrl)) { + baseSearchUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + headers.put( + JsonKey.AUTHORIZATION, JsonKey.BEARER + System.getenv(JsonKey.EKSTEP_AUTHORIZATION)); + if (StringUtils.isBlank(headers.get(JsonKey.AUTHORIZATION))) { + headers.put( + JsonKey.AUTHORIZATION, + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION)); + headers.put("Content_Type", "application/json; charset=utf-8"); + } + response = HttpUtil.sendGetRequest(baseSearchUrl + apiUrl, headers); + + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + throw new ProjectCommonException( + ResponseCode.unableToConnect.getErrorCode(), + ResponseCode.unableToConnect.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return response; + } + + public static String makePostRequest(String baseURL, String apiURL, String body) + throws IOException { + ProjectLogger.log("Request to Ekstep for Metrics" + body); + String authKey = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(authKey)) { + authKey = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } else { + authKey = JsonKey.BEARER + authKey; + } + HttpClient client = HttpClientBuilder.create().build(); + HttpPost post = new HttpPost(baseURL + PropertiesCache.getInstance().getProperty(apiURL)); + post.addHeader("Content-Type", "application/json; charset=utf-8"); + post.addHeader(JsonKey.AUTHORIZATION, authKey); + post.setEntity(new StringEntity(body, CHARSETS_UTF_8)); + ProjectLogger.log( + "BaseMetricsActor:makePostRequest completed requested data : " + body, + LoggerEnum.INFO.name()); + ProjectLogger.log( + "BaseMetricsActor:makePostRequest completed Url : " + + baseURL + + PropertiesCache.getInstance().getProperty(apiURL), + LoggerEnum.INFO.name()); + HttpResponse response = client.execute(post); + if (response.getStatusLine().getStatusCode() != 200) { + ProjectLogger.log( + "BaseMetricsActor:makePostRequest: Status code from analytics is not 200 ", + LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.unableToConnect.getErrorCode(), + ResponseCode.unableToConnect.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + BufferedReader rd = + new BufferedReader( + new InputStreamReader(response.getEntity().getContent(), CHARSETS_UTF_8)); + + StringBuilder result = new StringBuilder(); + String line = ""; + while ((line = rd.readLine()) != null) { + result.append(line); + } + ProjectLogger.log( + "BaseMetricsActor:makePostRequest: Response from analytics store for metrics = " + + response.toString(), + LoggerEnum.INFO.name()); + return result.toString(); + } + + public static String makePostRequest(String apiURL, String body) throws IOException { + String baseSearchUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(baseSearchUrl)) { + baseSearchUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + return makePostRequest(baseSearchUrl, apiURL, body); + } + + @SuppressWarnings({"rawtypes"}) + protected List> getBucketData(Map aggKeyMap, String period) { + if (null == aggKeyMap || aggKeyMap.isEmpty()) { + return new ArrayList<>(); + } + if ("5w".equalsIgnoreCase(period)) { + return getBucketDataForWeeks(aggKeyMap); + } else { + return getBucketDataForDays(aggKeyMap); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + protected List> getBucketDataForDays(Map aggKeyMap) { + List> parentGroupList = new ArrayList<>(); + List> aggKeyList = (List>) aggKeyMap.get("buckets"); + for (Map aggKeyListMap : aggKeyList) { + Map parentCountObject = new LinkedHashMap<>(); + parentCountObject.put(KEY, aggKeyListMap.get(KEY)); + parentCountObject.put(KEYNAME, aggKeyListMap.get("key_as_string")); + parentCountObject.put(VALUE, aggKeyListMap.get("doc_count")); + parentGroupList.add(parentCountObject); + } + return parentGroupList; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + protected List> getBucketDataForWeeks(Map aggKeyMap) { + List> parentGroupList = new ArrayList<>(); + List> aggKeyList = (List>) aggKeyMap.get("buckets"); + for (Map aggKeyListMap : aggKeyList) { + Map parentCountObject = new LinkedHashMap<>(); + parentCountObject.put(KEY, formatKeyString((String) aggKeyListMap.get("key_as_string"))); + parentCountObject.put(KEYNAME, formatKeyNameString(aggKeyListMap.get(KEY))); + parentCountObject.put(VALUE, aggKeyListMap.get("doc_count")); + parentGroupList.add(parentCountObject); + } + return parentGroupList; + } + + protected String formatKeyString(String key) { + return StringUtils.remove(key, "-"); + } + + protected String formatKeyNameString(Object keyName) { + StringBuilder buffer = new StringBuilder(); + Date date = new Date(); + if (keyName instanceof Long) { + date = new Date((Long) keyName); + } else if (keyName instanceof String) { + try { + date = new SimpleDateFormat("yyyy-MM-dd").parse((String) keyName); + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + } + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.get(Calendar.DAY_OF_WEEK); + buffer.append(sdf.format(cal.getTime())).append(" To "); + cal.add(Calendar.DATE, +6); + buffer.append(sdf.format(cal.getTime())); + return buffer.toString(); + } + + @SuppressWarnings("unchecked") + protected Response metricsResponseGenerator( + String esResponse, String periodStr, Map viewData) { + Response response = new Response(); + Map responseData = new LinkedHashMap<>(); + try { + Map esData = mapper.readValue(esResponse, Map.class); + responseData.putAll(viewData); + responseData.put(JsonKey.PERIOD, periodStr); + responseData.put(JsonKey.SNAPSHOT, esData.get(JsonKey.SNAPSHOT)); + responseData.put(JsonKey.SERIES, esData.get(JsonKey.SERIES)); + } catch (IOException e) { + ProjectLogger.log("Error occurred", e); + } + response.putAll(responseData); + return response; + } + + protected SearchDTO createESRequest( + Map filters, Map aggs, List fields) { + SearchDTO searchDTO = new SearchDTO(); + + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + if (isNotNull(aggs)) { + searchDTO.getFacets().add(aggs); + } + if (isNotNull(fields)) { + searchDTO.setFields(fields); + } + return searchDTO; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/MetricsBackGroundJobActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/MetricsBackGroundJobActor.java new file mode 100644 index 0000000000..5351d484b8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/MetricsBackGroundJobActor.java @@ -0,0 +1,310 @@ +package org.sunbird.metrics.actors; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.velocity.VelocityContext; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.ReportTrackingStatus; +import org.sunbird.common.models.util.azure.CloudService; +import org.sunbird.common.models.util.azure.CloudServiceFactory; +import org.sunbird.common.models.util.mail.SendMail; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.notificationservice.dao.EmailTemplateDao; +import org.sunbird.learner.actors.notificationservice.dao.impl.EmailTemplateDaoImpl; +import org.sunbird.learner.util.Util; + +/** Created by arvind on 28/8/17. */ +@ActorConfig( + tasks = {}, + asyncTasks = {"fileGenerationAndUpload", "processData"} +) +public class MetricsBackGroundJobActor extends BaseActor { + + private Util.DbInfo reportTrackingdbInfo = Util.dbInfoMap.get(JsonKey.REPORT_TRACKING_DB); + private Util.DbInfo organisationDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private EmailTemplateDao emailTemplateDao = EmailTemplateDaoImpl.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + ProjectLogger.log("Operation name is ==" + operation); + if (operation.equalsIgnoreCase(ActorOperations.PROCESS_DATA.getValue())) { + processData(request); + } else if (operation.equalsIgnoreCase(ActorOperations.FILE_GENERATION_AND_UPLOAD.getValue())) { + fileGenerationAndUpload(request); + } else if (operation.equalsIgnoreCase(ActorOperations.SEND_MAIL.getValue())) { + sendMail(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void processData(Request actorMessage) { + ProjectLogger.log("In processData for metrics report"); + String operation = (String) actorMessage.getRequest().get(JsonKey.REQUEST); + String requestId = (String) actorMessage.getRequest().get(JsonKey.REQUEST_ID); + Request metricsRequest = new Request(); + Map request = new HashMap<>(); + request.put(JsonKey.REQUEST_ID, requestId); + if (JsonKey.OrgCreation.equalsIgnoreCase(operation)) { + metricsRequest.setOperation(ActorOperations.ORG_CREATION_METRICS_DATA.getValue()); + metricsRequest.setRequest(request); + tellToAnother(metricsRequest); + } else if (JsonKey.OrgConsumption.equalsIgnoreCase(operation)) { + metricsRequest.setOperation(ActorOperations.ORG_CONSUMPTION_METRICS_DATA.getValue()); + metricsRequest.setRequest(request); + tellToAnother(metricsRequest); + } + } + + @SuppressWarnings("unchecked") + private void sendMail(Request request) { + ProjectLogger.log("In sendMail for metrics Report"); + Map map = request.getRequest(); + SimpleDateFormat simpleDateFormat = ProjectUtil.getDateFormatter(); + simpleDateFormat.setLenient(false); + String requestId = (String) map.get(JsonKey.REQUEST_ID); + + // fetch the DB details from database on basis of requestId .... + Response response = + cassandraOperation.getRecordById( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), requestId); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (responseList.isEmpty()) { + ProjectLogger.log("Invalid data"); + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + Map reportDbInfo = responseList.get(0); + Map dbReqMap = new HashMap<>(); + dbReqMap.put(JsonKey.ID, requestId); + + if (processMailSending(reportDbInfo, map)) { + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.SENDING_MAIL_SUCCESS.getValue()); + dbReqMap.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + } else { + increasetryCount(reportDbInfo); + if ((Integer) reportDbInfo.get(JsonKey.TRY_COUNT) > 3) { + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.FAILED.getValue()); + dbReqMap.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + } else { + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.SENDING_MAIL.getValue()); + dbReqMap.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + } + } + } + + private void increasetryCount(Map map) { + if (null == map.get(JsonKey.TRY_COUNT)) { + map.put(JsonKey.TRY_COUNT, 0); + } else { + Integer tryCount = (Integer) map.get(JsonKey.TRY_COUNT); + map.put(JsonKey.TRY_COUNT, tryCount + 1); + } + } + + @SuppressWarnings("unchecked") + private void fileGenerationAndUpload(Request request) throws IOException { + ProjectLogger.log("In fileGeneration and Upload"); + Map map = request.getRequest(); + String requestId = (String) map.get(JsonKey.REQUEST_ID); + SimpleDateFormat simpleDateFormat = ProjectUtil.getDateFormatter(); + simpleDateFormat.setLenient(false); + + Response response = + cassandraOperation.getRecordById( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), requestId); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (responseList.isEmpty()) { + ProjectLogger.log("Invalid data"); + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Map reportDbInfo = responseList.get(0); + String fileFormat = (String) reportDbInfo.get(JsonKey.FORMAT); + FileUtil fileUtil = FileUtil.getFileUtil(fileFormat); + + Map dbReqMap = new HashMap<>(); + dbReqMap.put(JsonKey.ID, requestId); + + List> finalList = (List>) map.get(JsonKey.DATA); + String fileName = (String) map.get(JsonKey.FILE_NAME); + if (StringUtils.isBlank(fileName)) { + fileName = "File-" + requestId; + } + File file = null; + try { + file = fileUtil.writeToFile(fileName, finalList); + } catch (Exception ex) { + ProjectLogger.log("PROCESS FAILED WHILE CONVERTING THE DATA TO FILE .", ex); + // update DB as status failed since unable to convert data to file + dbReqMap.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.FAILED.getValue()); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + throw ex; + } + + String storageUrl = null; + try { + storageUrl = processFileUpload(file, "testContainer"); + + } catch (Exception e) { + ProjectLogger.log( + "Error occurred while uploading file on storage for requset " + requestId, e); + increasetryCount(reportDbInfo); + if ((Integer) reportDbInfo.get(JsonKey.TRY_COUNT) > 3) { + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.FAILED.getValue()); + dbReqMap.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + } else { + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.UPLOADING_FILE.getValue()); + dbReqMap.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + } + throw e; + } finally { + if (ProjectUtil.isNotNull(file)) { + file.delete(); + } + } + + reportDbInfo.put(JsonKey.FILE_URL, storageUrl); + dbReqMap.put(JsonKey.FILE_URL, storageUrl); + dbReqMap.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + dbReqMap.put(JsonKey.DATA, null); + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.UPLOADING_FILE_SUCCESS.getValue()); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + + Request backGroundRequest = new Request(); + backGroundRequest.setOperation(ActorOperations.SEND_MAIL.getValue()); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUEST_ID, requestId); + innerMap.put(JsonKey.COURSE_NAME, map.get(JsonKey.COURSE_NAME)); + innerMap.put(JsonKey.BATCH_NAME, map.get(JsonKey.BATCH_NAME)); + innerMap.put(JsonKey.ROOT_ORG_ID, map.get(JsonKey.ROOT_ORG_ID)); + backGroundRequest.setRequest(innerMap); + self().tell(backGroundRequest, self()); + } + + private boolean processMailSending( + Map reportDbInfo, Map requestMap) { + + Map templateMap = new HashMap<>(); + templateMap.put(JsonKey.ACTION_URL, reportDbInfo.get(JsonKey.FILE_URL)); + templateMap.put(JsonKey.FIRST_NAME, reportDbInfo.get(JsonKey.FIRST_NAME)); + templateMap.put(JsonKey.COURSE_NAME, requestMap.get(JsonKey.COURSE_NAME)); + templateMap.put(JsonKey.BATCH_NAME, requestMap.get(JsonKey.BATCH_NAME)); + String zonedDateTime = + ZonedDateTime.parse( + (String) reportDbInfo.get(JsonKey.CREATED_DATE), + DateTimeFormatter.ofPattern(ProjectUtil.getDateFormatter().toPattern())) + .format( + DateTimeFormatter.ofPattern(JsonKey.COURSE_STAT_MAIL_DATE_TIME_PATTERN) + .withZone(ZoneId.of(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_TIMEZONE)))); + templateMap.put(JsonKey.DATE_TIME, zonedDateTime); + if (StringUtils.isNotEmpty((String) requestMap.get(JsonKey.ROOT_ORG_ID))) { + Response response = + cassandraOperation.getRecordById( + organisationDbInfo.getKeySpace(), + organisationDbInfo.getTableName(), + (String) requestMap.get(JsonKey.ROOT_ORG_ID)); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (!responseList.isEmpty() && MapUtils.isNotEmpty(responseList.get(0))) { + templateMap.put(JsonKey.ORG_NAME, responseList.get(0).get(JsonKey.ORG_NAME)); + } + } + ProjectLogger.log( + "MetricsBackGroundJobActor: processMailSending template map " + templateMap, + LoggerEnum.DEBUG); + String resource = getReportResourceName(reportDbInfo); + templateMap.put(JsonKey.ACTION_NAME, "DOWNLOAD REPORT"); + VelocityContext context = ProjectUtil.getContext(templateMap); + String courseProgressMailTemplate = + emailTemplateDao.getTemplate(JsonKey.COURSE_PROGRESS_MAIL_TEMPLATE); + return SendMail.sendMailWithBody( + new String[] {(String) reportDbInfo.get(JsonKey.EMAIL)}, + reportDbInfo.get(JsonKey.TYPE) + " for " + resource, + context, + courseProgressMailTemplate); + } + + private String getReportResourceName(Map reportDbInfo) { + + String resource = (String) reportDbInfo.get(JsonKey.RESOURCE_NAME); + if (StringUtils.isEmpty(resource)) { + resource = (String) reportDbInfo.get(JsonKey.RESOURCE_ID); + } + return resource; + } + + private String getPeriod(String period) { + if ("7d".equalsIgnoreCase(period)) { + return "7 Days"; + } else if ("14d".equalsIgnoreCase(period)) { + return "14 Days"; + } else if ("5w".equalsIgnoreCase(period)) { + return "5 Weeks"; + } else if ("fromBegining".equalsIgnoreCase(period)) { + return "from Beginning"; + } else { + return ""; + } + } + + private String processFileUpload(File file, String container) { + + String storageUrl = null; + try { + CloudService service = (CloudService) CloudServiceFactory.get("Azure"); + if (null == service) { + ProjectLogger.log("The cloud service is not available"); + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + storageUrl = service.uploadFile(container, file); + } catch (Exception e) { + ProjectLogger.log("Exception Occurred while reading file in FileUploadServiceActor", e); + throw e; + } + return storageUrl; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsActor.java new file mode 100644 index 0000000000..4c8a41f3a1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsActor.java @@ -0,0 +1,721 @@ +package org.sunbird.metrics.actors; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.ProjectUtil.ReportTrackingStatus; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import scala.concurrent.Future; + +@ActorConfig( + tasks = { + "orgCreationMetrics", + "orgConsumptionMetrics", + "orgCreationMetricsReport", + "orgConsumptionMetricsReport" + }, + asyncTasks = {} +) +public class OrganisationMetricsActor extends BaseMetricsActor { + + private static ObjectMapper mapper = new ObjectMapper(); + private static final String view = "org"; + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + private Util.DbInfo reportTrackingdbInfo = Util.dbInfoMap.get(JsonKey.REPORT_TRACKING_DB); + private DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + + @Override + public void onReceive(Request request) throws Throwable { + if (request.getOperation().equalsIgnoreCase(ActorOperations.ORG_CREATION_METRICS.getValue())) { + orgCreationMetrics(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.ORG_CONSUMPTION_METRICS.getValue())) { + orgConsumptionMetrics(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.ORG_CREATION_METRICS_REPORT.getValue())) { + orgCreationMetricsReport(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.ORG_CONSUMPTION_METRICS_REPORT.getValue())) { + orgConsumptionMetricsReport(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void orgConsumptionMetricsReport(Request actorMessage) { + ProjectLogger.log( + "OrganisationMetricsActor: orgConsumptionMetricsReport called.", LoggerEnum.INFO.name()); + String requestId = createReportTrackingEntry(actorMessage); + + Response response = new Response(); + response.put(JsonKey.REQUEST_ID, requestId); + sender().tell(response, self()); + + // assign the back ground task to background job actor ... + Request backGroundRequest = new Request(); + backGroundRequest.setOperation(ActorOperations.PROCESS_DATA.getValue()); + + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUEST_ID, requestId); + innerMap.put(JsonKey.REQUEST, JsonKey.OrgConsumption); + + backGroundRequest.setRequest(innerMap); + tellToAnother(backGroundRequest); + } + + private String createReportTrackingEntry(Request actorMessage) { + ProjectLogger.log( + "OrganisationMetricsActor: createReportTrackingEntry called.", LoggerEnum.INFO.name()); + SimpleDateFormat simpleDateFormat = ProjectUtil.getDateFormatter(); + String requestedBy = (String) actorMessage.get(JsonKey.REQUESTED_BY); + String orgId = (String) actorMessage.get(JsonKey.ORG_ID); + String period = (String) actorMessage.get(JsonKey.PERIOD); + + Future> requestedByInfoF = + esUtil.getDataByIdentifier(EsType.user.getTypeName(), requestedBy); + Map requestedByInfo = + (Map) ElasticSearchHelper.getResponseFromFuture(requestedByInfoF); + if (ProjectUtil.isNull(requestedByInfo) + || StringUtils.isBlank((String) requestedByInfo.get(JsonKey.FIRST_NAME))) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + Map orgData = validateOrg(orgId); + if (null == orgData) { + throw new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + String requestId = ProjectUtil.getUniqueIdFromTimestamp(1); + + Map requestDbInfo = new HashMap<>(); + requestDbInfo.put(JsonKey.ID, requestId); + requestDbInfo.put(JsonKey.USER_ID, requestedBy); + requestDbInfo.put(JsonKey.FIRST_NAME, requestedByInfo.get(JsonKey.FIRST_NAME)); + requestDbInfo.put(JsonKey.STATUS, ReportTrackingStatus.NEW.getValue()); + requestDbInfo.put(JsonKey.RESOURCE_ID, orgId); + requestDbInfo.put(JsonKey.PERIOD, period); + requestDbInfo.put(JsonKey.CREATED_DATE, simpleDateFormat.format(new Date())); + requestDbInfo.put(JsonKey.UPDATED_DATE, simpleDateFormat.format(new Date())); + String decryptedEmail = + decryptionService.decryptData((String) requestedByInfo.get(JsonKey.ENC_EMAIL)); + requestDbInfo.put(JsonKey.EMAIL, decryptedEmail); + requestDbInfo.put(JsonKey.FORMAT, actorMessage.get(JsonKey.FORMAT)); + requestDbInfo.put(JsonKey.RESOURCE_NAME, orgData.get(JsonKey.ORGANISATION_NAME)); + + cassandraOperation.insertRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), requestDbInfo); + + return requestId; + } + + private void orgCreationMetricsReport(Request actorMessage) { + ProjectLogger.log("OrganisationMetricsActor-orgCreationMetricsReport called"); + String requestId = createReportTrackingEntry(actorMessage); + Response response = new Response(); + response.put(JsonKey.REQUEST_ID, requestId); + sender().tell(response, self()); + + // assign the back ground task to background job actor ... + Request backGroundRequest = new Request(); + backGroundRequest.setOperation(ActorOperations.PROCESS_DATA.getValue()); + + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUEST_ID, requestId); + innerMap.put(JsonKey.REQUEST, JsonKey.OrgCreation); + backGroundRequest.setRequest(innerMap); + tellToAnother(backGroundRequest); + } + + protected Map getViewData(String orgId, Object orgName) { + Map orgData = new HashMap<>(); + Map viewData = new HashMap<>(); + orgData.put(JsonKey.ORG_ID, orgId); + orgData.put(JsonKey.ORG_NAME, orgName); + viewData.put(view, orgData); + return viewData; + } + + private String getQueryRequest(String periodStr, String orgId, String operation) { + ProjectLogger.log("orgId " + orgId); + Map dateMap = getStartAndEndDate(periodStr); + Map operationMap = new LinkedHashMap<>(); + ProjectLogger.log("period" + dateMap); + switch (operation) { + case "Create": + operationMap.put("dateKey", "createdOn"); + operationMap.put("status", OrganisationMetricsUtil.ContentStatus.Draft.name()); + operationMap.put("userActionKey", "createdBy"); + operationMap.put("contentCount", "required"); + break; + + case "Review": + operationMap.put("dateKey", "lastSubmittedOn"); + operationMap.put("status", OrganisationMetricsUtil.ContentStatus.Review.name()); + break; + + case "Publish": + operationMap.put("dateKey", "lastPublishedOn"); + operationMap.put("status", OrganisationMetricsUtil.ContentStatus.Live.name()); + operationMap.put("userActionKey", "lastPublishedBy"); + break; + + default: + operationMap.put("dateKey", ""); + operationMap.put("status", ""); + operationMap.put("userActionKey", ""); + break; + } + StringBuilder builder = new StringBuilder(); + builder + .append("{\"request\":{\"rawQuery\":{\"query\":{\"bool\":{\"must\":[{\"range\":{\"") + .append(operationMap.get("dateKey")) + .append("\":{\"gte\":\"") + .append(dateMap.get(STARTDATE) + "\",\"lte\":\"" + dateMap.get(ENDDATE) + "\"}}}") + .append(",{\"bool\":{\"should\":[{\"match\":{\"contentType.raw\":\"Resource\"}}") + .append(",{\"match\":{\"contentType.raw\":\"Collection\"}}") + .append(",{\"match\":{\"contentType.raw\":\"TextBook\"}}") + .append(",{\"match\":{\"contentType.raw\":\"TextBookUnit\"}}") + .append(",{\"match\":{\"contentType.raw\":\"Course\"}}") + .append(",{\"match\":{\"contentType.raw\":\"CourseUnit\"}}]}},") + .append("{\"match\":{\"createdFor.raw\":\"" + orgId + "\"}}") + .append(",{\"match\":{\"status.raw\":\"" + operationMap.get("status")) + .append("\"}}]}},\"aggs\":{\""); + if (operationMap.containsValue("createdOn")) { + builder + .append(operationMap.get("dateKey") + "\":{\"date_histogram\":{\"field\":\"") + .append(operationMap.get("dateKey")) + .append("\",\"interval\":\"" + dateMap.get(INTERVAL) + "\",\"format\":\"") + .append(dateMap.get(FORMAT) + "\"") + .append(",\"time_zone\":\"+05:30\",\"extended_bounds\":{\"min\":") + .append(dateMap.get(START_TIME_MILLIS) + ",\"max\":") + .append(dateMap.get(END_TIME_MILLIS) + "}}},\""); + } + builder + .append("status\":{\"terms\":{\"field\":\"status.raw\",\"include\":[\"") + .append(operationMap.get("status").toLowerCase() + "\"]},\"aggs\":{\"") + .append(operationMap.get("dateKey") + "\":{\"date_histogram\":{\"field\":\"") + .append(operationMap.get("dateKey") + "\",\"interval\":\"" + dateMap.get(INTERVAL)) + .append("\",\"format\":\"" + dateMap.get(FORMAT)) + .append("\",\"time_zone\":\"+05:30\",\"extended_bounds\":{\"min\":") + .append(dateMap.get(START_TIME_MILLIS) + ",\"max\":") + .append(dateMap.get(END_TIME_MILLIS)) + .append("}}}}}"); + if (operationMap.containsKey("userActionKey")) { + builder + .append(",\"" + operationMap.get("userActionKey") + ".count\":") + .append("{\"cardinality\":{\"field\":\"" + operationMap.get("userActionKey")) + .append(".raw\",\"precision_threshold\":100}}"); + } + + if (operationMap.containsKey("contentCount")) { + builder + .append(",\"content_count\":{\"terms\":{\"field\":\"contentType.raw\"") + .append(",\"exclude\":[\"assets\",\"plugin\",\"template\"]}},") + .append("\"total_content_count\":{\"sum_bucket\":") + .append("{\"buckets_path\":\"content_count>_count\"}}"); + } + builder.append("}}}}"); + return builder.toString(); + } + + @SuppressWarnings("unchecked") + private static Map putAggregationMap( + String responseStr, Map aggregationMap, String operation) { + try { + Map resultData = mapper.readValue(responseStr, Map.class); + resultData = (Map) resultData.get(JsonKey.RESULT); + resultData = (Map) resultData.get(JsonKey.AGGREGATIONS); + List> statusList = new ArrayList<>(); + for (Map.Entry data : resultData.entrySet()) { + if ("status".equalsIgnoreCase(data.getKey())) { + Map statusMap = new HashMap<>(); + statusMap.put(operation, data.getValue()); + statusList = (List>) aggregationMap.get(data.getKey()); + if (null == statusList) { + statusList = new ArrayList<>(); + } + statusList.add(statusMap); + aggregationMap.put(data.getKey(), statusList); + } else { + aggregationMap.put(data.getKey(), data.getValue()); + } + } + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return aggregationMap; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private String orgCreationResponseGenerator(String periodStr, Map resultData) { + String result = null; + Map responseMap = new HashMap<>(); + try { + Map snapshot = new LinkedHashMap<>(); + Map dataMap = new HashMap<>(); + dataMap.put(JsonKey.NAME, "Number of contents created"); + Map contentData = (Map) resultData.get("total_content_count"); + if (null != contentData && !contentData.isEmpty()) { + dataMap.put(VALUE, contentData.get(VALUE)); + } else { + dataMap.put(VALUE, 0); + } + snapshot.put("org.creation.content.count", dataMap); + dataMap = new HashMap<>(); + dataMap.put(JsonKey.NAME, "Number of authors"); + if (null != resultData.get("createdBy.count")) { + dataMap.putAll((Map) resultData.get("createdBy.count")); + } else { + dataMap.put(VALUE, 0); + } + snapshot.put("org.creation.authors.count", dataMap); + dataMap = new HashMap<>(); + dataMap.put(JsonKey.NAME, "Number of reviewers"); + if (null != resultData.get("lastPublishedBy.count")) { + dataMap.putAll((Map) resultData.get("lastPublishedBy.count")); + } else { + dataMap.put(VALUE, 0); + } + snapshot.put("org.creation.reviewers.count", dataMap); + dataMap = new HashMap<>(); + Object value = null; + List> valueMapList = (List>) resultData.get("status"); + Map statusValueMap = new HashMap<>(); + statusValueMap.put("live", 0); + statusValueMap.put("draft", 0); + statusValueMap.put("review", 0); + for (Map data : valueMapList) { + Map statusMap = new HashMap<>(); + List> valueList = new ArrayList<>(); + if (data.containsKey("Create")) { + statusMap = (Map) data.get("Create"); + valueList = (List>) statusMap.get("buckets"); + if (CollectionUtils.isNotEmpty(valueList)) { + statusMap = valueList.get(0); + statusValueMap.put("draft", statusMap.get("doc_count")); + statusValueMap.put("draftBucket", statusMap.get("createdOn")); + } + } else if (data.containsKey("Publish")) { + statusMap = (Map) data.get("Publish"); + valueList = (List>) statusMap.get("buckets"); + if (CollectionUtils.isNotEmpty(valueList)) { + statusMap = valueList.get(0); + statusValueMap.put("live", statusMap.get("doc_count")); + statusValueMap.put("liveBucket", statusMap.get("lastPublishedOn")); + } + } else if (data.containsKey("Review")) { + statusMap = (Map) data.get("Review"); + valueList = (List>) statusMap.get("buckets"); + if (CollectionUtils.isNotEmpty(valueList)) { + statusMap = valueList.get(0); + statusValueMap.put("review", statusMap.get("doc_count")); + statusValueMap.put("reviewBucket", statusMap.get("lastSubmittedOn")); + } + } + } + + dataMap.put(JsonKey.NAME, "Number of content items created"); + value = statusValueMap.get("draft"); + dataMap.put(VALUE, value); + snapshot.put("org.creation.content[@status=draft].count", dataMap); + dataMap = new HashMap<>(); + dataMap.put(JsonKey.NAME, "Number of content items reviewed"); + value = statusValueMap.get("review"); + dataMap.put(VALUE, value); + snapshot.put("org.creation.content[@status=review].count", dataMap); + dataMap = new HashMap<>(); + value = statusValueMap.get("live"); + dataMap.put(JsonKey.NAME, "Number of content items published"); + dataMap.put(VALUE, value); + snapshot.put("org.creation.content[@status=published].count", dataMap); + + Map series = new LinkedHashMap<>(); + // Map aggKeyMap = (Map) resultData.get("createdOn"); + // List> bucket = getBucketData(aggKeyMap, periodStr); + Map seriesData = new LinkedHashMap<>(); + /* + * if ("5w".equalsIgnoreCase(periodStr)) { seriesData.put(JsonKey.NAME, + * "Content created per week"); } else { seriesData.put(JsonKey.NAME, + * "Content created per day"); } seriesData.put(JsonKey.SPLIT, + * "content.created_on"); seriesData.put(GROUP_ID, "org.content.count"); if + * (null == bucket || bucket.isEmpty()) { bucket = + * createBucketStructure(periodStr); } seriesData.put("buckets", bucket); + * series.put("org.creation.content.created_on.count", seriesData); + */ + + Map statusList = new HashMap(); + List> statusBucket = new ArrayList<>(); + statusList = (Map) statusValueMap.get("draftBucket"); + statusBucket = getBucketData(statusList, periodStr); + if (null == statusBucket || statusBucket.isEmpty()) { + statusBucket = createBucketStructure(periodStr); + } + seriesData = new LinkedHashMap<>(); + seriesData.put(JsonKey.NAME, "Draft"); + seriesData.put(JsonKey.SPLIT, "content.created_on"); + seriesData.put(GROUP_ID, "org.content.count"); + seriesData.put("buckets", statusBucket); + series.put("org.creation.content[@status=draft].count", seriesData); + + statusList = (Map) statusValueMap.get("reviewBucket"); + statusBucket = getBucketData(statusList, periodStr); + if (null == statusBucket || statusBucket.isEmpty()) { + statusBucket = createBucketStructure(periodStr); + } + seriesData = new LinkedHashMap<>(); + seriesData.put(JsonKey.NAME, "Review"); + seriesData.put(JsonKey.SPLIT, "content.reviewed_on"); + seriesData.put(GROUP_ID, "org.content.count"); + seriesData.put("buckets", statusBucket); + series.put("org.creation.content[@status=review].count", seriesData); + + statusList = (Map) statusValueMap.get("liveBucket"); + statusBucket = getBucketData(statusList, periodStr); + if (null == statusBucket || statusBucket.isEmpty()) { + statusBucket = createBucketStructure(periodStr); + } + seriesData = new LinkedHashMap<>(); + seriesData.put(JsonKey.NAME, "Live"); + seriesData.put(JsonKey.SPLIT, "content.published_on"); + seriesData.put(GROUP_ID, "org.content.count"); + seriesData.put("buckets", statusBucket); + series.put("org.creation.content[@status=published].count", seriesData); + + responseMap.put(JsonKey.SNAPSHOT, snapshot); + responseMap.put(JsonKey.SERIES, series); + + result = mapper.writeValueAsString(responseMap); + } catch (JsonProcessingException e) { + ProjectLogger.log("Error occurred", e); + } + return result; + } + + @SuppressWarnings("unchecked") + private void orgCreationMetrics(Request actorMessage) { + ProjectLogger.log( + "OrganisationMetricsActor: orgCreationMetrics called.", LoggerEnum.INFO.name()); + try { + String periodStr = (String) actorMessage.getRequest().get(JsonKey.PERIOD); + String orgId = (String) actorMessage.getRequest().get(JsonKey.ORG_ID); + Map orgData = validateOrg(orgId); + if (null == orgData) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + String orgName = (String) orgData.get(JsonKey.ORG_NAME); + if (StringUtils.isBlank(orgName)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + + Map aggregationMap = getOrgCreationData(periodStr, orgId); + String responseFormat = orgCreationResponseGenerator(periodStr, aggregationMap); + Response response = + metricsResponseGenerator(responseFormat, periodStr, getViewData(orgId, orgName)); + sender().tell(response, self()); + } catch (ProjectCommonException e) { + ProjectLogger.log( + "OrganisationMetricsActor:orgCreationMetrics: Exception in getting org creation data: " + + e.getMessage(), + e); + sender().tell(e, self()); + return; + } catch (Exception e) { + ProjectLogger.log( + "OrganisationMetricsActor:orgCreationMetrics: Generic exception in getting org creation data: " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + private Map getOrgCreationData(String periodStr, String orgId) + throws IOException { + Map aggregationMap = new HashMap<>(); + for (String operation : OrganisationMetricsUtil.operationList) { + String request = getQueryRequest(periodStr, orgId, operation); + String analyticsBaseUrl = ProjectUtil.getConfigValue(JsonKey.ANALYTICS_API_BASE_URL); + String esResponse = + makePostRequest(analyticsBaseUrl, JsonKey.EKSTEP_ES_METRICS_API_URL, request); + aggregationMap = putAggregationMap(esResponse, aggregationMap, operation); + } + return aggregationMap; + } + + private void orgConsumptionMetrics(Request actorMessage) { + ProjectLogger.log("In orgConsumptionMetrics api"); + try { + String periodStr = (String) actorMessage.getRequest().get(JsonKey.PERIOD); + String orgId = (String) actorMessage.getRequest().get(JsonKey.ORG_ID); + Map orgData = validateOrg(orgId); + if (null == orgData) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + String orgName = (String) orgData.get(JsonKey.ORG_NAME); + String orgHashId = (String) orgData.get(JsonKey.HASHTAGID); + ProjectLogger.log( + "OrganisationMetricsActor:orgConsumptionMetrics: org hash tag id = " + orgHashId, + LoggerEnum.INFO.name()); + if (StringUtils.isBlank(orgName)) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + if (StringUtils.isBlank(orgHashId)) { + orgHashId = orgId; + } + String orgRootId = (String) orgData.get(JsonKey.ROOT_ORG_ID); + if (StringUtils.isBlank(orgRootId)) { + orgRootId = orgId; + } + ProjectLogger.log( + "OrganisationMetricsActor:orgConsumptionMetrics: root org id = " + orgRootId, + LoggerEnum.INFO.name()); + Map rootOrgData = validateOrg(orgRootId); + if (null == rootOrgData || rootOrgData.isEmpty()) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRootOrgData.getErrorCode(), + ResponseCode.invalidRootOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + String channel = (String) rootOrgData.get(JsonKey.HASHTAGID); + ProjectLogger.log( + "OrganisationMetricsActor:orgConsumptionMetrics: hash tag id = " + channel, + LoggerEnum.INFO.name()); + String responseFormat = getOrgConsumptionData(actorMessage, periodStr, orgHashId, channel); + ProjectLogger.log("Response" + responseFormat); + Response response = + metricsResponseGenerator(responseFormat, periodStr, getViewData(orgId, orgName)); + sender().tell(response, self()); + } catch (ProjectCommonException e) { + ProjectLogger.log( + "OrganisationMetricsActor:orgConsumptionMetrics: Exception in getting org consumption data: " + + e.getMessage(), + e); + sender().tell(e, self()); + return; + } catch (Exception e) { + ProjectLogger.log( + "OrganisationMetricsActor:orgConsumptionMetrics: Generic exception in getting org consumption data: " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + private String getOrgConsumptionData( + Request actorMessage, String periodStr, String orgHashId, String channel) throws IOException { + String requestStr = getOrgMetricsRequest(actorMessage, periodStr, orgHashId, null, channel); + ProjectLogger.log( + "OrganisationMetricsActor:getOrgConsumptionData Requested data : " + requestStr, + LoggerEnum.INFO.name()); + String analyticsBaseUrl = ProjectUtil.getConfigValue(JsonKey.ANALYTICS_API_BASE_URL); + String ekStepResponse = + makePostRequest(analyticsBaseUrl, JsonKey.EKSTEP_METRICS_API_URL, requestStr); + ProjectLogger.log( + "OrganisationMetricsActor:getOrgConsumptionData Response data : " + ekStepResponse, + LoggerEnum.INFO.name()); + return orgConsumptionResponseGenerator(periodStr, ekStepResponse); + } + + private String getOrgMetricsRequest( + Request actorMessage, String periodStr, String orgHashId, String userId, String channel) + throws JsonProcessingException { + Request request = new Request(); + request.setId(actorMessage.getId()); + Map requestObject = new HashMap<>(); + requestObject.put(JsonKey.PERIOD, getEkstepPeriod(periodStr)); + Map filterMap = new HashMap<>(); + filterMap.put(JsonKey.TAG, orgHashId); + if (!StringUtils.isBlank(userId)) { + filterMap.put(USER_ID, userId); + } + requestObject.put(JsonKey.FILTER, filterMap); + requestObject.put(JsonKey.CHANNEL, channel); + request.setRequest(requestObject); + return mapper.writeValueAsString(request); + } + + @SuppressWarnings("unchecked") + private String orgConsumptionResponseGenerator(String period, String ekstepResponse) { + String result = ""; + try { + Map resultData = mapper.readValue(ekstepResponse, Map.class); + resultData = (Map) resultData.get(JsonKey.RESULT); + List> resultList = + (List>) resultData.get(JsonKey.METRICS); + List> userBucket = createBucketStructure(period); + List> consumptionBucket = createBucketStructure(period); + Map userData = new HashMap<>(); + int index = 0; + Collections.reverse(resultList); + Map resData = new HashMap<>(); + for (Map res : resultList) { + resData = consumptionBucket.get(index); + userData = userBucket.get(index); + String bucketDate = ""; + String metricsDate = ""; + if ("5w".equalsIgnoreCase(period)) { + bucketDate = (String) resData.get("key"); + bucketDate = bucketDate.substring(bucketDate.length() - 2, bucketDate.length()); + metricsDate = String.valueOf(res.get("d_period")); + metricsDate = metricsDate.substring(metricsDate.length() - 2, metricsDate.length()); + } else { + bucketDate = (String) resData.get("key_name"); + metricsDate = String.valueOf(res.get("d_period")); + Date date = new SimpleDateFormat("yyyyMMdd").parse(metricsDate); + metricsDate = new SimpleDateFormat("yyyy-MM-dd").format(date); + } + if (metricsDate.equalsIgnoreCase(bucketDate)) { + Double totalTimeSpent = (Double) res.get("m_total_ts"); + // reading m_total_sessions which represents total number of user visits + Integer totalSessions = (Integer) res.get("m_total_sessions"); + resData.put(VALUE, totalTimeSpent); + userData.put(VALUE, totalSessions); + } + if (index < consumptionBucket.size() && index < userBucket.size()) { + index++; + } + } + + Map series = new HashMap<>(); + + Map seriesData = new LinkedHashMap<>(); + if ("5w".equalsIgnoreCase(period)) { + seriesData.put(JsonKey.NAME, "Time spent by week"); + } else { + seriesData.put(JsonKey.NAME, "Time spent by day"); + } + seriesData.put(JsonKey.SPLIT, "content.time_spent.user.count"); + seriesData.put(JsonKey.TIME_UNIT, "seconds"); + seriesData.put(GROUP_ID, "org.timespent.sum"); + seriesData.put("buckets", consumptionBucket); + series.put("org.consumption.content.time_spent.sum", seriesData); + seriesData = new LinkedHashMap<>(); + if ("5w".equalsIgnoreCase(period)) { + seriesData.put(JsonKey.NAME, "Number of users per week"); + } else { + seriesData.put(JsonKey.NAME, "Number of users per day"); + } + seriesData.put(JsonKey.SPLIT, "content.users.count"); + seriesData.put(GROUP_ID, "org.users.count"); + seriesData.put("buckets", userBucket); + series.put("org.consumption.content.users.count", seriesData); + + resultData = (Map) resultData.get(JsonKey.SUMMARY); + Map snapshot = new LinkedHashMap<>(); + Map dataMap = new HashMap<>(); + dataMap.put(JsonKey.NAME, "Number of visits by users"); + // reading m_total_sessions which represents total number of user visits + dataMap.put(VALUE, resultData.get("m_total_sessions")); + snapshot.put("org.consumption.content.session.count", dataMap); + dataMap = new LinkedHashMap<>(); + dataMap.put(JsonKey.NAME, "Content consumption time"); + dataMap.put(VALUE, resultData.get("m_total_ts")); + dataMap.put(JsonKey.TIME_UNIT, "seconds"); + snapshot.put("org.consumption.content.time_spent.sum", dataMap); + dataMap = new LinkedHashMap<>(); + dataMap.put(JsonKey.NAME, "Average time spent by user per visit"); + dataMap.put(VALUE, resultData.get("m_avg_ts_session")); + dataMap.put(JsonKey.TIME_UNIT, "seconds"); + snapshot.put("org.consumption.content.time_spent.average", dataMap); + Map responseMap = new HashMap<>(); + responseMap.put(JsonKey.SNAPSHOT, snapshot); + responseMap.put(JsonKey.SERIES, series); + + result = mapper.writeValueAsString(responseMap); + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + } + return result; + } + + private Map validateOrg(String orgId) { + try { + Future> resultF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), orgId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (null == result || result.isEmpty()) { + return null; + } + ProjectLogger.log("Result:" + result.toString()); + return result; + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + throw new ProjectCommonException( + ResponseCode.esError.getErrorCode(), + ResponseCode.esError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsBackgroundActor.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsBackgroundActor.java new file mode 100644 index 0000000000..912edd890a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsBackgroundActor.java @@ -0,0 +1,548 @@ +package org.sunbird.metrics.actors; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.ProjectUtil.ReportTrackingStatus; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.metrics.actors.OrganisationMetricsUtil.ContentStatus; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {}, + asyncTasks = {"orgCreationMetricsData", "orgConsumptionMetricsData"} +) +public class OrganisationMetricsBackgroundActor extends BaseMetricsActor { + + private static ObjectMapper mapper = new ObjectMapper(); + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private Util.DbInfo reportTrackingdbInfo = Util.dbInfoMap.get(JsonKey.REPORT_TRACKING_DB); + private static Map conceptsList = new HashMap<>(); + private DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.ORG_CREATION_METRICS_DATA.getValue())) { + orgCreationMetricsData(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.ORG_CONSUMPTION_METRICS_DATA.getValue())) { + orgConsumptionMetricsData(request); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + private void orgCreationMetricsData(Request actorMessage) { + ProjectLogger.log( + "OrganisationMetricsBackgroundActor: orgCreationMetricsData called.", + LoggerEnum.INFO.name()); + try { + String requestId = (String) actorMessage.getRequest().get(JsonKey.REQUEST_ID); + Map requestData = getData(requestId); + String orgId = (String) requestData.get(JsonKey.RESOURCE_ID); + List headers = new ArrayList<>(); + headers.add("contentCreatedFor"); + headers.add("userId"); + headers.add("userName"); + headers.add("userCreatedOn"); + headers.add("contentName"); + headers.add("contentType"); + headers.add("contentLanguage"); + headers.add("contentSize"); + headers.add("contentCreatedOn"); + headers.add("contentReviewedOn"); + headers.add("contentLastPublishedOn"); + headers.add("contentLastUpdatedOn"); + headers.add("contentLastUpdatedStatus"); + headers.add("contentLastPublishedBy"); + headers.add("contentConceptsCovered"); + headers.add("contentDomain"); + headers.add("contentTagsCount"); + headers.add("contentCreationTimeSpent"); + headers.add("contentCreationTotalSessions"); + headers.add("contentCreationAvgTimePerSession"); + List> csvRecords = new ArrayList<>(); + csvRecords.add(headers); + for (String operation : OrganisationMetricsUtil.operationList) { + String requestStr = getRequestObject(operation, requestId); + + String baseSearchUrl = ProjectUtil.getConfigValue(JsonKey.SEARCH_SERVICE_API_BASE_URL); + String ekStepResponse = + makePostRequest(baseSearchUrl, JsonKey.EKSTEP_CONTENT_SEARCH_URL, requestStr); + List> ekstepData = getDataFromResponse(ekStepResponse, headers, orgId); + List> userData = getUserDetailsFromES(ekstepData); + csvRecords.addAll(generateDataList(userData, headers)); + } + String period = (String) requestData.get(JsonKey.PERIOD); + String fileName = + "CreationReport" + + FILENAMESEPARATOR + + orgId + + FILENAMESEPARATOR + + System.currentTimeMillis() + + FILENAMESEPARATOR + + period; + + saveData(csvRecords, requestId, "Creation Report"); + Request backGroundRequest = new Request(); + backGroundRequest.setOperation(ActorOperations.FILE_GENERATION_AND_UPLOAD.getValue()); + + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUEST_ID, requestId); + innerMap.put(JsonKey.FILE_NAME, fileName); + innerMap.put(JsonKey.DATA, csvRecords); + backGroundRequest.setRequest(innerMap); + tellToAnother(backGroundRequest); + } catch (Exception e) { + ProjectLogger.log("Some error occurs", e); + throw new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + @SuppressWarnings("unchecked") + private void orgConsumptionMetricsData(Request actorMessage) { + ProjectLogger.log( + "OrganisationMetricsBackgroundActor: orgConsumptionMetricsData called.", + LoggerEnum.INFO.name()); + try { + String requestId = (String) actorMessage.getRequest().get(JsonKey.REQUEST_ID); + Map requestData = getData(requestId); + String periodStr = (String) requestData.get(JsonKey.PERIOD); + String orgId = (String) requestData.get(JsonKey.RESOURCE_ID); + Map orgData = OrganisationMetricsUtil.validateOrg(orgId); + if (null == orgData) { + throw new ProjectCommonException( + ResponseCode.invalidOrgData.getErrorCode(), + ResponseCode.invalidOrgData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + String orgHashId = (String) orgData.get(JsonKey.HASHTAGID); + String channel = + (String) (orgData.get(JsonKey.CHANNEL) == null ? "" : orgData.get(JsonKey.CHANNEL)); + + List headers = new ArrayList<>(); + headers.add("userId"); + headers.add("userName"); + headers.add("userCreatedOn"); + headers.add("totalNumberOfVisitsByUser"); + headers.add("totalTimeSpentOnConsumingContent"); + headers.add("totalPiecesOfContentConsumed"); + headers.add("avgTimeSpentPerVisit"); + List> consumptionData = new ArrayList<>(); + List> usersData = getUserDetailsUsingOrg(orgId); + for (Map userData : usersData) { + String request = + OrganisationMetricsUtil.getOrgMetricsRequest( + actorMessage, periodStr, orgHashId, (String) userData.get(JsonKey.ID), channel); + String analyticsBaseUrl = ProjectUtil.getConfigValue(JsonKey.ANALYTICS_API_BASE_URL); + String esResponse = + makePostRequest(analyticsBaseUrl, JsonKey.EKSTEP_METRICS_API_URL, request); + Map ekstepData = + getConsumptionDataFromResponse(esResponse, userData, (List) (Object) headers); + consumptionData.add(ekstepData); + } + List> csvRecords = new ArrayList<>(); + csvRecords.add(headers); + csvRecords.addAll(generateDataList(consumptionData, headers)); + + String fileName = + "ConsumptionReport" + + FILENAMESEPARATOR + + orgId + + FILENAMESEPARATOR + + System.currentTimeMillis() + + FILENAMESEPARATOR + + periodStr; + saveData(csvRecords, requestId, "Consumption Report"); + Request backGroundRequest = new Request(); + backGroundRequest.setOperation(ActorOperations.FILE_GENERATION_AND_UPLOAD.getValue()); + + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUEST_ID, requestId); + innerMap.put(JsonKey.FILE_NAME, fileName); + innerMap.put(JsonKey.DATA, csvRecords); + backGroundRequest.setRequest(innerMap); + tellToAnother(backGroundRequest); + } catch (Exception e) { + ProjectLogger.log("Some error occurs", e); + throw new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + private List> generateDataList( + List> aggregationMap, List headers) { + List> result = new ArrayList<>(); + for (Map data : aggregationMap) { + List dataResult = new ArrayList<>(); + for (Object header : headers) { + dataResult.add(data.get(header)); + } + result.add(dataResult); + } + return result; + } + + @SuppressWarnings("unchecked") + private List> getUserDetailsFromES(List> ekstepData) { + List coursefields = new ArrayList<>(); + List> userResult = new ArrayList<>(); + coursefields.add(JsonKey.USER_ID); + coursefields.add(JsonKey.USERNAME); + coursefields.add(JsonKey.CREATED_DATE); + String userId = ""; + for (Map userData : ekstepData) { + Map data = new HashMap<>(); + if (userData.containsKey("userId")) { + userId = (String) userData.get("userId"); + } else { + data.putAll(userData); + userResult.add(data); + continue; + } + Map filter = new HashMap<>(); + filter.put(JsonKey.IDENTIFIER, userId); + try { + Future> resultF = + esService.search( + createESRequest(filter, null, coursefields), EsType.user.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (null != result && !result.isEmpty()) { + List> resultList = + (List>) result.get(JsonKey.CONTENT); + if (null != resultList && !resultList.isEmpty()) { + for (Map dataObject : resultList) { + data.putAll(dataObject); + } + } + data.putAll(userData); + userResult.add(data); + } + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.esError.getErrorCode(), + ResponseCode.esError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + // decrypt the userdata and return + return decryptionService.decryptData(userResult); + } + + private String getRequestObject(String operation, String requestId) { + Request request = new Request(); + Map requestedData = getData(requestId); + String orgId = (String) requestedData.get(JsonKey.RESOURCE_ID); + String periodStr = (String) requestedData.get(JsonKey.PERIOD); + Map dateMap = getStartAndEndDate(periodStr); + Map operationMap = new LinkedHashMap<>(); + switch (operation) { + case "Create": + operationMap.put("dateKey", "createdOn"); + operationMap.put("status", ContentStatus.Draft.name()); + break; + + case "Review": + operationMap.put("dateKey", "lastSubmittedOn"); + operationMap.put("status", ContentStatus.Review.name()); + break; + + case "Publish": + operationMap.put("dateKey", "lastPublishedOn"); + operationMap.put("status", ContentStatus.Live.name()); + break; + + default: + operationMap.put("dateKey", ""); + operationMap.put("status", ""); + break; + } + Map requestObject = new HashMap<>(); + Map filterMap = new HashMap<>(); + List fields = new ArrayList<>(); + Map dateValue = new HashMap<>(); + dateValue.put("min", dateMap.get(STARTDATE)); + dateValue.put("max", dateMap.get(ENDDATE)); + filterMap.put(operationMap.get("dateKey"), dateValue); + List contentType = new ArrayList<>(); + contentType.add("Story"); + contentType.add("Worksheet"); + contentType.add("Game"); + contentType.add("Collection"); + contentType.add("TextBook"); + contentType.add("TextBookUnit"); + contentType.add("Course"); + contentType.add("CourseUnit"); + filterMap.put("contentType", contentType); + filterMap.put("createdFor", orgId); + filterMap.put(JsonKey.STATUS, operationMap.get(JsonKey.STATUS)); + requestObject.put(JsonKey.FILTERS, filterMap); + fields.add("createdBy"); + fields.add("createdFor"); + fields.add("createdOn"); + fields.add("lastUpdatedOn"); + fields.add("status"); + fields.add("lastPublishedBy"); + fields.add("name"); + fields.add("contentType"); + fields.add("size"); + fields.add("concepts"); + fields.add("domain"); + fields.add("tags"); + fields.add("language"); + fields.add("lastPublishedOn"); + fields.add("lastSubmittedOn"); + fields.add("me_creationTimespent"); + fields.add("me_creationSessions"); + fields.add("me_avgCreationTsPerSession"); + requestObject.put(JsonKey.FIELDS, fields); + request.setRequest(requestObject); + String requestStr = ""; + try { + requestStr = mapper.writeValueAsString(request); + } catch (JsonProcessingException e) { + ProjectLogger.log("Error occurred", e); + } + return requestStr; + } + + @SuppressWarnings("unchecked") + private List> getDataFromResponse( + String responseData, List headers, String orgId) { + List> result = new ArrayList<>(); + try { + Map resultData = mapper.readValue(responseData, Map.class); + resultData = (Map) resultData.get(JsonKey.RESULT); + List> resultList = + (List>) resultData.get(JsonKey.CONTENT); + for (Map content : resultList) { + Map data = new HashMap<>(); + for (String header : content.keySet()) { + String headerName = StringUtils.capitalize(header); + headerName = "content" + headerName; + if (headers.contains(headerName)) { + data.put(headerName, content.get(header)); + } else if ("status".equalsIgnoreCase(header)) { + data.put("contentLastUpdatedStatus", content.get(header)); + } else if ("contentType".equalsIgnoreCase(header)) { + data.put(header, content.get(header)); + } else if ("concepts".equalsIgnoreCase(header)) { + List concepts = getConcepts((List) content.get(header)); + data.put("contentConceptsCovered", concepts); + } else if ("tags".equalsIgnoreCase(header)) { + List tags = (List) content.get(header); + data.put("contentTagsCount", tags.size()); + } else if ("lastSubmittedOn".equals(header)) { + data.put("contentReviewedOn", content.get(header)); + } + if ("createdFor".equalsIgnoreCase(header)) { + data.put(headerName, orgId); + } + if ("createdBy".equalsIgnoreCase(header) || "lastPublishedBy".equalsIgnoreCase(header)) { + data.put("userId", content.get(header)); + } + } + result.add(data); + } + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + } + return result; + } + + private static List getConcepts(List data) { + List result = new ArrayList<>(); + for (String concept : data) { + String conceptName = getConcept(concept); + if (!StringUtils.isBlank(conceptName)) { + result.add(conceptName); + } + } + return result; + } + + private static String getConcept(String data) { + if (null == conceptsList || conceptsList.isEmpty()) { + conceptList(); + } + return conceptsList.get(data); + } + + @SuppressWarnings("unchecked") + private static Map conceptList() { + List domains = getDomains(); + for (String domain : domains) { + String url = PropertiesCache.getInstance().getProperty((JsonKey.EKSTEP_CONCEPT_URL)); + url = StringUtils.replace(url, "{domain}", domain); + String resposne = getDataFromEkstep(url); + try { + Map responseMap = mapper.readValue(resposne, Map.class); + responseMap = (Map) responseMap.get(JsonKey.RESULT); + List> conceptData = + (List>) responseMap.get("concepts"); + for (Map concept : conceptData) { + String id = (String) concept.get(JsonKey.IDENTIFIER); + String name = (String) concept.get(JsonKey.NAME); + conceptsList.put(id, name); + } + } catch (IOException e) { + ProjectLogger.log("Error occurred", e); + } + } + return conceptsList; + } + + @SuppressWarnings("unchecked") + private static List getDomains() { + String domainUrl = PropertiesCache.getInstance().getProperty((JsonKey.EKSTEP_DOMAIN_URL)); + String resposne = getDataFromEkstep(domainUrl); + List domainList = new ArrayList<>(); + try { + Map responseMap = mapper.readValue(resposne, Map.class); + responseMap = (Map) responseMap.get(JsonKey.RESULT); + List> domainData = (List>) responseMap.get("domains"); + for (Map domain : domainData) { + String id = (String) domain.get(JsonKey.IDENTIFIER); + domainList.add(id); + } + } catch (IOException e) { + ProjectLogger.log("Error occurred", e); + } + return domainList; + } + + @SuppressWarnings("unchecked") + private List> getUserDetailsUsingOrg(String orgId) { + List coursefields = new ArrayList<>(); + List> userResult = new ArrayList<>(); + coursefields.add(JsonKey.USER_ID); + coursefields.add(JsonKey.USER_NAME); + coursefields.add(JsonKey.CREATED_DATE); + Map filter = new HashMap<>(); + filter.put("organisations.organisationId", orgId); + try { + Future> resultF = + esService.search(createESRequest(filter, null, coursefields), EsType.user.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + + if (null != result && !result.isEmpty()) { + List> resultList = + (List>) result.get(JsonKey.CONTENT); + if (null != resultList && !resultList.isEmpty()) { + for (Map dataObject : resultList) { + userResult.add(dataObject); + } + } + } + // decrypt the userdata + userResult = decryptionService.decryptData(userResult); + return userResult; + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.esError.getErrorCode(), + ResponseCode.esError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + @SuppressWarnings("unchecked") + private Map getConsumptionDataFromResponse( + String responseData, Map userData, List headers) { + Map resultMap = new HashMap<>(); + try { + Map resultData = mapper.readValue(responseData, Map.class); + resultData = (Map) resultData.get(JsonKey.RESULT); + Map result = (Map) resultData.get(JsonKey.SUMMARY); + resultMap.put(headers.get(0), userData.get(JsonKey.ID)); + resultMap.put(headers.get(1), userData.get(JsonKey.USERNAME)); + resultMap.put(headers.get(2), userData.get(JsonKey.CREATED_DATE)); + resultMap.put(headers.get(3), result.get("m_total_sessions")); + resultMap.put(headers.get(4), result.get("m_total_ts")); + resultMap.put(headers.get(5), result.get("m_total_content_count")); + resultMap.put(headers.get(6), result.get("m_avg_ts_session")); + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + } + return resultMap; + } + + private void saveData(List> data, String requestId, String type) { + Map dbReqMap = new HashMap<>(); + SimpleDateFormat format = ProjectUtil.getDateFormatter(); + format.setLenient(false); + dbReqMap.put(JsonKey.ID, requestId); + String dataStr = getJsonString(data); + dbReqMap.put(JsonKey.DATA, dataStr); + dbReqMap.put(JsonKey.STATUS, ReportTrackingStatus.GENERATING_DATA.getValue()); + dbReqMap.put(JsonKey.UPDATED_DATE, format.format(new Date())); + dbReqMap.put(JsonKey.TYPE, type); + cassandraOperation.updateRecord( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), dbReqMap); + } + + @SuppressWarnings("unchecked") + private Map getData(String requestId) { + Response response = + cassandraOperation.getRecordById( + reportTrackingdbInfo.getKeySpace(), reportTrackingdbInfo.getTableName(), requestId); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (responseList.isEmpty()) { + return new HashMap<>(); + } + return responseList.get(0); + } + + private String getJsonString(Object requestObject) { + ObjectMapper mapper = new ObjectMapper(); + String data = ""; + try { + data = mapper.writeValueAsString(requestObject); + } catch (JsonProcessingException e) { + throw new ProjectCommonException( + ResponseCode.invalidJsonData.getErrorCode(), + ResponseCode.invalidJsonData.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return data; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsUtil.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsUtil.java new file mode 100644 index 0000000000..0be7aa4eb7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/metrics/actors/OrganisationMetricsUtil.java @@ -0,0 +1,89 @@ +package org.sunbird.metrics.actors; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import scala.concurrent.Future; + +public final class OrganisationMetricsUtil { + + public static List operationList = new ArrayList<>(); + private static ObjectMapper mapper = new ObjectMapper(); + private static ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + private OrganisationMetricsUtil() {} + + protected enum ContentStatus { + Draft("Create"), + Review("Review"), + Live("Publish"); + + private String contentOperation; + + private ContentStatus(String operation) { + this.contentOperation = operation; + } + + private String getOperation() { + return this.contentOperation; + } + } + + static { + operationList.add(ContentStatus.Draft.getOperation()); + operationList.add(ContentStatus.Review.getOperation()); + operationList.add(ContentStatus.Live.getOperation()); + } + + public static Map validateOrg(String orgId) { + try { + Future> resultF = + esService.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), orgId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (null == result || result.isEmpty()) { + return null; + } + ProjectLogger.log("Result:" + result.toString()); + return result; + } catch (Exception e) { + ProjectLogger.log("Error occurred", e); + throw new ProjectCommonException( + ResponseCode.esError.getErrorCode(), + ResponseCode.esError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + public static String getOrgMetricsRequest( + Request actorMessage, String periodStr, String orgHashId, String userId, String channel) + throws JsonProcessingException { + Request request = new Request(); + request.setId(actorMessage.getId()); + Map requestObject = new HashMap<>(); + requestObject.put(JsonKey.PERIOD, BaseMetricsActor.getEkstepPeriod(periodStr)); + Map filterMap = new HashMap<>(); + filterMap.put(JsonKey.TAG, orgHashId); + if (!StringUtils.isBlank(userId)) { + filterMap.put(BaseMetricsActor.USER_ID, userId); + } + requestObject.put(JsonKey.FILTER, filterMap); + requestObject.put(JsonKey.CHANNEL, channel); + request.setRequest(requestObject); + String requestStr = mapper.writeValueAsString(request); + return requestStr; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/Category.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/Category.java new file mode 100644 index 0000000000..dbb01c4b20 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/Category.java @@ -0,0 +1,15 @@ +package org.sunbird.models; + +/** @author anmolgupta this class will be used to define the Category for the feeds */ +public enum Category { + USER_EXTERNAL_ID_VALIDATION("USER_EXTERNAL_ID_VALIDATION"); + private String value; + + Category(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilParams.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilParams.java new file mode 100644 index 0000000000..d7be5bc8d0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilParams.java @@ -0,0 +1,73 @@ +package org.sunbird.models.adminutil; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang.builder.ToStringBuilder; + +import java.io.Serializable; + +public class AdminUtilParams implements Serializable +{ + private final static long serialVersionUID = -8580469966189743283L; + @JsonProperty("did") + private String did; + @JsonProperty("key") + private String key; + @JsonProperty("msgid") + private String msgid; + + /** + * No args constructor for use in serialization + * + */ + public AdminUtilParams() { + } + + /** + * + * @param msgid + * @param did + * @param key + */ + public AdminUtilParams(String did, String key, String msgid) { + super(); + this.did = did; + this.key = key; + this.msgid = msgid; + } + + @JsonProperty("did") + public String getDid() { + return did; + } + + @JsonProperty("did") + public void setDid(String did) { + this.did = did; + } + + @JsonProperty("key") + public String getKey() { + return key; + } + + @JsonProperty("key") + public void setKey(String key) { + this.key = key; + } + + @JsonProperty("msgid") + public String getMsgid() { + return msgid; + } + + @JsonProperty("msgid") + public void setMsgid(String msgid) { + this.msgid = msgid; + } + + @Override + public String toString() { + return new ToStringBuilder(this).append("did", did).append("key", key).append("msgid", msgid).toString(); + } + +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequest.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequest.java new file mode 100644 index 0000000000..44b781facd --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequest.java @@ -0,0 +1,48 @@ +package org.sunbird.models.adminutil; + +import com.fasterxml.jackson.annotation.*; +import org.apache.commons.lang.builder.ToStringBuilder; + +import java.io.Serializable; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdminUtilRequest implements Serializable +{ + + @JsonProperty("data") + private List data = null; + private final static long serialVersionUID = 8702012703305240394L; + + /** + * No args constructor for use in serialization + * + */ + public AdminUtilRequest() { + } + + /** + * + * @param data + */ + public AdminUtilRequest(List data) { + super(); + this.data = data; + } + + @JsonProperty("data") + public List getData() { + return data; + } + + @JsonProperty("data") + public void setData(List data) { + this.data = data; + } + + @Override + public String toString() { + return new ToStringBuilder(this).append("data", data).toString(); + } + +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequestData.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequestData.java new file mode 100644 index 0000000000..6e13af9c7f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequestData.java @@ -0,0 +1,59 @@ +package org.sunbird.models.adminutil; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang.builder.ToStringBuilder; + +import java.io.Serializable; + +public class AdminUtilRequestData implements Serializable +{ + + @JsonProperty("parentId") + private String parentId; + @JsonProperty("sub") + private String sub; + private final static long serialVersionUID = 351766241059464964L; + + /** + * No args constructor for use in serialization + * + */ + public AdminUtilRequestData() { + } + + /** + * + * @param sub + * @param parentId + */ + public AdminUtilRequestData(String parentId, String sub) { + super(); + this.parentId = parentId; + this.sub = sub; + } + + @JsonProperty("parentId") + public String getParentId() { + return parentId; + } + + @JsonProperty("parentId") + public void setParentId(String parentId) { + this.parentId = parentId; + } + + @JsonProperty("sub") + public String getSub() { + return sub; + } + + @JsonProperty("sub") + public void setSub(String sub) { + this.sub = sub; + } + + @Override + public String toString() { + return new ToStringBuilder(this).append("parentId", parentId).append("sub", sub).toString(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequestPayload.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequestPayload.java new file mode 100644 index 0000000000..44e0121a62 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/adminutil/AdminUtilRequestPayload.java @@ -0,0 +1,101 @@ +package org.sunbird.models.adminutil; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang.builder.ToStringBuilder; + +import java.io.Serializable; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdminUtilRequestPayload implements Serializable { + private static final long serialVersionUID = -2362783406031347676L; + + @JsonProperty + private String id; + + @JsonProperty + private String ver; + + @JsonProperty + private long ts; + + @JsonProperty + private AdminUtilParams params; + + @JsonProperty + private AdminUtilRequest request; + + public AdminUtilRequestPayload() { + } + /** + * + * @param request + * @param ver + * @param id + * @param params + * @param ts + */ + public AdminUtilRequestPayload(String id, String ver, long ts, AdminUtilParams params, AdminUtilRequest request) { + super(); + this.id = id; + this.ver = ver; + this.ts = ts; + this.params = params; + this.request = request; + } + + @JsonProperty("id") + public String getId() { + return id; + } + + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + @JsonProperty("ver") + public String getVer() { + return ver; + } + + @JsonProperty("ver") + public void setVer(String ver) { + this.ver = ver; + } + + @JsonProperty("ts") + public long getTs() { + return ts; + } + + @JsonProperty("ts") + public void setTs(long ts) { + this.ts = ts; + } + + @JsonProperty("params") + public AdminUtilParams getParams() { + return params; + } + + @JsonProperty("params") + public void setParams(AdminUtilParams params) { + this.params = params; + } + + @JsonProperty("request") + public AdminUtilRequest getRequest() { + return request; + } + + @JsonProperty("request") + public void setRequest(AdminUtilRequest request) { + this.request = request; + } + + @Override + public String toString() { + return new ToStringBuilder(this).append("id", id).append("ver", ver).append("ts", ts).append("params", params).append("request", request).toString(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/role/Role.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/role/Role.java new file mode 100644 index 0000000000..3a74e63288 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/role/Role.java @@ -0,0 +1,48 @@ +package org.sunbird.models.role; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import java.io.Serializable; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Role implements Serializable { + private static final long serialVersionUID = 1L; + private String id; + private String name; + private List roleGroupId; + private int status; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getRoleGroupId() { + return roleGroupId; + } + + public void setRoleGroupId(List roleGroupId) { + this.roleGroupId = roleGroupId; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/role/group/RoleGroup.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/role/group/RoleGroup.java new file mode 100644 index 0000000000..56e3253e40 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/role/group/RoleGroup.java @@ -0,0 +1,39 @@ +package org.sunbird.models.role.group; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import java.io.Serializable; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RoleGroup implements Serializable { + private static final long serialVersionUID = 1L; + private String id; + private String name; + private List url_Action_Ids; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getUrlActionIds() { + return url_Action_Ids; + } + + public void setUrlActionIds(List url_Action_Ids) { + this.url_Action_Ids = url_Action_Ids; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/systemsetting/SystemSetting.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/systemsetting/SystemSetting.java new file mode 100644 index 0000000000..0e5813fd7c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/systemsetting/SystemSetting.java @@ -0,0 +1,47 @@ +package org.sunbird.models.systemsetting; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import java.io.Serializable; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class SystemSetting implements Serializable { + private static final long serialVersionUID = 1L; + private String id; + private String field; + private String value; + + public SystemSetting() {} + + public SystemSetting(String id, String field, String value) { + this.id = id; + this.field = field; + this.value = value; + } + + public String getId() { + return this.id; + } + + public String getField() { + return this.field; + } + + public String getValue() { + return this.value; + } + + public void setId(String id) { + this.id = id; + } + + public void setField(String field) { + this.field = field; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/url/action/UrlAction.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/url/action/UrlAction.java new file mode 100644 index 0000000000..6d96a47112 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/url/action/UrlAction.java @@ -0,0 +1,39 @@ +package org.sunbird.models.url.action; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import java.io.Serializable; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UrlAction implements Serializable { + private static final long serialVersionUID = 1L; + private String id; + private String name; + private List url; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getUrl() { + return url; + } + + public void setUrl(List url) { + this.url = url; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/Feed.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/Feed.java new file mode 100644 index 0000000000..d989661cb5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/Feed.java @@ -0,0 +1,112 @@ +package org.sunbird.models.user; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Map; + +/** @author anmolgupta Pojo class for user_feed table. */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Feed implements Serializable { + private String id; + private String userId; + private String category; + private int priority; + private String createdBy; + private String status; + private Map data; + private String updatedBy; + private Timestamp expireOn; + private Timestamp updatedOn; + private Timestamp createdOn; + + public String getId() { + return id; + } + + public String getUserId() { + return userId; + } + + public String getCategory() { + return category; + } + + public int getPriority() { + return priority; + } + + public String getCreatedBy() { + return createdBy; + } + + public String getStatus() { + return status; + } + + public Map getData() { + return data; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public Timestamp getExpireOn() { + return expireOn; + } + + public Timestamp getUpdatedOn() { + return updatedOn; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setId(String id) { + this.id = id; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public void setCategory(String category) { + this.category = category; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public void setStatus(String status) { + this.status = status; + } + + public void setData(Map data) { + this.data = data; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public void setExpireOn(Timestamp expireOn) { + this.expireOn = expireOn; + } + + public void setUpdatedOn(Timestamp updatedOn) { + this.updatedOn = updatedOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/FeedAction.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/FeedAction.java new file mode 100644 index 0000000000..635689510a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/FeedAction.java @@ -0,0 +1,15 @@ +package org.sunbird.models.user; + +public enum FeedAction { + ORG_MIGRATION_ACTION("OrgMigrationAction"); + + private String action; + + private FeedAction(String action) { + this.action = action; + } + + public String getfeedAction() { + return action; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/FeedStatus.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/FeedStatus.java new file mode 100644 index 0000000000..9d2d81a2a9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/FeedStatus.java @@ -0,0 +1,16 @@ +package org.sunbird.models.user; + +public enum FeedStatus { + READ("read"), + UNREAD("unread"); + + private String status; + + private FeedStatus(String status) { + this.status = status; + } + + public String getfeedStatus() { + return status; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/User.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/User.java new file mode 100644 index 0000000000..ed84ea6b76 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/User.java @@ -0,0 +1,492 @@ +package org.sunbird.models.user; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.List; +import java.util.Map; + +/** + * @desc POJO class for User + * @author Amit Kumar + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class User implements Serializable { + + private static final long serialVersionUID = 7529802960267784945L; + + private String id; + private String avatar; + private String countryCode; + private String createdBy; + private String createdDate; + private String dob; + private String email; + private String firstName; + private String gender; + private List grade; + private Boolean isDeleted; + private List language; + private String lastLoginTime; + private String lastName; + private String location; + private String phone; + private String profileSummary; + private Map profileVisibility; + private String provider; + private List roles; + private String rootOrgId; + private Integer status; + private List subject; + private String tcStatus; + private String tcUpdatedAt; + private String tempPassword; + private String thumbnail; + private String updatedBy; + private String updatedDate; + private String userId; + private String userName; + private List> webPages; + private String externalId; + private String channel; + private String loginId; + private String registryId; + private String organisationId; + private String maskedEmail; + private String maskedPhone; + private List> externalIds; + private String userType; + private Timestamp tncAcceptedOn; + private String tncAcceptedVersion; + private Map> framework; + private List locationIds; + private String prevUsedPhone; + private String prevUsedEmail; + private int flagsValue; + private String recoveryEmail; + private String recoveryPhone; + private String managedBy; + private String accessCode; + + public List getLocationIds() { + return locationIds; + } + + public void setLocationIds(List locationIds) { + this.locationIds = locationIds; + } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getOrganisationId() { + return organisationId; + } + + public void setOrganisationId(String organisationId) { + this.organisationId = organisationId; + } + + public String getRegistryId() { + return registryId; + } + + public void setRegistryId(String registryId) { + this.registryId = registryId; + } + + public String getLoginId() { + return loginId; + } + + public void setLoginId(String loginId) { + this.loginId = loginId; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public String getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(String createdDate) { + this.createdDate = createdDate; + } + + public String getDob() { + return dob; + } + + public void setDob(String dob) { + this.dob = dob; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public List getGrade() { + return grade; + } + + public void setGrade(List grade) { + this.grade = grade; + } + + @JsonProperty(value = "isDeleted") + public Boolean getIsDeleted() { + return isDeleted; + } + + public void setIsDeleted(Boolean isDeleted) { + this.isDeleted = isDeleted; + } + + public List getLanguage() { + return language; + } + + public void setLanguage(List language) { + this.language = language; + } + + public String getLastLoginTime() { + return lastLoginTime; + } + + public void setLastLoginTime(String lastLoginTime) { + this.lastLoginTime = lastLoginTime; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getProfileSummary() { + return profileSummary; + } + + public void setProfileSummary(String profileSummary) { + this.profileSummary = profileSummary; + } + + public Map getProfileVisibility() { + return profileVisibility; + } + + public void setProfileVisibility(Map profileVisibility) { + this.profileVisibility = profileVisibility; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public String getRootOrgId() { + return rootOrgId; + } + + public void setRootOrgId(String rootOrgId) { + this.rootOrgId = rootOrgId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public List getSubject() { + return subject; + } + + public void setSubject(List subject) { + this.subject = subject; + } + + public String getTcStatus() { + return tcStatus; + } + + public void setTcStatus(String tcStatus) { + this.tcStatus = tcStatus; + } + + public String getTcUpdatedAt() { + return tcUpdatedAt; + } + + public void setTcUpdatedAt(String tcUpdatedAt) { + this.tcUpdatedAt = tcUpdatedAt; + } + + public String getTempPassword() { + return tempPassword; + } + + public void setTempPassword(String tempPassword) { + this.tempPassword = tempPassword; + } + + public String getThumbnail() { + return thumbnail; + } + + public void setThumbnail(String thumbnail) { + this.thumbnail = thumbnail; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(String updatedDate) { + this.updatedDate = updatedDate; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public List> getWebPages() { + return webPages; + } + + public void setWebPages(List> webPages) { + this.webPages = webPages; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public List> getExternalIds() { + return externalIds; + } + + public void setExternalIds(List> externalIds) { + this.externalIds = externalIds; + } + + public Map> getFramework() { + return framework; + } + + public void setFramework(Map> framework) { + this.framework = framework; + } + + public Timestamp getTncAcceptedOn() { + return tncAcceptedOn; + } + + public void setTncAcceptedOn(Timestamp tncAcceptedOn) { + this.tncAcceptedOn = tncAcceptedOn; + } + + public String getMaskedEmail() { + return maskedEmail; + } + + public void setMaskedEmail(String maskedEmail) { + this.maskedEmail = maskedEmail; + } + + public String getMaskedPhone() { + return maskedPhone; + } + + public void setMaskedPhone(String maskedPhone) { + this.maskedPhone = maskedPhone; + } + + public String getTncAcceptedVersion() { + + return tncAcceptedVersion; + } + + public void setTncAcceptedVersion(String tncAcceptedVersion) { + this.tncAcceptedVersion = tncAcceptedVersion; + } + + public String getPrevUsedPhone() { + return prevUsedPhone; + } + + public void setPrevUsedPhone(String prevUsedPhone) { + this.prevUsedPhone = prevUsedPhone; + } + + public String getPrevUsedEmail() { + return prevUsedEmail; + } + + public void setPrevUsedEmail(String prevUsedEmail) { + this.prevUsedEmail = prevUsedEmail; + } + + public int getFlagsValue() { + return flagsValue; + } + + public void setFlagsValue(int flagsValue) { + this.flagsValue = flagsValue; + } + + public String getRecoveryEmail() { + return recoveryEmail; + } + + public void setRecoveryEmail(String recoveryEmail) { + this.recoveryEmail = recoveryEmail; + } + + public String getRecoveryPhone() { + return recoveryPhone; + } + + public void setRecoveryPhone(String recoveryPhone) { + this.recoveryPhone = recoveryPhone; + } + + public String getManagedBy() { + return managedBy; + } + + public void setManagedBy(String managedBy) { + this.managedBy = managedBy; + } + + public String getAccessCode() { + return accessCode; + } + + public void setAccessCode(String accessCode) { + this.accessCode = accessCode; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/UserType.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/UserType.java new file mode 100644 index 0000000000..4ed94c99f2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/UserType.java @@ -0,0 +1,16 @@ +package org.sunbird.models.user; + +public enum UserType { + TEACHER("TEACHER"), + OTHER("OTHER"); + + private String typeName; + + private UserType(String name) { + this.typeName = name; + } + + public String getTypeName() { + return typeName; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/courses/UserCourses.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/courses/UserCourses.java new file mode 100644 index 0000000000..daa595d7c7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/courses/UserCourses.java @@ -0,0 +1,192 @@ +package org.sunbird.models.user.courses; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import java.io.Serializable; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserCourses implements Serializable { + + private static final long serialVersionUID = 1L; + private String id; + private boolean active; + private String addedBy; + private String batchId; + private String contentId; + private String courseId; + private String courseLogoUrl; + private String courseName; + private String timestamp; + private String delta; + private String description; + private String enrolledDate; + private String grade; + private String lastReadContentId; + private int lastReadContentStatus; + private int leafNodesCount; + private int progress; + private int status; + private String tocUrl; + private String userId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public String getAddedBy() { + return addedBy; + } + + public void setAddedBy(String addedBy) { + this.addedBy = addedBy; + } + + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public String getContentId() { + return contentId; + } + + public void setContentId(String contentId) { + this.contentId = contentId; + } + + public String getCourseId() { + return courseId; + } + + public void setCourseId(String courseId) { + this.courseId = courseId; + } + + public String getCourseLogoUrl() { + return courseLogoUrl; + } + + public void setCourseLogoUrl(String courseLogoUrl) { + this.courseLogoUrl = courseLogoUrl; + } + + public String getCourseName() { + return courseName; + } + + public void setCourseName(String courseName) { + this.courseName = courseName; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getDelta() { + return delta; + } + + public void setDelta(String delta) { + this.delta = delta; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getEnrolledDate() { + return enrolledDate; + } + + public void setEnrolledDate(String enrolledDate) { + this.enrolledDate = enrolledDate; + } + + public String getGrade() { + return grade; + } + + public void setGrade(String grade) { + this.grade = grade; + } + + public String getLastReadContentId() { + return lastReadContentId; + } + + public void setLastReadContentId(String lastReadContentId) { + this.lastReadContentId = lastReadContentId; + } + + public int getLastReadContentStatus() { + return lastReadContentStatus; + } + + public void setLastReadContentStatus(int lastReadContentStatus) { + this.lastReadContentStatus = lastReadContentStatus; + } + + public int getLeafNodesCount() { + return leafNodesCount; + } + + public void setLeafNodesCount(int leafNodesCount) { + this.leafNodesCount = leafNodesCount; + } + + public int getProgress() { + return progress; + } + + public void setProgress(int progress) { + this.progress = progress; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getTocUrl() { + return tocUrl; + } + + public void setTocUrl(String tocUrl) { + this.tocUrl = tocUrl; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/skill/Skill.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/skill/Skill.java new file mode 100644 index 0000000000..6414ee4fcb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/models/user/skill/Skill.java @@ -0,0 +1,105 @@ +package org.sunbird.models.user.skill; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Skill { + private String skillName; + + private Timestamp createdOn; + + private List> endorsersList = null; + private String createdBy; + private Integer endorsementCount; + private String id; + private String skillNameToLowercase; + private String userId; + private String lastUpdatedBy; + + private Timestamp lastUpdatedOn; + + public String getSkillName() { + return skillName; + } + + public void setSkillName(String skillName) { + this.skillName = skillName; + } + + public List> getEndorsersList() { + return endorsersList; + } + + public void setEndorsersList(List> endorsersList) { + this.endorsersList = endorsersList; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getSkillNameToLowercase() { + return skillNameToLowercase; + } + + public void setSkillNameToLowercase(String skillNameToLowercase) { + this.skillNameToLowercase = skillNameToLowercase; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Integer getEndorsementCount() { + return endorsementCount; + } + + public void setEndorsementCount(Integer endorsementCount) { + this.endorsementCount = endorsementCount; + } + + public String getLastUpdatedBy() { + return lastUpdatedBy; + } + + public void setLastUpdatedBy(String lastUpdatedBy) { + this.lastUpdatedBy = lastUpdatedBy; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } + + public Timestamp getLastUpdatedOn() { + return lastUpdatedOn; + } + + public void setLastUpdatedOn(Timestamp lastUpdatedOn) { + this.lastUpdatedOn = lastUpdatedOn; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/dao/RateLimitDao.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/dao/RateLimitDao.java new file mode 100644 index 0000000000..2a1af583ca --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/dao/RateLimitDao.java @@ -0,0 +1,23 @@ +package org.sunbird.ratelimit.dao; + +import java.util.List; +import java.util.Map; +import org.sunbird.ratelimit.limiter.RateLimit; + +public interface RateLimitDao { + + /** + * Inserts one or more rate limits for throttling + * + * @param rateLimits List of rate limits + */ + void insertRateLimits(List rateLimits); + + /** + * Fetches list of rate limits for given (partition) key + * + * @param key Partition key (e.g. phone number, email address) + * @return List of rate limits for given key + */ + List> getRateLimits(String key); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/dao/RateLimitDaoImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/dao/RateLimitDaoImpl.java new file mode 100644 index 0000000000..10406df616 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/dao/RateLimitDaoImpl.java @@ -0,0 +1,63 @@ +package org.sunbird.ratelimit.dao; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.ratelimit.limiter.RateLimit; + +public class RateLimitDaoImpl implements RateLimitDao { + + private static final String TABLE_NAME = JsonKey.RATE_LIMIT; + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static volatile RateLimitDao rateLimitDao; + + public static RateLimitDao getInstance() { + if (rateLimitDao == null) { + synchronized (RateLimitDaoImpl.class) { + if (rateLimitDao == null) { + rateLimitDao = new RateLimitDaoImpl(); + } + } + } + return rateLimitDao; + } + + @Override + public void insertRateLimits(List rateLimits) { + if (CollectionUtils.isEmpty(rateLimits)) { + return; + } + List ttls = + rateLimits.stream().map(rateLimit -> rateLimit.getTTL()).collect(Collectors.toList()); + List> records = + rateLimits.stream().map(rateLimit -> rateLimit.getRecord()).collect(Collectors.toList()); + + cassandraOperation.batchInsertWithTTL(Util.KEY_SPACE_NAME, TABLE_NAME, records, ttls); + } + + @Override + public List> getRateLimits(String key) { + Map partitionKey = new HashMap<>(); + partitionKey.put(JsonKey.KEY, key); + + Map ttlPropsWithAlias = new HashMap<>(); + ttlPropsWithAlias.put(JsonKey.COUNT, JsonKey.TTL); + + List properties = + Arrays.asList(JsonKey.KEY, JsonKey.RATE_LIMIT_UNIT, JsonKey.COUNT, JsonKey.RATE); + + Response response = + cassandraOperation.getRecordsByIdsWithSpecifiedColumnsAndTTL( + Util.KEY_SPACE_NAME, TABLE_NAME, partitionKey, properties, ttlPropsWithAlias); + + return (List>) response.get(JsonKey.RESPONSE); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/OtpRateLimiter.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/OtpRateLimiter.java new file mode 100644 index 0000000000..dd73c1569f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/OtpRateLimiter.java @@ -0,0 +1,35 @@ +package org.sunbird.ratelimit.limiter; + +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.ProjectUtil; + +/** Defines various rate limits for OTP functionality with rate and corresponding TTL. */ +public enum OtpRateLimiter implements RateLimiter { + MINUTE("sunbird_otp_minute_rate_limit", 60), + HOUR("sunbird_otp_hour_rate_limit", 3600), + DAY("sunbird_otp_day_rate_limit", 86400); + + private String limitKey; + private int ttl; + + private OtpRateLimiter(String limitKey, int ttl) { + this.limitKey = limitKey; + this.ttl = ttl; + } + + public String getLimitKey() { + return limitKey; + } + + public Integer getRateLimit() { + String limitVal = ProjectUtil.getConfigValue(limitKey); + if (!StringUtils.isBlank(limitVal)) { + return Integer.valueOf(limitVal); + } + return null; + } + + public int getTTL() { + return ttl; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/RateLimit.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/RateLimit.java new file mode 100644 index 0000000000..be4012bb8f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/RateLimit.java @@ -0,0 +1,137 @@ +package org.sunbird.ratelimit.limiter; + +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; + +public class RateLimit { + + private String key; + private String unit; + private Integer count; + private Integer limit; + private Integer ttl; + + public RateLimit(String key, Map rateLimitMap) { + this.key = key; + this.unit = (String) rateLimitMap.get(JsonKey.RATE_LIMIT_UNIT); + this.limit = (int) rateLimitMap.get(JsonKey.RATE); + this.count = (int) rateLimitMap.get(JsonKey.COUNT); + this.ttl = (int) rateLimitMap.get(JsonKey.TTL); + } + + public RateLimit(String key, String unit, Integer limit, int ttl) { + this.key = key; + this.unit = unit; + this.limit = limit; + this.count = 1; + this.ttl = ttl; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + + public Integer getCount() { + return count; + } + + public Integer getLimit() { + return limit; + } + + public void setLimit(Integer limit) { + this.limit = limit; + } + + public Integer getTTL() { + return ttl; + } + + public void setTTL(Integer ttl) { + this.ttl = ttl; + } + + public synchronized void incrementCount() { + this.count += 1; + } + + public Map getRecord() { + if (!isValid()) { + ProjectLogger.log("RateLimit:getRecord: Invalid record =" + toString(), LoggerEnum.ERROR); + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); + } + Map rateLimitMap = new HashMap<>(); + rateLimitMap.put(JsonKey.KEY, this.key); + rateLimitMap.put(JsonKey.RATE_LIMIT_UNIT, this.unit); + rateLimitMap.put(JsonKey.RATE, this.limit); + rateLimitMap.put(JsonKey.COUNT, this.count); + return rateLimitMap; + } + + public boolean isValid() { + if (StringUtils.isBlank(key) || StringUtils.isBlank(unit)) { + return false; + } + if (count < 1 || limit < 1) { + return false; + } + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + result = prime * result + ((unit == null) ? 0 : unit.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + RateLimit other = (RateLimit) obj; + if (key == null) { + if (other.key != null) return false; + } else if (!key.equals(other.key)) return false; + if (unit == null) { + if (other.unit != null) return false; + } else if (!unit.equals(other.unit)) return false; + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("RateLimit [unit="); + builder.append(unit); + builder.append(", count="); + builder.append(count); + builder.append(", limit="); + builder.append(limit); + builder.append(", ttl="); + builder.append(ttl); + builder.append("]"); + return builder.toString(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/RateLimiter.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/RateLimiter.java new file mode 100644 index 0000000000..338d8a49d9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/limiter/RateLimiter.java @@ -0,0 +1,10 @@ +package org.sunbird.ratelimit.limiter; + +public interface RateLimiter { + + Integer getRateLimit(); + + int getTTL(); + + String name(); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/service/RateLimitService.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/service/RateLimitService.java new file mode 100644 index 0000000000..5ef3d0479e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/service/RateLimitService.java @@ -0,0 +1,14 @@ +package org.sunbird.ratelimit.service; + +import org.sunbird.ratelimit.limiter.RateLimiter; + +public interface RateLimitService { + + /** + * Throttle requests by key as per given rate limiters. + * + * @param key Key (e.g. phone number, email address) + * @param rateLimiters List of rate limiters + */ + void throttleByKey(String key, RateLimiter[] rateLimiters); +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/service/RateLimitServiceImpl.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/service/RateLimitServiceImpl.java new file mode 100644 index 0000000000..8054a6d26f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/ratelimit/service/RateLimitServiceImpl.java @@ -0,0 +1,93 @@ +package org.sunbird.ratelimit.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.ratelimit.dao.RateLimitDao; +import org.sunbird.ratelimit.dao.RateLimitDaoImpl; +import org.sunbird.ratelimit.limiter.RateLimit; +import org.sunbird.ratelimit.limiter.RateLimiter; + +public class RateLimitServiceImpl implements RateLimitService { + + private RateLimitDao rateLimitDao = RateLimitDaoImpl.getInstance(); + + public boolean isRateLimitOn() { + return Boolean.TRUE + .toString() + .equalsIgnoreCase(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_RATE_LIMIT_ENABLED)); + } + + @Override + public void throttleByKey(String key, RateLimiter[] rateLimiters) { + if (!isRateLimitOn()) { + ProjectLogger.log( + "RateLimitServiceImpl:throttleByKey: Rate limiter is disabled", LoggerEnum.INFO); + return; + } + Map entryByRate = new HashMap<>(); + + List> ratesByKey = getRatesByKey(key); + if (CollectionUtils.isNotEmpty(ratesByKey)) { + ratesByKey + .stream() + .forEach( + rate -> { + if (!MapUtils.isEmpty(rate)) { + ProjectLogger.log( + "RateLimitServiceImpl:throttleByKey: key = " + key + " rate =" + rate, + LoggerEnum.INFO); + RateLimit rateLimit = new RateLimit(key, rate); + + if (rateLimit.getCount() >= rateLimit.getLimit()) { + ProjectLogger.log( + "RateLimitServiceImpl:throttleByKey: Rate limit threshold crossed for key = " + + key, + LoggerEnum.ERROR); + throw new ProjectCommonException( + ResponseCode.errorRateLimitExceeded.getErrorCode(), + ResponseCode.errorRateLimitExceeded.getErrorMessage(), + ResponseCode.TOO_MANY_REQUESTS.getResponseCode(), + rateLimit.getUnit().toLowerCase()); + } + rateLimit.incrementCount(); + entryByRate.put(rateLimit.getUnit(), rateLimit); + } + }); + } + + Arrays.stream(rateLimiters) + .forEach( + rateLimiter -> { + if (!entryByRate.containsKey(rateLimiter.name()) + && rateLimiter.getRateLimit() != null) { + RateLimit rateLimit = + new RateLimit( + key, rateLimiter.name(), rateLimiter.getRateLimit(), rateLimiter.getTTL()); + ProjectLogger.log( + "RateLimitServiceImpl:throttleByKey: Initialise rate limit for key = " + + key + + " rate =" + + rateLimit.getLimit(), + LoggerEnum.INFO); + entryByRate.put(rateLimiter.name(), rateLimit); + } + }); + + rateLimitDao.insertRateLimits(new ArrayList<>(entryByRate.values())); + } + + private List> getRatesByKey(String key) { + return rateLimitDao.getRateLimits(key); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/location/BaseLocationRequestValidator.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/location/BaseLocationRequestValidator.java new file mode 100644 index 0000000000..f5e134b4a6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/location/BaseLocationRequestValidator.java @@ -0,0 +1,72 @@ +package org.sunbird.validator.location; + +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.BaseRequestValidator; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** Created by arvind on 25/4/18. */ +public class BaseLocationRequestValidator extends BaseRequestValidator { + + /** + * Method to validate the create location request . Mandatory fields are as - name , type, code. + * + * @param req Request . + */ + public void validateCreateLocationRequest(Request req) { + checkMandatoryFieldsPresent( + req.getRequest(), JsonKey.NAME, JsonKey.CODE, GeoLocationJsonKey.LOCATION_TYPE); + } + + /** + * Method to validate the update location request . Mandatory fields are as - id, type. + * + * @param req Request. + */ + public void validateUpdateLocationRequest(Request req) { + checkMandatoryFieldsPresent(req.getRequest(), JsonKey.ID); + checkReadOnlyAttributesAbsent(req.getRequest(), GeoLocationJsonKey.LOCATION_TYPE); + } + + /** + * Method to validate the delete location request . Mandatory field - locationId. + * + * @param locationId + */ + public void validateDeleteLocationRequest(String locationId) { + if (StringUtils.isEmpty(locationId)) { + throw new ProjectCommonException( + ResponseCode.locationIdRequired.getErrorCode(), + ResponseCode.locationIdRequired.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * Method to validate the search location request . Request body can not be null and If filter is + * coming in request body it should be of type map. + * + * @param req + */ + public void validateSearchLocationRequest(Request req) { + Map requestBody = req.getRequest(); + if (MapUtils.isEmpty(requestBody)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (requestBody.containsKey(JsonKey.FILTERS) + && !(requestBody.get(JsonKey.FILTERS) instanceof Map)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/location/LocationRequestValidator.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/location/LocationRequestValidator.java new file mode 100644 index 0000000000..0f33b4f231 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/location/LocationRequestValidator.java @@ -0,0 +1,180 @@ +package org.sunbird.validator.location; + +import akka.actor.ActorRef; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actorutil.location.LocationClient; +import org.sunbird.actorutil.location.impl.LocationClientImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.models.location.Location; + +/** + * This class will contains method to validate the location api request. + * + * @author Amit Kumar + */ +public class LocationRequestValidator extends BaseLocationRequestValidator { + + private LocationClient locationClient = new LocationClientImpl(); + private static Map orderMap = new HashMap<>(); + + static { + List subTypeList = + Arrays.asList( + ProjectUtil.getConfigValue(GeoLocationJsonKey.SUNBIRD_VALID_LOCATION_TYPES).split(";")); + for (String str : subTypeList) { + List typeList = + (((Arrays.asList(str.split(","))).stream().map(String::toLowerCase)) + .collect(Collectors.toList())); + for (int i = 0; i < typeList.size(); i++) { + orderMap.put(typeList.get(i), i); + } + } + } + + /** + * This method will validate the list of location code whether its valid or not. If valid will + * return the locationId List. + * + * @param actorRef Actor reference. + * @param codeList List of location code. + * @return List of location id. + */ + public List getValidatedLocationIds(ActorRef actorRef, List codeList) { + Set locationIds = null; + List codes = new ArrayList<>(codeList); + List locationList = locationClient.getLocationsByCodes(actorRef, codeList); + List locationIdList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(locationList)) { + if (locationList.size() != codes.size()) { + List resCodeList = + locationList.stream().map(Location::getCode).collect(Collectors.toList()); + List invalidCodeList = + codes.stream().filter(s -> !resCodeList.contains(s)).collect(Collectors.toList()); + throwInvalidParameterValueException(invalidCodeList, JsonKey.LOCATION_CODE); + } else { + locationIds = getValidatedLocationSet(actorRef, locationList); + } + } else { + throwInvalidParameterValueException(codeList, JsonKey.LOCATION_CODE); + } + locationIdList.addAll(locationIds); + return locationIdList; + } + + /** + * This method will validate the list of location ids whether its valid or not. If valid will + * return the hierarchy List. + * + * @param actorRef Actor reference. + * @param codeList List of location ids. + * @return List of locationIds. + */ + public List getHierarchyLocationIds(ActorRef actorRef, List locationIdsList) { + Set locationIds = null; + List codes = new ArrayList<>(locationIdsList); + List locationList = locationClient.getLocationByIds(actorRef, locationIdsList); + List locationIdList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(locationList)) { + if (locationList.size() != codes.size()) { + List resCodeList = + locationList.stream().map(Location::getId).collect(Collectors.toList()); + List invalidIdsList = + codes.stream().filter(s -> !resCodeList.contains(s)).collect(Collectors.toList()); + throwInvalidParameterValueException(invalidIdsList, JsonKey.LOCATION_IDS); + } else { + locationIds = getValidatedLocationSet(actorRef, locationList); + } + } else { + throwInvalidParameterValueException(locationIdsList, JsonKey.LOCATION_IDS); + } + + locationIdList.addAll(locationIds); + return locationIdList; + } + + private void throwInvalidParameterValueException(List invalidList, String attributeName) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameterValue.getErrorMessage(), invalidList, attributeName), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + /** + * This method will validate the location hierarchy and return the locationIds list. + * + * @param actorRef Actor reference. + * @param locationList List of location. + * @return Set of locationId. + */ + public Set getValidatedLocationSet(ActorRef actorRef, List locationList) { + Set locationSet = new HashSet<>(); + for (Location requestedLocation : locationList) { + Set parentLocnSet = getParentLocations(actorRef, requestedLocation); + if (CollectionUtils.sizeIsEmpty(locationSet)) { + locationSet.addAll(parentLocnSet); + } else { + for (Location currentLocation : parentLocnSet) { + String type = currentLocation.getType(); + locationSet + .stream() + .forEach( + location -> { + if (type.equalsIgnoreCase(location.getType()) + && !(currentLocation.getId().equals(location.getId()))) { + throw new ProjectCommonException( + ResponseCode.conflictingOrgLocations.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.conflictingOrgLocations.getErrorMessage(), + requestedLocation.getCode(), + location.getCode(), + type), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + locationSet.add(currentLocation); + } + } + } + return locationSet.stream().map(Location::getId).collect(Collectors.toSet()); + } + + private Set getParentLocations(ActorRef actorRef, Location locationObj) { + Set locationSet = new LinkedHashSet<>(); + Location location = locationObj; + int count = getOrder(location.getType()); + locationSet.add(location); + while (count > 0) { + Location parent = null; + if (getOrder(location.getType()) == 0 && StringUtils.isNotEmpty(location.getId())) { + parent = locationClient.getLocationById(actorRef, location.getId()); + } else if (StringUtils.isNotEmpty(location.getParentId())) { + parent = locationClient.getLocationById(actorRef, location.getParentId()); + } + if (null != parent) { + locationSet.add(parent); + location = parent; + } + count--; + } + return locationSet; + } + + public int getOrder(String type) { + return orderMap.get(type); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/user/UserBulkMigrationRequestValidator.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/user/UserBulkMigrationRequestValidator.java new file mode 100644 index 0000000000..649b89aff5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/user/UserBulkMigrationRequestValidator.java @@ -0,0 +1,189 @@ +package org.sunbird.validator.user; + +import java.util.HashSet; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.bean.MigrationUser; +import org.sunbird.bean.ShadowUserUpload; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.error.CsvError; +import org.sunbird.error.CsvRowErrorDetails; +import org.sunbird.error.ErrorEnum; +import org.sunbird.error.IErrorDispatcher; +import org.sunbird.error.factory.ErrorDispatcherFactory; + +/** + * this class will validate the csv file for shadow db + * + * @author anmolgupta + */ +public class UserBulkMigrationRequestValidator { + + private ShadowUserUpload shadowUserMigration; + private HashSet userExternalIdsSet = new HashSet<>(); + private CsvError csvRowsErrors = new CsvError(); + private static final int MAX_ROW_SUPPORTED = 20000; + private static final String NAME_REG_MATCHER = "^[^.][^^;\\-()<>|!=’%_#$]+"; + + private UserBulkMigrationRequestValidator(ShadowUserUpload migration) { + this.shadowUserMigration = migration; + } + + public static UserBulkMigrationRequestValidator getInstance(ShadowUserUpload migration) { + return new UserBulkMigrationRequestValidator(migration); + } + + public void validate() { + ProjectLogger.log( + "UserBulkMigrationRequestValidator:validate:start validating migration users", + LoggerEnum.INFO.name()); + checkCsvRows(); + } + + private void checkCsvRows() { + validateRowsCount(); + shadowUserMigration + .getValues() + .stream() + .forEach( + onCsvRow -> { + int index = shadowUserMigration.getValues().indexOf(onCsvRow); + validateMigrationUser(onCsvRow, index); + }); + if (csvRowsErrors.getErrorsList().size() > 0) { + IErrorDispatcher errorDispatcher = ErrorDispatcherFactory.getErrorDispatcher(csvRowsErrors); + errorDispatcher.dispatchError(); + } + } + + private void validateRowsCount() { + int ROW_BEGINNING_INDEX = 1; + if (shadowUserMigration.getValues().size() >= MAX_ROW_SUPPORTED) { + throw new ProjectCommonException( + ResponseCode.csvRowsExceeds.getErrorCode(), + ResponseCode.csvRowsExceeds.getErrorMessage().concat("supported:" + MAX_ROW_SUPPORTED), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else if (shadowUserMigration.getValues().size() < ROW_BEGINNING_INDEX) { + throw new ProjectCommonException( + ResponseCode.noDataForConsumption.getErrorCode(), + ResponseCode.noDataForConsumption.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private void validateMigrationUser(MigrationUser migrationUser, int index) { + + checkEmailAndPhone(migrationUser.getEmail(), migrationUser.getPhone(), index); + checkUserExternalId(migrationUser.getUserExternalId(), index); + checkName(migrationUser.getName(), index); + checkInputStatus(migrationUser.getInputStatus(), index); + } + + private void addErrorToList(CsvRowErrorDetails errorDetails) { + csvRowsErrors.setError(errorDetails); + } + + public void checkEmailAndPhone(String email, String phone, int index) { + CsvRowErrorDetails errorDetails = new CsvRowErrorDetails(); + errorDetails.setRowId(index); + boolean isEmailBlank = StringUtils.isBlank(email); + boolean isPhoneBlank = StringUtils.isBlank(phone); + if (isEmailBlank && isPhoneBlank) { + errorDetails.setErrorEnum(ErrorEnum.missing); + errorDetails.setHeader(JsonKey.EMAIL); + } + + if (!isEmailBlank) { + checkEmail(email, index); + } + if (!isPhoneBlank) { + checkPhone(phone, index); + } + if (errorDetails.getErrorEnum() != null) { + addErrorToList(errorDetails); + } + } + + private void checkEmail(String email, int index) { + CsvRowErrorDetails errorDetails = new CsvRowErrorDetails(); + errorDetails.setRowId(index); + errorDetails.setHeader(JsonKey.EMAIL); + boolean isEmailValid = ProjectUtil.isEmailvalid(email); + if (!isEmailValid) { + errorDetails.setErrorEnum(ErrorEnum.invalid); + } + if (errorDetails.getErrorEnum() != null) { + addErrorToList(errorDetails); + } + } + + private void checkPhone(String phone, int index) { + CsvRowErrorDetails errorDetails = new CsvRowErrorDetails(); + errorDetails.setRowId(index); + errorDetails.setHeader(JsonKey.PHONE); + boolean isPhoneValid = ProjectUtil.validatePhoneNumber(phone); + if (!isPhoneValid) { + errorDetails.setErrorEnum(ErrorEnum.invalid); + } + if (errorDetails.getErrorEnum() != null) { + addErrorToList(errorDetails); + } + } + + private void checkUserExternalId(String userExternalId, int index) { + CsvRowErrorDetails errorDetails = new CsvRowErrorDetails(); + errorDetails.setRowId(index); + errorDetails.setHeader(JsonKey.USER_EXTERNAL_ID); + if (StringUtils.isBlank(userExternalId)) { + errorDetails.setErrorEnum(ErrorEnum.missing); + } + if (!userExternalIdsSet.add(userExternalId)) { + errorDetails.setErrorEnum(ErrorEnum.duplicate); + } + if (errorDetails.getErrorEnum() != null) { + addErrorToList(errorDetails); + } + } + + private void checkName(String name, int index) { + if (StringUtils.isNotBlank(name) && !(Pattern.matches(NAME_REG_MATCHER, name))) { + CsvRowErrorDetails errorDetails = new CsvRowErrorDetails(); + errorDetails.setRowId(index); + errorDetails.setHeader(JsonKey.NAME); + errorDetails.setErrorEnum(ErrorEnum.invalid); + addErrorToList(errorDetails); + } + checkValue(name, index, JsonKey.NAME); + } + + private void checkInputStatus(String inputStatus, int index) { + CsvRowErrorDetails errorDetails = new CsvRowErrorDetails(); + errorDetails.setRowId(index); + if (StringUtils.isBlank(inputStatus)) { + errorDetails.setHeader(JsonKey.INPUT_STATUS); + errorDetails.setErrorEnum(ErrorEnum.missing); + addErrorToList(errorDetails); + + } else if (!(inputStatus.equalsIgnoreCase(JsonKey.ACTIVE) + || inputStatus.equalsIgnoreCase(JsonKey.INACTIVE))) { + errorDetails.setHeader(JsonKey.INPUT_STATUS); + errorDetails.setErrorEnum(ErrorEnum.invalid); + addErrorToList(errorDetails); + } + } + + private void checkValue(String column, int rowIndex, String header) { + if (StringUtils.isBlank(column)) { + CsvRowErrorDetails errorDetails = new CsvRowErrorDetails(); + errorDetails.setRowId(rowIndex); + errorDetails.setHeader(header); + errorDetails.setErrorEnum(ErrorEnum.missing); + addErrorToList(errorDetails); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/user/UserBulkUploadRequestValidator.java b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/user/UserBulkUploadRequestValidator.java new file mode 100644 index 0000000000..deb34e16e4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/main/java/org/sunbird/validator/user/UserBulkUploadRequestValidator.java @@ -0,0 +1,50 @@ +package org.sunbird.validator.user; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.StringFormatter; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.models.user.UserType; + +public class UserBulkUploadRequestValidator { + + private UserBulkUploadRequestValidator() {} + + public static void validateUserBulkUploadRequest(Map userMap) { + validateUserType(userMap); + validateOrganisationId(userMap); + } + + public static void validateUserType(Map userMap) { + List userTypes = + Stream.of(UserType.values()).map(UserType::getTypeName).collect(Collectors.toList()); + String userType = (String) userMap.get(JsonKey.USER_TYPE); + if (userTypes.contains(userType.trim().toUpperCase())) { + userMap.put(JsonKey.USER_TYPE, userType.trim().toUpperCase()); + } else { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidValue, + MessageFormat.format( + ResponseCode.invalidValue.getErrorMessage(), JsonKey.USER_TYPE, userType, userTypes)); + } + } + + public static void validateOrganisationId(Map userMap) { + String userType = (String) userMap.get(JsonKey.USER_TYPE); + if (UserType.TEACHER.name().equalsIgnoreCase(userType.trim().toUpperCase()) + && (StringUtils.isBlank((String) userMap.get(JsonKey.ORG_ID)) + && StringUtils.isBlank((String) userMap.get(JsonKey.ORG_EXTERNAL_ID)))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + (StringFormatter.joinByOr(JsonKey.ORG_ID, JsonKey.ORG_EXTERNAL_ID)))); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/common/quartz/scheduler/OnDemandSchedulerManagerTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/common/quartz/scheduler/OnDemandSchedulerManagerTest.java new file mode 100644 index 0000000000..def51598c6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/common/quartz/scheduler/OnDemandSchedulerManagerTest.java @@ -0,0 +1,40 @@ +package org.sunbird.common.quartz.scheduler; + +import static org.mockito.Mockito.*; +import static org.powermock.api.mockito.PowerMockito.when; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + SchedulerManager.class, +}) +@PowerMockIgnore("javax.management.*") +public class OnDemandSchedulerManagerTest { + + static OnDemandSchedulerManager onDemandSchedulerManager; + static SchedulerManager schedulerManager; + static Scheduler scheduler; + + @Test + public void testTriggerScheduler() throws SchedulerException { + PowerMockito.suppress(PowerMockito.constructor(SchedulerManager.class)); + PowerMockito.suppress(PowerMockito.methodsDeclaredIn(SchedulerManager.class)); + scheduler = mock(Scheduler.class); + PowerMockito.mockStatic(SchedulerManager.class); + String[] jobs = {"shadowuser"}; + onDemandSchedulerManager = spy(OnDemandSchedulerManager.class); + when(scheduler.checkExists((JobKey) Mockito.anyObject())).thenReturn(false); + onDemandSchedulerManager.triggerScheduler(jobs); + verify(onDemandSchedulerManager).scheduleOnDemand(Mockito.anyString(), Mockito.anyString()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/feed/FeedUtilTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/feed/FeedUtilTest.java new file mode 100644 index 0000000000..587322ac31 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/feed/FeedUtilTest.java @@ -0,0 +1,148 @@ +package org.sunbird.feed; + +import static org.powermock.api.mockito.PowerMockito.*; + +import java.util.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.actorutil.org.impl.OrganisationClientImpl; +import org.sunbird.bean.ShadowUser; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.Constants; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.feed.impl.FeedFactory; +import org.sunbird.feed.impl.FeedServiceImpl; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.models.organisation.Organisation; +import org.sunbird.models.user.Feed; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + ElasticSearchHelper.class, + EsClientFactory.class, + CassandraOperationImpl.class, + ElasticSearchService.class, + IFeedService.class, + FeedServiceImpl.class, + FeedFactory.class, + ShadowUser.class, + OrganisationClient.class, + OrganisationClientImpl.class +}) +@SuppressStaticInitializationFor("org.sunbird.common.ElasticSearchUtil") +@PowerMockIgnore({"javax.management.*"}) +public class FeedUtilTest { + private ElasticSearchService esUtil; + private CassandraOperation cassandraOperation = null; + private static Response response; + private static IFeedService feedService; + private static OrganisationClient organisationClient; + + @Before + public void setUp() throws Exception { + PowerMockito.mockStatic(FeedServiceImpl.class); + PowerMockito.mockStatic(FeedFactory.class); + feedService = mock(FeedServiceImpl.class); + organisationClient = mock(OrganisationClient.class); + mockStatic(OrganisationClientImpl.class); + when(FeedFactory.getInstance()).thenReturn(feedService); + when(FeedServiceImpl.getCassandraInstance()).thenReturn(cassandraOperation); + when(FeedServiceImpl.getESInstance()).thenReturn(esUtil); + when(feedService.getRecordsByProperties(Mockito.anyMap())) + .thenReturn(getFeedList(true)) + .thenReturn(getFeedList(false)); + when(feedService.insert(Mockito.any())).thenReturn(new Response()); + when(feedService.update(Mockito.any())).thenReturn(new Response()); + + // whenNew(OrganisationClientImpl.class).withNoArguments().thenReturn(organisationClient); + when(OrganisationClientImpl.getInstance()).thenReturn(organisationClient); + when(organisationClient.esSearchOrgByFilter(Mockito.anyMap())).thenReturn(getFeedOrgs()); + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + esUtil = mock(ElasticSearchService.class); + esUtil = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esUtil); + cassandraOperation = mock(CassandraOperationImpl.class); + response = new Response(); + Map responseMap = new HashMap<>(); + responseMap.put(Constants.RESPONSE, Arrays.asList(getFeedMap())); + response.getResult().putAll(responseMap); + PowerMockito.when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + PowerMockito.when( + cassandraOperation.getRecordsByProperties(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(response); + Response upsertResponse = new Response(); + Map responseMap2 = new HashMap<>(); + responseMap2.put(Constants.RESPONSE, Constants.SUCCESS); + upsertResponse.getResult().putAll(responseMap2); + PowerMockito.when(cassandraOperation.upsertRecord(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(upsertResponse); + } + + private List getFeedList(boolean needId) { + Feed feed = new Feed(); + feed.setUserId("123-456-7890"); + feed.setCategory("category"); + if (needId) { + feed.setId("123-456-789"); + } + Map map = new HashMap<>(); + List channelList = new ArrayList<>(); + channelList.add("SI"); + map.put(JsonKey.PROSPECT_CHANNELS, channelList); + feed.setData(map); + List feedList = new ArrayList<>(); + feedList.add(feed); + return feedList; + } + + private Map getFeedMap() { + Map fMap = new HashMap<>(); + fMap.put(JsonKey.ID, "123-456-7890"); + fMap.put(JsonKey.USER_ID, "123-456-789"); + fMap.put(JsonKey.CATEGORY, "category"); + return fMap; + } + + @Test + public void saveFeedInsertTest() { + List userIds = new ArrayList<>(); + userIds.add("123-456-7890"); + Response response = FeedUtil.saveFeed(getShadowUser(), userIds); + Assert.assertNotNull(response); + } + + public static ShadowUser getShadowUser() { + ShadowUser.ShadowUserBuilder user = new ShadowUser.ShadowUserBuilder(); + user.setChannel("SI"); + return user.build(); + } + + private List getFeedOrgs() { + Organisation org = new Organisation(); + org.setChannel("dummyChannel"); + org.setId("dummyId"); + List orgList = new ArrayList<>(); + orgList.add(org); + return orgList; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/feed/impl/FeedServiceImplTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/feed/impl/FeedServiceImplTest.java new file mode 100644 index 0000000000..e8a936002a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/feed/impl/FeedServiceImplTest.java @@ -0,0 +1,163 @@ +package org.sunbird.feed.impl; + +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.dispatch.Futures; +import java.util.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.Constants; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.feed.IFeedService; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.models.user.Feed; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + ElasticSearchHelper.class, + EsClientFactory.class, + CassandraOperationImpl.class, + ElasticSearchService.class +}) +@SuppressStaticInitializationFor("org.sunbird.common.ElasticSearchUtil") +@PowerMockIgnore({"javax.management.*"}) +public class FeedServiceImplTest { + private ElasticSearchService esUtil; + private static CassandraOperation cassandraOperation = null; + private static IFeedService feedService = FeedFactory.getInstance(); + private static SearchDTO search = new SearchDTO(); + private static Map esResponse = new HashMap<>(); + private static Promise> promise; + + @Before + public void setUp() throws Exception { + Map filters = new HashMap<>(); + filters.put(JsonKey.USER_ID, "123-456-789"); + search.getAdditionalProperties().put(JsonKey.FILTERS, filters); + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + esUtil = mock(ElasticSearchService.class); + esUtil = mock(ElasticSearchRestHighImpl.class); + promise = Futures.promise(); + promise.success(esResponse); + + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esUtil); + cassandraOperation = mock(CassandraOperationImpl.class); + PowerMockito.when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(FeedServiceImpl.getCassandraInstance()).thenReturn(cassandraOperation); + when(FeedServiceImpl.getESInstance()).thenReturn(esUtil); + when(esUtil.search(search, ProjectUtil.EsType.userfeed.getTypeName())) + .thenReturn(promise.future()); + when(ElasticSearchHelper.getResponseFromFuture(Mockito.any())).thenReturn(esResponse); + initCassandraForSuccess(); + } + + private static void initCassandraForSuccess() { + Response response = new Response(); + Map responseMap = new HashMap<>(); + responseMap.put(Constants.RESPONSE, Arrays.asList(getFeedMap())); + response.getResult().putAll(responseMap); + PowerMockito.when( + cassandraOperation.getRecordsByProperties(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(response); + + Response upsertResponse = new Response(); + Map responseMap2 = new HashMap<>(); + responseMap2.put(Constants.RESPONSE, Constants.SUCCESS); + upsertResponse.getResult().putAll(responseMap2); + PowerMockito.when(cassandraOperation.upsertRecord(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(upsertResponse); + PowerMockito.when( + cassandraOperation.deleteRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(upsertResponse); + } + + @Test + public void testInsert() { + Response res = feedService.insert(getFeed(false)); + Assert.assertTrue( + ((String) res.getResult().get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)); + } + + @Test + public void testUpdate() { + Response res = feedService.update(getFeed(true)); + Assert.assertTrue( + ((String) res.getResult().get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)); + } + + @Test + public void testDelete() { + boolean response = false; + try { + feedService.delete("123-456-789"); + response = true; + } catch (Exception ex) { + Assert.assertTrue(response); + } + Assert.assertTrue(response); + } + + @Test + public void testGetRecordsByProperties() { + Map props = new HashMap<>(); + props.put(JsonKey.USER_ID, "123-456-789"); + List res = feedService.getRecordsByProperties(props); + Assert.assertTrue(res != null); + } + + @Test + public void testSearch() { + Response response = feedService.search(search); + when(ElasticSearchHelper.getResponseFromFuture(Mockito.any())).thenReturn(esResponse); + PowerMockito.when(esUtil.search(search, ProjectUtil.EsType.userfeed.getTypeName())) + .thenReturn(promise.future()); + Assert.assertTrue(esResponse != null); + } + + private static Map getFeedMap() { + Map fMap = new HashMap<>(); + fMap.put(JsonKey.ID, "123-456-7890"); + fMap.put(JsonKey.USER_ID, "123-456-789"); + fMap.put(JsonKey.CATEGORY, "category"); + return fMap; + } + + private Feed getFeed(boolean needId) { + Feed feed = new Feed(); + feed.setUserId("123-456-7890"); + feed.setCategory("category"); + if (needId) { + feed.setId("123-456-789"); + } + Map map = new HashMap<>(); + List channelList = new ArrayList<>(); + channelList.add("SI"); + map.put(JsonKey.PROSPECT_CHANNELS, channelList); + feed.setData(map); + return feed; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/BackgroundServiceActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/BackgroundServiceActorTest.java new file mode 100644 index 0000000000..5067909e8d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/BackgroundServiceActorTest.java @@ -0,0 +1,162 @@ +package org.sunbird.learner.actors; + +import static org.junit.Assert.assertTrue; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.*; +import org.junit.runners.MethodSorters; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class BackgroundServiceActorTest { + + private static ActorSystem system; + private static final Props props = Props.create(BackGroundServiceActor.class); + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static Util.DbInfo geoLocationDbInfo = Util.dbInfoMap.get(JsonKey.GEO_LOCATION_DB); + private static final String locnId = "hhjcjrdf4scdv56vf79fw4p89"; + + @BeforeClass + public static void setUp() { + + system = ActorSystem.create("system"); + + Map locnMap = new HashMap(); + locnMap.put(JsonKey.ID, locnId); + cassandraOperation.insertRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnMap); + } + + @Test + @Ignore + public void updateUserCountTest() { + Map locnMap = new HashMap(); + locnMap.put(JsonKey.ID, locnId); + locnMap.put(JsonKey.USER_COUNT, 0); + cassandraOperation.updateRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnMap); + List locnIdList = new ArrayList<>(); + locnIdList.add(locnId); + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.LOCATION_IDS, locnIdList); + actorMessage.getRequest().put(JsonKey.OPERATION, "GeoLocationManagementActor"); + actorMessage.setOperation(BackgroundOperations.updateUserCountToLocationID.name()); + + subject.tell(actorMessage, probe.getRef()); + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + ProjectLogger.log(e.getMessage(), e); + } + Response response = + cassandraOperation.getRecordById( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnId); + // probe.expectMsgClass(duration("300 second"),Response.class); + List> reslist = (List>) response.get(JsonKey.RESPONSE); + Map map = reslist.get(0); + int count = (int) map.get(JsonKey.USER_COUNT); + boolean bool = (count >= 0) ? true : false; + assertTrue(bool); + } + + @Test + @Ignore + public void updateUserCountTest2() { + + Map locnMap = new HashMap(); + locnMap.put(JsonKey.ID, locnId); + locnMap.put(JsonKey.USER_COUNT, 0); + cassandraOperation.updateRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnMap); + + List locnIdList = new ArrayList<>(); + locnIdList.add(locnId); + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.LOCATION_IDS, locnIdList); + actorMessage.getRequest().put(JsonKey.OPERATION, "UpdateUserCountScheduler"); + actorMessage.setOperation(BackgroundOperations.updateUserCountToLocationID.name()); + + subject.tell(actorMessage, probe.getRef()); + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + ProjectLogger.log(e.getMessage(), e); + } + Response response = + cassandraOperation.getRecordById( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnId); + // probe.expectMsgClass(duration("300 second"),Response.class); + List> reslist = (List>) response.get(JsonKey.RESPONSE); + Map map = reslist.get(0); + int count = (int) map.get(JsonKey.USER_COUNT); + boolean bool = (count >= 0) ? true : false; + assertTrue(bool); + } + + @Test + @Ignore + public void updateUserCountTest3() { + + Map locnMap = new HashMap(); + locnMap.put(JsonKey.ID, locnId); + locnMap.put(JsonKey.USER_COUNT, 0); + locnMap.put(JsonKey.USER_COUNT_TTL, "abc"); + cassandraOperation.updateRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnMap); + + List locnIdList = new ArrayList<>(); + locnIdList.add(locnId); + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.LOCATION_IDS, locnIdList); + actorMessage.getRequest().put(JsonKey.OPERATION, "GeoLocationManagementActor"); + actorMessage.setOperation(BackgroundOperations.updateUserCountToLocationID.name()); + + subject.tell(actorMessage, probe.getRef()); + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + ProjectLogger.log(e.getMessage(), e); + } + Response response = + cassandraOperation.getRecordById( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnId); + // probe.expectMsgClass(duration("300 second"),Response.class); + List> reslist = (List>) response.get(JsonKey.RESPONSE); + Map map = reslist.get(0); + int count = (int) map.get(JsonKey.USER_COUNT); + boolean bool = (count >= 0) ? true : false; + assertTrue(bool); + } + + @AfterClass + public static void destroy() { + cassandraOperation.deleteRecord( + geoLocationDbInfo.getKeySpace(), geoLocationDbInfo.getTableName(), locnId); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/DbOperationActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/DbOperationActorTest.java new file mode 100644 index 0000000000..47d9ac40f2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/DbOperationActorTest.java @@ -0,0 +1,254 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.*; +import org.junit.runners.MethodSorters; +import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.learner.datapersistence.DbOperationActor; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Ignore +public class DbOperationActorTest { + private static ActorSystem system; + private static final Props props = Props.create(DbOperationActor.class); + + @BeforeClass + public static void setUp() { + SunbirdMWService.init(); + system = ActorSystem.create("system"); + } + + @Test + public void testInvalidOperation() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request reqObj = new Request(); + reqObj.setOperation("INVALID_OPERATION"); + + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = probe.expectMsgClass(ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testInvalidMessageType() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + subject.tell("Invalid Type", probe.getRef()); + ProjectCommonException exc = probe.expectMsgClass(ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testA1Create() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.CREATE_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + map.put("indexed", true); + Map innerMap = new HashMap<>(); + innerMap.put("id", "454ee9-17-a2-47-id"); + innerMap.put("sourceid", "45_sourceId"); + innerMap.put("userid", "230cb747-userId"); + innerMap.put("status", "active"); + map.put("payload", innerMap); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("20 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testA1CreateFrExc() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.CREATE_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + map.put("indexed", true); + Map innerMap = new HashMap<>(); + innerMap.put("id", "454ee9-17-a2-47-id"); + innerMap.put("sourceid", "45_sourceId"); + innerMap.put("userid", "230cb747-userId"); + innerMap.put("status1", "active"); + map.put("payload", innerMap); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("20 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testA2Update() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.UPDATE_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + map.put("indexed", true); + Map innerMap = new HashMap<>(); + innerMap.put("id", "454ee9-17-a2-47-id"); + innerMap.put("sourceid", "45_sourceId"); + innerMap.put("userid", "230cb747-userId"); + innerMap.put("status", "inactive"); + map.put("payload", innerMap); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("20 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testA2UpdateFrExc() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.UPDATE_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + map.put("indexed", true); + Map innerMap = new HashMap<>(); + innerMap.put("id", "454ee9-17-a2-47-id"); + innerMap.put("sourceid", "45_sourceId"); + innerMap.put("userid", "230cb747-userId"); + innerMap.put("status1", "inactive"); + map.put("payload", innerMap); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("20 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testA3Read() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.READ_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + map.put("id", "454ee9-17-a2-47-id"); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("20 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testA3ReadFrExec() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.READ_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement1"); + map.put("id", "454ee9-17-a2-47-id"); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("20 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testA4ReadAll() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.READ_ALL_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("20 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testA4ReadAllFrExc() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.READ_ALL_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement1"); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("20 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testA5Search() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.SEARCH_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + List list = new ArrayList<>(); + list.add("id"); + map.put("requiredFields", list); + Map filter = new HashMap<>(); + map.put(JsonKey.FILTERS, filter); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("20 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testA6delete() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.DELETE_DATA.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + map.put("indexed", true); + map.put("id", "454ee9-17-a2-47-id"); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("20 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testA7getMetrics() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.GET_METRICS.getValue()); + Map map = new HashMap<>(); + map.put("entityName", "announcement"); + Map query = new HashMap<>(); + map.put("rawQuery", query); + reqObj.setRequest(map); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("20 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/EmailServiceActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/EmailServiceActorTest.java new file mode 100644 index 0000000000..c5d4bf0f18 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/EmailServiceActorTest.java @@ -0,0 +1,384 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.datasecurity.impl.DefaultDecryptionServiceImpl; +import org.sunbird.common.models.util.datasecurity.impl.DefaultEncryptionServivceImpl; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.notificationservice.EmailServiceActor; +import org.sunbird.learner.actors.notificationservice.dao.impl.EmailTemplateDaoImpl; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + Util.class, + DataCacheHandler.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class, + ElasticSearchRestHighImpl.class, + EmailTemplateDaoImpl.class, + EsClientFactory.class, + ElasticSearchHelper.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class EmailServiceActorTest { + + private static final Props props = Props.create(EmailServiceActor.class); + private ActorSystem system = ActorSystem.create("system"); + private static CassandraOperationImpl cassandraOperation; + private static DefaultDecryptionServiceImpl defaultDecryptionService; + private static DefaultEncryptionServivceImpl defaultEncryptionServivce; + private static EmailTemplateDaoImpl emailTemplateDao; + private ElasticSearchService esService; + + @BeforeClass + public static void setUp() { + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EmailTemplateDaoImpl.class); + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + defaultDecryptionService = mock(DefaultDecryptionServiceImpl.class); + defaultEncryptionServivce = mock(DefaultEncryptionServivceImpl.class); + emailTemplateDao = mock(EmailTemplateDaoImpl.class); + } + + @Before + public void beforeTest() { + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + esService = mock(ElasticSearchRestHighImpl.class); + PowerMockito.mockStatic(EsClientFactory.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + PowerMockito.mockStatic(EmailTemplateDaoImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getDecryptionServiceInstance(null)) + .thenReturn(defaultDecryptionService); + when(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null)) + .thenReturn(defaultEncryptionServivce); + when(cassandraOperation.getRecordsByIdsWithSpecifiedColumns( + Mockito.anyString(), Mockito.anyString(), Mockito.anyList(), Mockito.anyList())) + .thenReturn(cassandraGetRecordById()); + + emailTemplateDao = mock(EmailTemplateDaoImpl.class); + when(EmailTemplateDaoImpl.getInstance()).thenReturn(emailTemplateDao); + when(emailTemplateDao.getTemplate(Mockito.anyString())).thenReturn("templateName"); + + Map recipientSearchQuery = new HashMap<>(); + recipientSearchQuery.put(JsonKey.FILTERS, "anyName"); + recipientSearchQuery.put(JsonKey.ROOT_ORG_ID, "anyRootId"); + Map esOrgResult = new HashMap<>(); + esOrgResult.put(JsonKey.ORGANISATION_NAME, "anyOrgName"); + Promise> promise = Futures.promise(); + promise.success(createGetSkillResponse()); + when(esService.search( + Mockito.eq(ElasticSearchHelper.createSearchDTO(recipientSearchQuery)), + Mockito.eq(ProjectUtil.EsType.user.getTypeName()))) + .thenReturn(promise.future()); + Promise> promise_recipientSearchQuery = Futures.promise(); + + promise_recipientSearchQuery.trySuccess(recipientSearchQuery); + when(esService.getDataByIdentifier( + Mockito.eq(ProjectUtil.EsType.user.getTypeName()), Mockito.eq("001"))) + .thenReturn(promise_recipientSearchQuery.future()); + + Promise> promise_esOrgResult = Futures.promise(); + promise_esOrgResult.trySuccess(esOrgResult); + when(esService.getDataByIdentifier( + Mockito.eq(ProjectUtil.EsType.organisation.getTypeName()), Mockito.eq("anyRootId"))) + .thenReturn(promise_esOrgResult.future()); + } + + private static Response cassandraGetRecordById() { + Response response = new Response(); + List> list = new ArrayList(); + Map map = new HashMap<>(); + map.put(JsonKey.ID, "anyId"); + map.put(JsonKey.EMAIL, "anyEmailId"); + list.add(map); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private static Map createGetSkillResponse() { + HashMap response = new HashMap<>(); + List> content = new ArrayList<>(); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.EMAIL, "anyEmailId"); + content.add(innerMap); + response.put(JsonKey.CONTENT, content); + return response; + } + + @Test + public void testSendEmailSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(BackgroundOperations.emailService.name()); + + HashMap innerMap = new HashMap<>(); + Map pageMap = new HashMap(); + List emailIdList = new ArrayList<>(); + emailIdList.add("aaa@gmail.com"); + List userIdList = new ArrayList<>(); + userIdList.add("001"); + Map queryMap = new HashMap<>(); + Map filterMap = new HashMap<>(); + filterMap.put(JsonKey.NAME, "anyName"); + queryMap.put(JsonKey.FILTERS, filterMap); + pageMap.put(JsonKey.RECIPIENT_EMAILS, emailIdList); + pageMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + innerMap.put(JsonKey.EMAIL_REQUEST, pageMap); + innerMap.put(JsonKey.RECIPIENT_USERIDS, userIdList); + innerMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + reqObj.setRequest(innerMap); + subject.tell(reqObj, probe.getRef()); + Response response = probe.expectMsgClass(duration("10 second"), Response.class); + assertTrue(response != null); + } + + @Test + public void testSendEmailFailureWithInvalidParameterValue() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(BackgroundOperations.emailService.name()); + + HashMap innerMap = new HashMap<>(); + Map pageMap = new HashMap(); + List emailIdList = new ArrayList<>(); + emailIdList.add("aaa"); + List userIdList = new ArrayList<>(); + userIdList.add("001"); + Map queryMap = new HashMap<>(); + Map filterMap = new HashMap<>(); + queryMap.put(JsonKey.FILTERS, filterMap); + pageMap.put(JsonKey.RECIPIENT_EMAILS, emailIdList); + pageMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + innerMap.put(JsonKey.EMAIL_REQUEST, pageMap); + innerMap.put(JsonKey.RECIPIENT_USERIDS, userIdList); + innerMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + reqObj.setRequest(innerMap); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidParameterValue.getErrorCode())); + } + + @Test + public void testSendEmailFailureWithEmptyFilters() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(BackgroundOperations.emailService.name()); + + HashMap innerMap = new HashMap<>(); + Map pageMap = new HashMap(); + List emailIdList = new ArrayList<>(); + emailIdList.add("aaa@gmail.com"); + List userIdList = new ArrayList<>(); + userIdList.add("001"); + Map queryMap = new HashMap<>(); + Map filterMap = new HashMap<>(); + queryMap.put(JsonKey.FILTERS, filterMap); + pageMap.put(JsonKey.RECIPIENT_EMAILS, emailIdList); + pageMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + innerMap.put(JsonKey.EMAIL_REQUEST, pageMap); + innerMap.put(JsonKey.RECIPIENT_USERIDS, userIdList); + innerMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + reqObj.setRequest(innerMap); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidParameterValue.getErrorCode())); + } + + @Test + public void testSendEmailFailureWithEmailSizeExceeding() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(BackgroundOperations.emailService.name()); + + HashMap innerMap = new HashMap<>(); + Map pageMap = new HashMap(); + List emailIdList = new ArrayList<>(); + + for (int i = 0; i < 40; i++) { + emailIdList.add("aaa" + i + "@gmail.com"); + emailIdList.add("bbb" + i + "@gmail.com"); + emailIdList.add("ccc" + i + "@gmail.com"); + } + List userIdList = new ArrayList<>(); + userIdList.add("001"); + Map queryMap = new HashMap<>(); + Map filterMap = new HashMap<>(); + filterMap.put(JsonKey.NAME, "anyName"); + queryMap.put(JsonKey.FILTERS, filterMap); + pageMap.put(JsonKey.RECIPIENT_EMAILS, emailIdList); + pageMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + innerMap.put(JsonKey.EMAIL_REQUEST, pageMap); + innerMap.put(JsonKey.RECIPIENT_USERIDS, userIdList); + innerMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + reqObj.setRequest(innerMap); + Promise> promise = Futures.promise(); + promise.success(createGetSkillResponse()); + + when(esService.search( + Mockito.eq(ElasticSearchHelper.createSearchDTO(new HashMap<>())), + Mockito.eq(ProjectUtil.EsType.user.getTypeName()))) + .thenReturn(promise.future()); + + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue( + exc.getCode().equals(ResponseCode.emailNotSentRecipientsExceededMaxLimit.getErrorCode())); + } + + @Test + public void testSendEmailFailureWithBlankTemplateName() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(BackgroundOperations.emailService.name()); + + HashMap innerMap = new HashMap<>(); + Map pageMap = new HashMap(); + List emailIdList = new ArrayList<>(); + emailIdList.add("aaa@gmail.com"); + List userIdList = new ArrayList<>(); + userIdList.add("001"); + Map queryMap = new HashMap<>(); + Map filterMap = new HashMap<>(); + filterMap.put(JsonKey.NAME, "anyName"); + queryMap.put(JsonKey.FILTERS, filterMap); + pageMap.put(JsonKey.RECIPIENT_EMAILS, emailIdList); + pageMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + innerMap.put(JsonKey.EMAIL_REQUEST, pageMap); + innerMap.put(JsonKey.RECIPIENT_USERIDS, userIdList); + innerMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + reqObj.setRequest(innerMap); + when(emailTemplateDao.getTemplate(Mockito.anyString())).thenReturn(""); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidParameterValue.getErrorCode())); + } + + @Test + public void testSendEmailFailureWithInvalidUserIdInList() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(BackgroundOperations.emailService.name()); + + HashMap innerMap = new HashMap<>(); + Map pageMap = new HashMap(); + List emailIdList = new ArrayList<>(); + emailIdList.add("aaa@gmail.com"); + List userIdList = new ArrayList<>(); + userIdList.add("001"); + userIdList.add("002"); + Map queryMap = new HashMap<>(); + Map filterMap = new HashMap<>(); + queryMap.put(JsonKey.FILTERS, filterMap); + pageMap.put(JsonKey.RECIPIENT_EMAILS, emailIdList); + + Map searchQueryMap = new HashMap<>(); + Map userIdMap = new HashMap<>(); + userIdMap.put(JsonKey.RECIPIENT_USERIDS, userIdList); + userIdMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, searchQueryMap); + innerMap.put(JsonKey.EMAIL_REQUEST, userIdMap); + + innerMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + reqObj.setRequest(innerMap); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidParameterValue.getErrorCode())); + } + + @Test + public void testSendEmailFailureWithElasticSearchException() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(BackgroundOperations.emailService.name()); + + HashMap innerMap = new HashMap<>(); + Map pageMap = new HashMap(); + List emailIdList = new ArrayList<>(); + emailIdList.add("aaa@gmail.com"); + List userIdList = new ArrayList<>(); + userIdList.add("001"); + Map queryMap = new HashMap<>(); + Map filterMap = new HashMap<>(); + filterMap.put(JsonKey.NAME, "anyName"); + queryMap.put(JsonKey.FILTERS, filterMap); + pageMap.put(JsonKey.RECIPIENT_EMAILS, emailIdList); + pageMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + innerMap.put(JsonKey.EMAIL_REQUEST, pageMap); + innerMap.put(JsonKey.RECIPIENT_USERIDS, userIdList); + innerMap.put(JsonKey.RECIPIENT_SEARCH_QUERY, queryMap); + reqObj.setRequest(innerMap); + when(esService.search( + Mockito.eq(ElasticSearchHelper.createSearchDTO(new HashMap<>())), + Mockito.eq(ProjectUtil.EsType.user.getTypeName()))) + .thenThrow(new ProjectCommonException("", "", 0)); + when(ElasticSearchHelper.getResponseFromFuture(Mockito.any())) + .thenThrow(new ProjectCommonException("", "", 0)); + + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidParameterValue.getErrorCode())); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/HealthActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/HealthActorTest.java new file mode 100644 index 0000000000..8a70ef2a5f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/HealthActorTest.java @@ -0,0 +1,117 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.health.HealthActor; +import org.sunbird.learner.util.Util; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CassandraOperationImpl.class, + ServiceFactory.class, + CassandraOperation.class, + CassandraUtil.class, + Util.class, + EsClientFactory.class, + ElasticSearchService.class, + ElasticSearchHelper.class, + ElasticSearchRestHighImpl.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class HealthActorTest { + + private static ActorSystem system; + private Util.DbInfo badgesDbInfo = Util.dbInfoMap.get(JsonKey.BADGES_DB); + + private CassandraOperation cassandraOperation; + private static final Props props = Props.create(HealthActor.class); + + @BeforeClass + public static void setUp() { + system = ActorSystem.create("system"); + PowerMockito.mockStatic(ServiceFactory.class); + } + + @Test + public void getHealthCheck() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.HEALTH_CHECK.getValue()); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("200 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void getACTORHealthCheck() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.ACTOR.getValue()); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("200 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void getESHealthCheck() { + ElasticSearchService elasticSearchService = PowerMockito.mock(ElasticSearchService.class); + Promise promise = Futures.promise(); + promise.success(true); + PowerMockito.mockStatic(EsClientFactory.class); + when(EsClientFactory.getInstance(JsonKey.REST)).thenReturn(elasticSearchService); + when(elasticSearchService.healthCheck()).thenReturn(promise.future()); + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.ES.getValue()); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("200 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + @PrepareForTest(ServiceFactory.class) + public void getCASSANDRAHealthCheck() { + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.getAllRecords(badgesDbInfo.getKeySpace(), badgesDbInfo.getTableName())) + .thenReturn(new Response()); + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.CASSANDRA.getValue()); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("200 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/NotesManagementActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/NotesManagementActorTest.java new file mode 100644 index 0000000000..f6cdb23892 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/NotesManagementActorTest.java @@ -0,0 +1,351 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.HashMap; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + Util.class, + RequestRouter.class, + ElasticSearchRestHighImpl.class, + EsClientFactory.class +}) +@PowerMockIgnore({"javax.management.*", "javax.crypto.*", "javax.net.ssl.*", "javax.security.*"}) +public class NotesManagementActorTest { + + private static String userId = "userId-example"; + private static String noteId = ""; + private ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(NotesManagementActor.class); + private static CassandraOperationImpl cassandraOperation; + private ElasticSearchService esUtil; + + @Before + public void beforeEachTest() { + ActorRef actorRef = mock(ActorRef.class); + PowerMockito.mockStatic(RequestRouter.class); + when(RequestRouter.getActor(Mockito.anyString())).thenReturn(actorRef); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + esUtil = mock(ElasticSearchRestHighImpl.class); + PowerMockito.mockStatic(EsClientFactory.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esUtil); + } + + @Test + public void testCreateNoteSuccess() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + req.setRequest(reqMap); + req.setOperation(ActorOperations.CREATE_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + boolean result = testScenario(req, null); + assertTrue(result); + } + + @Test + public void testCreateNoteFailure() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + req.setRequest(reqMap); + req.setOperation(ActorOperations.CREATE_NOTE.getValue()); + boolean result = testScenario(req, ResponseCode.invalidUserId); + assertTrue(result); + } + + @Test + public void testCreateNoteFailureWithInvalidUserId() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + req.setRequest(reqMap); + Promise> promise = Futures.promise(); + promise.success(new HashMap<>()); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + req.setOperation(ActorOperations.CREATE_NOTE.getValue()); + boolean result = testScenario(req, ResponseCode.invalidUserId); + assertTrue(result); + } + + @Test + public void testUpdateNoteFailure() { + beforeEachTest(); + Request req = new Request(); + req.getContext().put(JsonKey.USER_ID, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + req.setRequest(reqMap); + req.setOperation(ActorOperations.UPDATE_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(new HashMap<>()); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + boolean result = testScenario(req, ResponseCode.unAuthorized); + assertTrue(result); + } + + @Test + public void testUpdateNoteFailurewithUserIdMismatch() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "misMatch"); + req.setRequest(reqMap); + Promise> promise = Futures.promise(); + promise.success(reqMap); + + req.setOperation(ActorOperations.UPDATE_NOTE.getValue()); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + boolean result = testScenario(req, ResponseCode.errorForbidden); + assertTrue(result); + } + + @Test + public void testUpdateNoteFailurewithEmptyNote() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + req.setRequest(reqMap); + req.setOperation(ActorOperations.UPDATE_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + Promise> promiseAny = Futures.promise(); + promiseAny.success(new HashMap<>()); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()) + .thenReturn(promiseAny.future()); + boolean result = testScenario(req, ResponseCode.invalidNoteId); + assertTrue(result); + } + + @Test + public void testUpdateNoteSuccess() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + req.setRequest(reqMap); + req.setOperation(ActorOperations.UPDATE_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()) + .thenReturn(promise.future()); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + boolean result = testScenario(req, null); + assertTrue(result); + } + + @Test + public void testSearchNoteSuccess() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + req.setRequest(reqMap); + req.setOperation(ActorOperations.SEARCH_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + when(esUtil.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + boolean result = testScenario(req, null); + assertTrue(result); + } + + @Test + public void testGetNoteFailurewithUserIdMismatch() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "misMatch"); + req.setRequest(reqMap); + req.setOperation(ActorOperations.GET_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + boolean result = testScenario(req, ResponseCode.errorForbidden); + assertTrue(result); + } + + @Test + public void testGetNoteFailureWithInvalidUserId() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + req.setRequest(reqMap); + Promise> promise = Futures.promise(); + promise.success(new HashMap<>()); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + req.setOperation(ActorOperations.GET_NOTE.getValue()); + boolean result = testScenario(req, ResponseCode.invalidParameterValue); + assertTrue(result); + } + + @Test + public void testGetNoteFailureWithInvalidNoteId() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + reqMap.put(JsonKey.USER_ID, userId); + reqMap.put(JsonKey.COUNT, 0L); + req.setRequest(reqMap); + Promise> promise = Futures.promise(); + promise.success(reqMap); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + when(esUtil.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + req.setOperation(ActorOperations.GET_NOTE.getValue()); + boolean result = testScenario(req, ResponseCode.invalidNoteId); + assertTrue(result); + } + + @Test + public void testGetNoteSuccess() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + reqMap.put(JsonKey.USER_ID, userId); + reqMap.put(JsonKey.COUNT, 1L); + req.setRequest(reqMap); + Promise> promise = Futures.promise(); + promise.success(reqMap); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + when(esUtil.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + req.setOperation(ActorOperations.GET_NOTE.getValue()); + boolean result = testScenario(req, null); + assertTrue(result); + } + + @Test + public void testDeleteNoteSuccess() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + req.setRequest(reqMap); + req.setOperation(ActorOperations.DELETE_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()) + .thenReturn(promise.future()); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + boolean result = testScenario(req, null); + assertTrue(result); + } + + @Test + public void testDeleteNoteFailurewithEmptyNote() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + req.setRequest(reqMap); + req.setOperation(ActorOperations.DELETE_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + Promise> promise_any = Futures.promise(); + promise_any.success(new HashMap<>()); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()) + .thenReturn(promise_any.future()); + boolean result = testScenario(req, ResponseCode.invalidNoteId); + assertTrue(result); + } + + @Test + public void testDeleteNoteFailurewithUserIdMismatch() { + Request req = new Request(); + req.getContext().put(JsonKey.REQUESTED_BY, userId); + req.getContext().put(JsonKey.NOTE_ID, noteId); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "misMatch"); + req.setRequest(reqMap); + req.setOperation(ActorOperations.DELETE_NOTE.getValue()); + Promise> promise = Futures.promise(); + promise.success(reqMap); + when(esUtil.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + boolean result = testScenario(req, ResponseCode.errorForbidden); + assertTrue(result); + } + + private boolean testScenario(Request reqObj, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + private static Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/OnDemandSchedulerActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/OnDemandSchedulerActorTest.java new file mode 100644 index 0000000000..5313d14c9e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/OnDemandSchedulerActorTest.java @@ -0,0 +1,95 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.*; +import static org.mockito.Mockito.doNothing; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.quartz.scheduler.OnDemandSchedulerManager; +import org.sunbird.common.quartz.scheduler.SchedulerManager; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({OnDemandSchedulerManager.class, SchedulerManager.class}) +@PowerMockIgnore("javax.management.*") +public class OnDemandSchedulerActorTest { + private ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(OnDemandSchedulerActor.class); + private static OnDemandSchedulerManager onDemandSchedulerManager; + private static SchedulerManager schedulerManager; + + @Before + public void beforeEachTest() throws Exception { + schedulerManager = mock(SchedulerManager.class); + onDemandSchedulerManager = mock(OnDemandSchedulerManager.class); + // PowerMockito.whenNew(OnDemandSchedulerManager.class).withNoArguments().thenReturn(onDemandSchedulerManager); + PowerMockito.mockStatic(SchedulerManager.class); + + PowerMockito.mockStatic(OnDemandSchedulerManager.class); + doNothing().when(schedulerManager).schedule(); + when(OnDemandSchedulerManager.getInstance()).thenReturn(onDemandSchedulerManager); + } + + @Test + public void testOnDemandScheduler() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + List types = new ArrayList<>(); + types.add("shadowuser"); + reqMap.put(JsonKey.TYPE, types); + req.setRequest(reqMap); + req.setOperation(ActorOperations.ONDEMAND_START_SCHEDULER.getValue()); + boolean result = testScenario(req, null); + assertTrue(result); + } + + @Test + public void testOnDemandSchedulerWithInvalidType() { + Request req = new Request(); + Map reqMap = new HashMap<>(); + List types = new ArrayList<>(); + types.add("shadowuser1"); + reqMap.put(JsonKey.TYPE, types); + req.setRequest(reqMap); + req.setOperation(ActorOperations.ONDEMAND_START_SCHEDULER.getValue()); + boolean result = testScenario(req, ResponseCode.invalidParameter); + assertTrue(result); + } + + private boolean testScenario(Request request, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(request, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("100 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/OrgManagementActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/OrgManagementActorTest.java new file mode 100644 index 0000000000..3cf28b6799 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/OrgManagementActorTest.java @@ -0,0 +1,395 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.validator.location.LocationRequestValidator; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + OrganisationManagementActor.class, + Util.class, + ElasticSearchRestHighImpl.class, + RequestRouter.class, + ProjectUtil.class, + LocationRequestValidator.class, + EsClientFactory.class +}) +@PowerMockIgnore("javax.management.*") +public class OrgManagementActorTest { + + private ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(OrganisationManagementActor.class); + private static CassandraOperationImpl cassandraOperation; + private static Map basicRequestData; + private static final String ADD_MEMBER_TO_ORG = + ActorOperations.ADD_MEMBER_ORGANISATION.getValue(); + private static ElasticSearchService esService; + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(Util.class); + PowerMockito.mockStatic(ProjectUtil.class); + PowerMockito.mockStatic(EsClientFactory.class); + + cassandraOperation = mock(CassandraOperationImpl.class); + esService = mock(ElasticSearchRestHighImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + basicRequestData = getBasicData(); + Promise> promise = Futures.promise(); + promise.success(getEsResponse(false)); + when(esService.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getRecordsByProperty(false)); + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(false)); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(false)); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(false)); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(false)); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getRecordsByProperty(false)); + when(cassandraOperation.getRecordsByCompositeKey( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(false)); + + when(Util.validateRoles(Mockito.anyList())).thenReturn("SUCCESS"); + when(Util.encryptData(Mockito.anyString())).thenReturn("userExtId"); + when(ProjectUtil.getUniqueIdFromTimestamp(Mockito.anyInt())).thenReturn("time"); + when(ProjectUtil.getFormattedDate()).thenReturn("date"); + when(ProjectUtil.getConfigValue(GeoLocationJsonKey.SUNBIRD_VALID_LOCATION_TYPES)) + .thenReturn("dummy"); + when(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_API_REQUEST_LOWER_CASE_FIELDS)) + .thenReturn("lowercase"); + PowerMockito.mockStatic(LocationRequestValidator.class); + } + + // @Test + public void testUpdateOrgStatus() { + Request reqObj = new Request(); + Map requestData = new HashMap<>(); + requestData.put(JsonKey.REQUESTED_BY, "as23-12asd234-123"); + requestData.put(JsonKey.ORGANISATION_ID, "orgId"); + reqObj.setRequest(requestData); + reqObj.setOperation(ActorOperations.UPDATE_ORG_STATUS.getValue()); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getRecordsByProperty(false)); + boolean result = testScenario(reqObj, null); + assertTrue(result); + } + + @Test + public void testAddUserToOrgSuccessWithUserIdAndOrgId() { + + boolean result = + testScenario( + getRequest( + getRequestData(true, true, false, false, basicRequestData), ADD_MEMBER_TO_ORG), + null); + assertTrue(result); + } + + @Test + public void testAddUserToOrgSuccessWithUserExtIdAndOrgId() { + + boolean result = + testScenario( + getRequest( + getRequestData(false, true, true, false, basicRequestData), ADD_MEMBER_TO_ORG), + null); + assertTrue(result); + } + + @Test + public void testAddUserToOrgSuccessWithUserIdAndOrgExtId() { + + boolean result = + testScenario( + getRequest( + getRequestData(true, false, false, true, basicRequestData), ADD_MEMBER_TO_ORG), + null); + assertTrue(result); + } + + @Test + public void testAddUserToOrgSuccessWithUserExtIdAndOrgExtId() { + + boolean result = + testScenario( + getRequest( + getRequestData(false, false, true, true, basicRequestData), ADD_MEMBER_TO_ORG), + null); + assertTrue(result); + } + + @Test + public void testAddUserToOrgFailureWithUserNotFoundWithUserId() { + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getRecordsByProperty(true)); + boolean result = + testScenario( + getRequest( + getRequestData(true, false, true, true, basicRequestData), ADD_MEMBER_TO_ORG), + ResponseCode.invalidUsrData); + assertTrue(result); + } + + @Test + public void testAddUserToOrgFailureWithOrgNotFoundWithOrgId() { + Promise> promise = Futures.promise(); + promise.success(getEsResponse(true)); + when(esService.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + boolean result = + testScenario( + getRequest( + getRequestData(true, false, true, true, basicRequestData), ADD_MEMBER_TO_ORG), + ResponseCode.invalidOrgData); + assertTrue(result); + } + + @Test + public void testAddUserToOrgFailureWithUserNotFoundWithUserExtId() { + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(true)); + + boolean result = + testScenario( + getRequest( + getRequestData(false, false, true, true, basicRequestData), ADD_MEMBER_TO_ORG), + ResponseCode.invalidUsrData); + assertTrue(result); + } + + @Test + public void testAddUserToOrgFailureWithOrgNotFoundWithOrgExtId() { + Promise> promise = Futures.promise(); + promise.success(getEsResponse(true)); + when(esService.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + boolean result = + testScenario( + getRequest( + getRequestData(true, false, true, true, basicRequestData), ADD_MEMBER_TO_ORG), + ResponseCode.invalidOrgData); + assertTrue(result); + } + + @Test + public void testCreateOrgSuccessWithExternalIdAndProvider() { + when(cassandraOperation.getRecordsByCompositeKey( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(true)); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccess()); + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(true)); + Promise> promise = Futures.promise(); + promise.success(getValidateChannelEsResponse(true)); + + when(esService.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + boolean result = + testScenario( + getRequest( + getRequestDataForOrgCreate(basicRequestData), + ActorOperations.CREATE_ORG.getValue()), + null); + assertTrue(result); + } + + @Test + public void testCreateOrgSuccessWithoutExternalIdAndProvider() { + when(cassandraOperation.getRecordsByCompositeKey( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(true)); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccess()); + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsByProperty(true)); + Promise> promise = Futures.promise(); + promise.success(getValidateChannelEsResponse(true)); + + when(esService.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + Map map = getRequestDataForOrgCreate(basicRequestData); + map.remove(JsonKey.EXTERNAL_ID); + boolean result = testScenario(getRequest(map, ActorOperations.CREATE_ORG.getValue()), null); + assertTrue(result); + } + + @Test + public void testCreateOrgFailureWithoutChannel() { + Map map = getRequestDataForOrgCreate(basicRequestData); + map.remove(JsonKey.CHANNEL); + boolean result = + testScenario( + getRequest(map, ActorOperations.CREATE_ORG.getValue()), + ResponseCode.mandatoryParamsMissing); + assertTrue(result); + } + + private Response getOrgStatus() { + Response res = new Response(); + List> list = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.STATUS, 1); + map.put(JsonKey.ID, "id"); + list.add(map); + res.put(JsonKey.RESPONSE, list); + return res; + } + + private Response getSuccess() { + Response res = new Response(); + res.setResponseCode(ResponseCode.OK); + return res; + } + + private Map getRequestDataForOrgCreate(Map map) { + map.put(JsonKey.CHANNEL, "channel"); + map.put(JsonKey.IS_ROOT_ORG, false); + map.put(JsonKey.EXTERNAL_ID, "externalId"); + + return map; + } + + private Map getRequestData( + boolean userId, boolean orgId, boolean userExtId, boolean OrgExtId, Map map) { + List rolesList = new ArrayList<>(); + rolesList.add("dummyRole"); + map.put(JsonKey.ROLES, rolesList); + if (userId) { + map.put(JsonKey.USER_ID, "userId"); + } + if (orgId) { + map.put(JsonKey.ORGANISATION_ID, "orgId"); + } + if (userExtId) { + map.put(JsonKey.USER_EXTERNAL_ID, "userExtId"); + } + if (OrgExtId) { + map.put(JsonKey.EXTERNAL_ID, "externalId"); + } + return map; + } + + private Response getRecordsByProperty(boolean empty) { + Response res = new Response(); + List> list = new ArrayList<>(); + if (!empty) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, "userId"); + map.put(JsonKey.IS_DELETED, true); + list.add(map); + } + res.put(JsonKey.RESPONSE, list); + return res; + } + + private Map getEsResponse(boolean empty) { + Map response = new HashMap<>(); + List> contentList = new ArrayList<>(); + if (!empty) { + Map content = new HashMap<>(); + content.put(JsonKey.ORGANISATION_ID, "orgId"); + content.put(JsonKey.HASHTAGID, "hashtagId"); + contentList.add(content); + } + response.put(JsonKey.CONTENT, contentList); + return response; + } + + private Map getValidateChannelEsResponse(boolean isValidChannel) { + Map response = new HashMap<>(); + List> contentList = new ArrayList<>(); + if (isValidChannel) { + Map content = new HashMap<>(); + content.put(JsonKey.STATUS, 1); + content.put(JsonKey.ID, "id"); + contentList.add(content); + } + response.put(JsonKey.CONTENT, contentList); + return response; + } + + private boolean testScenario(Request request, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(request, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + private Request getRequest(Map requestData, String actorOperation) { + Request reqObj = new Request(); + reqObj.setRequest(requestData); + reqObj.setOperation(actorOperation); + return reqObj; + } + + private Map getBasicData() { + Map map = new HashMap<>(); + map.put(JsonKey.PROVIDER, "provider"); + map.put(JsonKey.USER_PROVIDER, "userProvider"); + map.put(JsonKey.USER_ID_TYPE, "userIdType"); + return map; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/SearchHandlerActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/SearchHandlerActorTest.java new file mode 100644 index 0000000000..1be40bf960 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/SearchHandlerActorTest.java @@ -0,0 +1,163 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.*; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.search.SearchHandlerActor; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ServiceFactory.class, ElasticSearchRestHighImpl.class, EsClientFactory.class}) +@PowerMockIgnore({"javax.management.*"}) +public class SearchHandlerActorTest { + + private static ActorSystem system; + private static final Props props = Props.create(SearchHandlerActor.class); + private static CassandraOperationImpl cassandraOperation; + private static ElasticSearchService esService; + + @BeforeClass + public static void setUp() { + system = ActorSystem.create("system"); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + } + + @Before + public void beforeTest() { + PowerMockito.mockStatic(EsClientFactory.class); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + Promise> promise = Futures.promise(); + promise.success(createResponseGet(true)); + when(esService.search(Mockito.any(SearchDTO.class), Mockito.anyVararg())) + .thenReturn(promise.future()); + + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap(), Mockito.anyList())) + .thenReturn(getRecordByPropertyResponse()); + } + + private static Response getRecordByPropertyResponse() { + + Response response = new Response(); + List> list = new ArrayList<>(); + Map courseMap = new HashMap<>(); + courseMap.put(JsonKey.ACTIVE, true); + courseMap.put(JsonKey.USER_ID, "anyUserId"); + list.add(courseMap); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private static Map createResponseGet(boolean isResponseRequired) { + HashMap response = new HashMap<>(); + List> content = new ArrayList<>(); + HashMap innerMap = new HashMap<>(); + List> orgList = new ArrayList<>(); + Map orgMap = new HashMap<>(); + orgMap.put(JsonKey.ORGANISATION_ID, "anyOrgId"); + + innerMap.put(JsonKey.ROOT_ORG_ID, "anyRootOrgId"); + innerMap.put(JsonKey.ORGANISATIONS, orgList); + innerMap.put(JsonKey.HASHTAGID, "HASHTAGID"); + content.add(innerMap); + response.put(JsonKey.CONTENT, content); + return response; + } + + @Test + public void searchUser() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.COMPOSITE_SEARCH.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.QUERY, ""); + Map filters = new HashMap<>(); + List objectType = new ArrayList(); + objectType.add("user"); + filters.put(JsonKey.OBJECT_TYPE, objectType); + filters.put(JsonKey.ROOT_ORG_ID, "ORG_001"); + innerMap.put(JsonKey.FILTERS, filters); + innerMap.put(JsonKey.LIMIT, 1); + Map contextMap = new HashMap<>(); + contextMap.put(JsonKey.FIELDS, JsonKey.ORG_NAME); + reqObj.setContext(contextMap); + reqObj.setRequest(innerMap); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void searchUserWithObjectTypeAsOrg() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.COMPOSITE_SEARCH.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.QUERY, ""); + Map filters = new HashMap<>(); + List objectType = new ArrayList(); + objectType.add("org"); + filters.put(JsonKey.OBJECT_TYPE, objectType); + filters.put(JsonKey.ROOT_ORG_ID, "ORG_001"); + innerMap.put(JsonKey.FILTERS, filters); + innerMap.put(JsonKey.LIMIT, 1); + + Map contextMap = new HashMap<>(); + contextMap.put(JsonKey.FIELDS, JsonKey.ORG_NAME); + reqObj.setContext(contextMap); + reqObj.setRequest(innerMap); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testInvalidOperation() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request reqObj = new Request(); + reqObj.setOperation("INVALID_OPERATION"); + + subject.tell(reqObj, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/UserTnCActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/UserTnCActorTest.java new file mode 100644 index 0000000000..01cc0af951 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/UserTnCActorTest.java @@ -0,0 +1,180 @@ +package org.sunbird.learner.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.tac.UserTnCActor; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + SystemSettingClientImpl.class, + RequestRouter.class, + EsClientFactory.class, + ElasticSearchRestHighImpl.class, + SunbirdMWService.class +}) +@PowerMockIgnore({"javax.management.*", "javax.crypto.*", "javax.net.ssl.*", "javax.security.*"}) +public class UserTnCActorTest { + private static ActorSystem system; + + private static final Props props = Props.create(UserTnCActor.class); + private static final CassandraOperation cassandraOperation = mock(CassandraOperationImpl.class);; + public static SystemSettingClient systemSettingClient; + private static final String LATEST_VERSION = "latestVersion"; + private static final String ACCEPTED_CORRECT_VERSION = "latestVersion"; + private static final String ACCEPTED_INVALID_VERSION = "invalid"; + private static ElasticSearchService esService; + + @BeforeClass + public static void setUp() { + system = ActorSystem.create("system"); + } + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(SystemSettingClientImpl.class); + PowerMockito.mockStatic(RequestRouter.class); + systemSettingClient = mock(SystemSettingClientImpl.class); + when(SystemSettingClientImpl.getInstance()).thenReturn(systemSettingClient); + ActorRef actorRef = mock(ActorRef.class); + + PowerMockito.mockStatic(SunbirdMWService.class); + SunbirdMWService.tellToBGRouter(Mockito.any(), Mockito.any()); + when(RequestRouter.getActor(Mockito.anyString())).thenReturn(actorRef); + + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + PowerMockito.mockStatic(EsClientFactory.class); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + } + + @Test + public void testAcceptUserTcnSuccessWithAcceptFirstTime() { + Promise> promise = Futures.promise(); + promise.success(getUser(null)); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + Response response = + setRequest(ACCEPTED_CORRECT_VERSION).expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue( + null != response && "SUCCESS".equals(response.getResult().get(JsonKey.RESPONSE))); + } + + @Test + public void testAcceptUserTncSuccessAlreadyAccepted() { + Promise> promise = Futures.promise(); + promise.success(getUser(LATEST_VERSION)); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + Response response = + setRequest(ACCEPTED_CORRECT_VERSION).expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue( + null != response && "SUCCESS".equals(response.getResult().get(JsonKey.RESPONSE))); + } + + @Test + public void testAcceptUserTncForBlockedUser() { + Promise> promise_recipientSearchQuery = Futures.promise(); + Map recipientSearchQuery = new HashMap<>(); + recipientSearchQuery.put(JsonKey.ROOT_ORG_ID, "anyRootId"); + recipientSearchQuery.put(JsonKey.IS_DELETED, true); + promise_recipientSearchQuery.trySuccess(recipientSearchQuery); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise_recipientSearchQuery.future()); + ProjectCommonException response = + setRequest(ACCEPTED_CORRECT_VERSION) + .expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertEquals(ResponseCode.userAccountlocked.getErrorCode(), response.getCode()); + Assert.assertEquals("User account has been blocked .", response.getMessage()); + } + + @Test + public void testAcceptUserTncFailureWithInvalidVersion() { + ProjectCommonException exception = + setRequest(ACCEPTED_INVALID_VERSION) + .expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue( + null != exception + && exception + .getCode() + .equalsIgnoreCase(ResponseCode.invalidParameterValue.getErrorCode())); + } + + private TestKit setRequest(String version) { + mockTnCSystemSettingResponse(); + mockCassandraOperation(); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.USER_TNC_ACCEPT.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.VERSION, version); + reqObj.setRequest(innerMap); + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + return probe; + } + + private void mockCassandraOperation() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response); + } + + private void mockTnCSystemSettingResponse() { + when(systemSettingClient.getSystemSettingByFieldAndKey( + Mockito.any(ActorRef.class), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyObject())) + .thenReturn(LATEST_VERSION); + } + + private Map getUser(String lastAcceptedVersion) { + Map user = new HashMap<>(); + user.put(JsonKey.NAME, "someName"); + if (lastAcceptedVersion != null) { + user.put(JsonKey.TNC_ACCEPTED_VERSION, lastAcceptedVersion); + } + + return user; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/bulkupload/BulkUploadManagementActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/bulkupload/BulkUploadManagementActorTest.java new file mode 100644 index 0000000000..bc711d099b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/bulkupload/BulkUploadManagementActorTest.java @@ -0,0 +1,375 @@ +package org.sunbird.learner.actors.bulkupload; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.*; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +/** @author arvind. Junit test cases for bulk upload - user, org */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ServiceFactory.class, Util.class, BulkUploadManagementActor.class}) +@PowerMockIgnore("javax.management.*") +public class BulkUploadManagementActorTest { + + private static ActorSystem system; + private static final Props props = Props.create(BulkUploadManagementActor.class); + private static final String USER_ID = "bcic783gfu239"; + private static final String refOrgId = "id34fy"; + private static CassandraOperationImpl cassandraOperation; + private static final String PROCESS_ID = "process-13647-fuzzy"; + + @BeforeClass + public static void setUp() { + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + system = ActorSystem.create("system"); + } + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + } + + @Test + public void checkTelemetryKeyFailure() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + String telemetryEnvKey = "user"; + PowerMockito.mockStatic(Util.class); + PowerMockito.doNothing() + .when( + Util.class, + "initializeContext", + Mockito.any(Request.class), + Mockito.eq(telemetryEnvKey)); + + byte[] bytes = getFileAsBytes("BulkOrgUploadSample.csv"); + + Response response = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.ORGANISATION); + innerMap.put(JsonKey.FILE, bytes); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + String uploadProcessId = (String) res.get(JsonKey.PROCESS_ID); + Assert.assertTrue(!(telemetryEnvKey.charAt(0) >= 65 && telemetryEnvKey.charAt(0) <= 90)); + } + + @Test + public void testOrgBulkUploadCreateOrgSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + byte[] bytes = getFileAsBytes("BulkOrgUploadSample.csv"); + + Response response = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.ORGANISATION); + innerMap.put(JsonKey.FILE, bytes); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + String uploadProcessId = (String) res.get(JsonKey.PROCESS_ID); + Assert.assertTrue(null != uploadProcessId); + } + + @Test + public void testOrgBulkUploadCreateOrgEmptyCsvFile() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + byte[] bytes = getFileAsBytes("BulkOrgUploadEmptyFile.csv"); + Response response = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.ORGANISATION); + innerMap.put(JsonKey.FILE, bytes); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertNotNull(res); + Assert.assertEquals(ResponseCode.csvError.getErrorCode(), res.getCode()); + Assert.assertEquals(ResponseCode.csvError.getErrorMessage(), res.getMessage()); + } + + @Test + public void testOrgBulkUploadCreateOrgWithInvalidHeaders() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + String headerLine = "batchId,orgName,isRootOrg,channel"; + String firstLine = "batch78575ir8478,hello001,false,,1119"; + StringBuilder builder = new StringBuilder(); + builder.append(headerLine).append("\n").append(firstLine); + + Response response = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.ORGANISATION); + innerMap.put(JsonKey.FILE, builder.toString().getBytes()); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != res); + } + + @Test + public void testBulkUploadGetStatus() { + Response response = getCassandraRecordByIdForBulkUploadResponse(); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyList())) + .thenReturn(response); + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.GET_BULK_OP_STATUS.getValue()); + reqObj.getRequest().put(JsonKey.PROCESS_ID, PROCESS_ID); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + List> list = (List>) res.get(JsonKey.RESPONSE); + if (!list.isEmpty()) { + Map map = list.get(0); + String processId = (String) map.get(JsonKey.PROCESS_ID); + Assert.assertTrue(null != processId); + } + } + + @Ignore + public void testUserBulkUploadCreateUserSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + byte[] bytes = getFileAsBytes("BulkUploadUserSample.csv"); + Response response = getCassandraRecordByIdForOrgResponse(); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(response); + Util.DbInfo orgDbInfo = Util.dbInfoMap.get(JsonKey.ORG_DB); + when(cassandraOperation.getRecordById( + orgDbInfo.getKeySpace(), orgDbInfo.getTableName(), refOrgId)) + .thenReturn(response); + Response insertResponse = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(insertResponse); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.USER); + innerMap.put(JsonKey.ORGANISATION_ID, refOrgId); + innerMap.put(JsonKey.FILE, bytes); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 seconds"), Response.class); + String processId = (String) res.get(JsonKey.PROCESS_ID); + Assert.assertTrue(null != processId); + } + + @Ignore + public void testUserBulkUploadCreateUserWithOrgExtId() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + byte[] bytes = getFileAsBytes("BulkUploadUserSample.csv"); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getCassandraRecordByIdForOrgResponse()); + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getCassandraRecordByIdForOrgResponse()); + Response insertResponse = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(insertResponse); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.USER); + innerMap.put(JsonKey.ORG_PROVIDER, "provider"); + innerMap.put(JsonKey.ORG_EXTERNAL_ID, "externalId"); + innerMap.put(JsonKey.FILE, bytes); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 seconds"), Response.class); + String processId = (String) res.get(JsonKey.PROCESS_ID); + Assert.assertTrue(null != processId); + } + + @Test + public void userBulkUploadWithInvalidHeaders() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + byte[] bytes = getFileAsBytes("BulkUploadUserWithInvalidHeaders.csv"); + Response response = getCassandraRecordByIdForOrgResponse(); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(response); + Response insertResponse = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(insertResponse); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.USER); + innerMap.put(JsonKey.ORGANISATION_ID, refOrgId); + innerMap.put(JsonKey.FILE, bytes); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException ex = + probe.expectMsgClass(duration("10 seconds"), ProjectCommonException.class); + Assert.assertTrue(null != ex); + Assert.assertEquals(ResponseCode.invalidColumns.getErrorCode(), ex.getCode()); + Assert.assertEquals( + "Invalid column: password. Valid columns are: firstName, lastName, phone, countryCode, email, userName, phoneVerified, emailVerified, roles, position, grade, location, dob, gender, language, profileSummary, subject, webPages, externalIdProvider, externalId, externalIdType, externalIds.", + ex.getMessage()); + } + + @Test + public void testUserBulkUploadCreateUserWithInvalidHeaders() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + String headerLine = "batchId,firstName,lastName,phone"; + String firstLine = "batch78575ir8478,xyz1234516,Kumar15,9000000011"; + StringBuilder builder = new StringBuilder(); + builder.append(headerLine).append("\n").append(firstLine); + + Response response = getCassandraRecordByIdForOrgResponse(); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(response); + Response insertResponse = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(insertResponse); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.USER); + innerMap.put(JsonKey.ORGANISATION_ID, refOrgId); + + innerMap.put(JsonKey.FILE, builder.toString().getBytes()); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != res); + } + + private Response createCassandraInsertSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + private Response getCassandraRecordByIdForBulkUploadResponse() { + Response response = new Response(); + List> list = new ArrayList<>(); + Map bulkUploadProcessMap = new HashMap<>(); + bulkUploadProcessMap.put(JsonKey.ID, "123"); + bulkUploadProcessMap.put(JsonKey.STATUS, ProjectUtil.BulkProcessStatus.COMPLETED.getValue()); + bulkUploadProcessMap.put(JsonKey.OBJECT_TYPE, JsonKey.ORGANISATION); + list.add(bulkUploadProcessMap); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private Response getCassandraRecordByIdForOrgResponse() { + Response response = new Response(); + List> list = new ArrayList<>(); + Map orgMap = new HashMap<>(); + orgMap.put(JsonKey.ORGANISATION_ID, refOrgId); + orgMap.put(JsonKey.IS_ROOT_ORG, true); + orgMap.put(JsonKey.EXTERNAL_ID, "externalId"); + orgMap.put(JsonKey.PROVIDER, "provider"); + orgMap.put(JsonKey.ID, refOrgId); + orgMap.put(JsonKey.CHANNEL, "channel"); + list.add(orgMap); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private byte[] getFileAsBytes(String fileName) { + File file = null; + byte[] bytes = null; + try { + file = + new File( + BulkUploadManagementActorTest.class.getClassLoader().getResource(fileName).getFile()); + Path path = Paths.get(file.getPath()); + bytes = Files.readAllBytes(path); + } catch (FileNotFoundException e) { + ProjectLogger.log(e.getMessage(), e); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + return bytes; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadActorTest.java new file mode 100644 index 0000000000..db3274afec --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/bulkupload/LocationBulkUploadActorTest.java @@ -0,0 +1,211 @@ +package org.sunbird.learner.actors.bulkupload; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.BulkUploadActorOperation; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.bulkupload.dao.impl.BulkUploadProcessDaoImpl; +import org.sunbird.learner.util.Util; + +/** + * Test case for Location Bulk upload. + * + * @author arvind on 30/4/18. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@PrepareForTest({ + ServiceFactory.class, + Util.class, + LocationBulkUploadActor.class, + BulkUploadProcessDaoImpl.class, + LocationBulkUploadBackGroundJobActor.class +}) +@PowerMockIgnore("javax.management.*") +@RunWith(PowerMockRunner.class) +public class LocationBulkUploadActorTest { + + private static ActorSystem system; + private static final Props props = Props.create(LocationBulkUploadActor.class); + private static final String USER_ID = "user123"; + private static final String LOCATION_TYPE = "State"; + private static CassandraOperationImpl cassandraOperation; + + @BeforeClass + public static void setUp() { + system = ActorSystem.create("system"); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + } + + @Test + @Ignore + public void testLocationBulkUploadWithProperData() throws Exception { + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getCassandraRecordByIdForUserResponse()); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createCassandraInsertSuccessResponse()); + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + List headerLine = + Arrays.asList( + GeoLocationJsonKey.PROPERTY_NAME, + GeoLocationJsonKey.CODE, + GeoLocationJsonKey.PARENT_CODE, + GeoLocationJsonKey.PARENT_ID); + List firstDataLine = Arrays.asList("location_name", "location-code", null, null); + String jsonString = createLines(headerLine, firstDataLine); + Request reqObj = getRequestObjectForLocationBulkUpload(LOCATION_TYPE, jsonString.getBytes()); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + String processId = (String) res.get(JsonKey.PROCESS_ID); + Assert.assertTrue(null != processId); + } + + private Response createCassandraInsertSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + private Response getCassandraRecordByIdForUserResponse() { + Response response = new Response(); + List> userList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.USER_ID, "VALID-USER-ID"); + map.put(JsonKey.CHANNEL, "anyChannel"); + userList.add(map); + response.put(JsonKey.RESPONSE, userList); + return response; + } + + @Test + public void testLocationBulkUploadWithInvalidAttributeNames() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + List headerLine = + Arrays.asList( + GeoLocationJsonKey.PROPERTY_NAME + "invalid", + GeoLocationJsonKey.CODE, + GeoLocationJsonKey.PARENT_CODE, + GeoLocationJsonKey.PARENT_ID); + List firstDataLine = Arrays.asList("location_name", "location-code", null, null); + String jsonString = createLines(headerLine, firstDataLine); + Request reqObj = getRequestObjectForLocationBulkUpload(LOCATION_TYPE, jsonString.getBytes()); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != res); + } + + @Test + public void testLocationBulkUploadWithoutMandatoryFieldCode() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + List headerLine = + Arrays.asList( + GeoLocationJsonKey.PROPERTY_NAME, + GeoLocationJsonKey.PARENT_CODE, + GeoLocationJsonKey.PARENT_ID); + List firstDataLine = Arrays.asList("location_name", null, null); + String jsonString = createLines(headerLine, firstDataLine); + Request reqObj = getRequestObjectForLocationBulkUpload(LOCATION_TYPE, jsonString.getBytes()); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != res); + } + + @Test + public void testLocationBulkUploadWithoutAnyDataRecord() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + List headerLine = + Arrays.asList( + GeoLocationJsonKey.PROPERTY_NAME, + GeoLocationJsonKey.PARENT_CODE, + GeoLocationJsonKey.PARENT_ID); + String jsonString = createLines(headerLine); + Request reqObj = getRequestObjectForLocationBulkUpload(LOCATION_TYPE, jsonString.getBytes()); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != res); + } + + @Test + public void testLocationBulkUploadWithExtraAttributeNameValue() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + List headerLine = + Arrays.asList( + GeoLocationJsonKey.PROPERTY_NAME, + GeoLocationJsonKey.CODE, + GeoLocationJsonKey.PARENT_CODE, + GeoLocationJsonKey.PARENT_ID, + GeoLocationJsonKey.PROPERTY_VALUE); + List firstDataLine = + Arrays.asList("location_name", "location-code", null, null, "value"); + String jsonString = createLines(headerLine, firstDataLine); + Request reqObj = getRequestObjectForLocationBulkUpload(LOCATION_TYPE, jsonString.getBytes()); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != res); + } + + private Request getRequestObjectForLocationBulkUpload(String locationType, byte[] file) { + Request reqObj = new Request(); + reqObj.setOperation(BulkUploadActorOperation.LOCATION_BULK_UPLOAD.getValue()); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CREATED_BY, USER_ID); + innerMap.put(JsonKey.OBJECT_TYPE, JsonKey.LOCATION); + innerMap.put(JsonKey.FILE, file); + innerMap.put(GeoLocationJsonKey.LOCATION_TYPE, locationType); + reqObj.getRequest().put(JsonKey.DATA, innerMap); + return reqObj; + } + + private String createLines(List... list) throws JsonProcessingException { + + StringBuilder builder = new StringBuilder(); + for (List l : list) { + String.join(",", l); + builder.append(String.join(",", l)); + builder.append(System.lineSeparator()); + } + return builder.toString(); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/client/ClientManagementActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/client/ClientManagementActorTest.java new file mode 100644 index 0000000000..28fb768882 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/client/ClientManagementActorTest.java @@ -0,0 +1,237 @@ +package org.sunbird.learner.actors.client; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ServiceFactory.class, Util.class}) +@PowerMockIgnore({"javax.management.*"}) +public class ClientManagementActorTest { + + private static ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(ClientManagementActor.class); + private static final String masterKey = "anyMasterKey"; + private static final String clientId = "anyClientId"; + private static final String clientName = "anyClientName"; + private static final String channel = "anyChannel"; + private static final String id = "anyId"; + private static final CassandraOperationImpl cassandraOperation = + mock(CassandraOperationImpl.class); + private Map request = new HashMap<>(); + private Map orgMap = new HashMap<>(); + + @Before + public void init() { + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + request.clear(); + orgMap.clear(); + } + + @Test + public void checkTelemetryKeyFailure() throws Exception { + + String telemetryEnvKey = "masterKey"; + PowerMockito.mockStatic(Util.class); + PowerMockito.doNothing() + .when( + Util.class, + "initializeContext", + Mockito.any(Request.class), + Mockito.eq(telemetryEnvKey)); + + request.put(JsonKey.CLIENT_NAME, clientName); + orgMap.put(JsonKey.CLIENT_ID, clientId); + boolean result = testScenario(request, orgMap, ActorOperations.REGISTER_CLIENT, null); + Assert.assertTrue(!(telemetryEnvKey.charAt(0) >= 65 && telemetryEnvKey.charAt(0) <= 90)); + } + + @Test + public void testRegisterClientSuccess() { + + request.put(JsonKey.CLIENT_NAME, clientName); + orgMap.put(JsonKey.CLIENT_ID, clientId); + boolean result = testScenario(request, orgMap, ActorOperations.REGISTER_CLIENT, null); + Assert.assertTrue(result); + } + + @Test + public void testRegisterClientFailureWithDuplicateChannel() { + + orgMap.put(JsonKey.MASTER_KEY, masterKey); + request.put(JsonKey.CLIENT_NAME, clientName); + request.put(JsonKey.CHANNEL, channel); + boolean result = + testScenario( + request, + orgMap, + ActorOperations.REGISTER_CLIENT, + ResponseCode.channelUniquenessInvalid); + Assert.assertTrue(result); + } + + @Test + public void testRegisterClientFailureWithInvalidClientName() { + + orgMap.put(JsonKey.ID, id); + request.put(JsonKey.CLIENT_NAME, clientName); + boolean result = + testScenario( + request, orgMap, ActorOperations.REGISTER_CLIENT, ResponseCode.invalidClientName); + Assert.assertTrue(result); + } + + @Test + public void testGetClientKeySuccess() { + + request.put(JsonKey.CLIENT_ID, clientId); + request.put(JsonKey.TYPE, JsonKey.CLIENT_ID); + orgMap.put(JsonKey.ID, id); + boolean result = testScenario(request, orgMap, ActorOperations.GET_CLIENT_KEY, null); + Assert.assertTrue(result); + } + + @Test + public void testGetClientKeyFailureWithInvalidClientIdType() { + + request.put(JsonKey.CLIENT_ID, clientId); + request.put(JsonKey.TYPE, JsonKey.CLIENT_ID); + boolean result = + testScenario( + request, orgMap, ActorOperations.GET_CLIENT_KEY, ResponseCode.invalidRequestData); + Assert.assertTrue(result); + } + + @Test + public void testGetClientKeyFailureWithInvalidChannelType() { + + request.put(JsonKey.CLIENT_ID, clientId); + request.put(JsonKey.TYPE, JsonKey.CHANNEL); + boolean result = + testScenario( + request, orgMap, ActorOperations.GET_CLIENT_KEY, ResponseCode.invalidRequestData); + Assert.assertTrue(result); + } + + @Test + public void testGetClientKeyFailureWithoutType() { + + request.put(JsonKey.CLIENT_ID, clientId); + boolean result = + testScenario( + request, orgMap, ActorOperations.GET_CLIENT_KEY, ResponseCode.invalidRequestData); + Assert.assertTrue(result); + } + + @Test + public void testUpdateClientKeySuccess() { + + orgMap.put(JsonKey.MASTER_KEY, masterKey); + boolean result = testScenario(orgMap, orgMap, ActorOperations.UPDATE_CLIENT_KEY, null); + Assert.assertTrue(result); + } + + @Test + public void testUpdateClientKeyFailureWithInvalidRequestedData() { + + request.put(JsonKey.CLIENT_ID, clientId); + request.put(JsonKey.MASTER_KEY, masterKey); + boolean result = + testScenario( + request, orgMap, ActorOperations.UPDATE_CLIENT_KEY, ResponseCode.invalidRequestData); + Assert.assertTrue(result); + } + + @Test + public void testUpdateClientKeyFailureWithDuplicateChannel() { + + request.put(JsonKey.CLIENT_ID, clientId); + request.put(JsonKey.CHANNEL, channel); + orgMap.put(JsonKey.CHANNEL, "differentChannel"); + boolean result = + testScenario( + request, + orgMap, + ActorOperations.UPDATE_CLIENT_KEY, + ResponseCode.channelUniquenessInvalid); + Assert.assertTrue(result); + } + + private static Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + private static Response getCassandraResponse(Map orgMap) { + Response response = new Response(); + List> list = new ArrayList<>(); + if (!orgMap.isEmpty()) { + list.add(orgMap); + } + response.put(JsonKey.RESPONSE, list); + return response; + } + + private boolean testScenario( + Map request, + Map orgMap, + ActorOperations actorOperations, + ResponseCode errorResponse) { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request actorMessage = new Request(); + actorMessage.setRequest(request); + actorMessage.setOperation(actorOperations.getValue()); + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getCassandraResponse(orgMap)); + subject.tell(actorMessage, probe.getRef()); + if (errorResponse == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + + return res.getCode().equals(errorResponse.getErrorCode()) + || res.getResponseCode() == errorResponse.getResponseCode(); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/geolocation/GeoLocationManagementActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/geolocation/GeoLocationManagementActorTest.java new file mode 100644 index 0000000000..7e02532c07 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/geolocation/GeoLocationManagementActorTest.java @@ -0,0 +1,458 @@ +package org.sunbird.learner.actors.geolocation; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ServiceFactory.class, Util.class, DataCacheHandler.class}) +@PowerMockIgnore({"javax.management.*"}) +public class GeoLocationManagementActorTest { + + private ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(GeoLocationManagementActor.class); + private static CassandraOperationImpl cassandraOperation; + private static final String orgId = "hhjcjr79fw4p89"; + private static final String type = "husvej"; + private static final String userId = "vcurc633r8911"; + private static List> createResponse; + private static String id = "anyId"; + + @BeforeClass + public static void setUp() { + + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + Map orgMap = new HashMap(); + orgMap.put(JsonKey.ID, orgId); + } + + @Before + public void beforeTest() { + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(cassandraGetRecordById()); + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(cassandraGetRecordById()); + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyList())) + .thenReturn(cassandraGetRecordById()); + } + + private static Response cassandraGetRecordById() { + Response response = new Response(); + List list = new ArrayList(); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "anyName"); + map.put(JsonKey.ID, "anyId"); + map.put(JsonKey.USER_COUNT, 0); + list.add(map); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private static Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + @Test + public void createGeoLocationSuccess() { + + List> dataList = new ArrayList<>(); + Map dataMap = new HashMap<>(); + dataMap.put(JsonKey.LOCATION, "location"); + dataMap.put(JsonKey.TYPE, type); + + dataList.add(dataMap); + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.setOperation(ActorOperations.CREATE_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.DATA, dataList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + createResponse = (List>) res.getResult().get(JsonKey.RESPONSE); + if (createResponse != null && createResponse.size() > 0) { + id = (String) createResponse.get(0).get(JsonKey.ID); + createResponse.remove(createResponse.get(0)); + } + Assert.assertTrue(null != id); + } + + @Test + public void createGeoLocationFailureWithNullOrgId() { + + List> dataList = new ArrayList<>(); + + Map dataMap = new HashMap<>(); + dataMap.put(JsonKey.LOCATION, "location"); + dataMap.put(JsonKey.TYPE, type); + + dataList.add(dataMap); + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.setOperation(ActorOperations.CREATE_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.DATA, dataList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, null); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidOrgId.getErrorCode())); + } + + @Test + public void createGeoLocationTestWithInvalidOrgId() { + + List> dataList = new ArrayList<>(); + + Map dataMap = new HashMap<>(); + dataMap.put(JsonKey.LOCATION, "location"); + dataMap.put(JsonKey.TYPE, type); + + dataList.add(dataMap); + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.setOperation(ActorOperations.CREATE_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.DATA, dataList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, "invalidOrgId"); + + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getFailureResponse()); + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidOrgId.getErrorCode())); + } + + private Response getFailureResponse() { + Response response = new Response(); + List> objList = new ArrayList<>(); + response.put(JsonKey.RESPONSE, objList); + return response; + } + + @Test + public void createGeoLocationFailureWithInvalidData() { + + List> dataList = new ArrayList<>(); + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.setOperation(ActorOperations.CREATE_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.DATA, dataList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidRequestData.getErrorCode())); + } + + @Test + public void getGeoLocationSuccessOrgId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.TYPE, JsonKey.ORGANISATION); + actorMessage.getRequest().put(JsonKey.ID, orgId); + actorMessage.setOperation(ActorOperations.GET_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void getGeoLocationSuccessWithLocationId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.TYPE, JsonKey.LOCATION); + actorMessage.getRequest().put(JsonKey.ID, id); + actorMessage.setOperation(ActorOperations.GET_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void getGeoLocationFailureWithNullType() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.TYPE, null); + actorMessage.getRequest().put(JsonKey.ID, orgId); + actorMessage.setOperation(ActorOperations.GET_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidRequestData.getErrorCode())); + } + + @Test + public void getGeoLocationFailureWithInvalidType() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.TYPE, "Invalid type"); + actorMessage.getRequest().put(JsonKey.ID, orgId); + actorMessage.setOperation(ActorOperations.GET_GEO_LOCATION.getValue()); + + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + + subject.tell(actorMessage, probe.getRef()); + + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidTypeValue.getErrorCode())); + } + + @Test + public void updateGeoLocationSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.LOCATION, "updated location"); + actorMessage.getRequest().put(JsonKey.TYPE, type); + actorMessage.getRequest().put(JsonKey.LOCATION_ID, id); + actorMessage.setOperation(ActorOperations.UPDATE_GEO_LOCATION.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void updateGeoLocationFailureWithNullId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.LOCATION, "updated location"); + actorMessage.getRequest().put(JsonKey.TYPE, type); + actorMessage.getRequest().put(JsonKey.LOCATION_ID, null); + actorMessage.setOperation(ActorOperations.UPDATE_GEO_LOCATION.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidRequestData.getErrorCode())); + } + + @Test + public void updateGeoLocationFailureWithInvalidId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.LOCATION, "updated location"); + actorMessage.getRequest().put(JsonKey.TYPE, type); + actorMessage.getRequest().put(JsonKey.LOCATION_ID, "invalId"); + actorMessage.setOperation(ActorOperations.UPDATE_GEO_LOCATION.getValue()); + + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getFailureResponse()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidLocationId.getErrorCode())); + } + + @Test + public void deleteGeoLocationSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.LOCATION_ID, id); + actorMessage.setOperation(ActorOperations.DELETE_GEO_LOCATION.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void deleteGeoLocationFailureWithNullId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.LOCATION_ID, null); + actorMessage.setOperation(ActorOperations.DELETE_GEO_LOCATION.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidRequestData.getErrorCode())); + } + + @Test + public void geoLocationFailureWithInvalidOperation() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.LOCATION_ID, null); + actorMessage.setOperation("invalid operation"); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidRequestData.getErrorCode())); + } + + @Test + public void getUserCountSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List list = new ArrayList<>(); + list.add("locId1"); + actorMessage.getRequest().put(JsonKey.LOCATION_IDS, list); + actorMessage.setOperation(ActorOperations.GET_USER_COUNT.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + + List> result = + (List>) res.getResult().get(JsonKey.LOCATIONS); + Map map = result.get(0); + int count = (int) map.get(JsonKey.USER_COUNT); + assertEquals(0, count); + } + + @Test + public void sendNotificationGeoLocationSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.LOCATION, "updated location"); + actorMessage.getRequest().put(JsonKey.TYPE, type); + actorMessage.getRequest().put(JsonKey.LOCATION_ID, id); + actorMessage.setOperation(ActorOperations.SEND_NOTIFICATION.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void sendNotificationGeoLocationFailure() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, userId); + actorMessage.getRequest().put(JsonKey.LOCATION, "updated location"); + actorMessage.getRequest().put(JsonKey.TYPE, type); + actorMessage.getRequest().put(JsonKey.LOCATION_ID, id); + actorMessage.setOperation(ActorOperations.SEND_NOTIFICATION.getValue()); + + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getFailureResponse()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("100 second"), ProjectCommonException.class); + assertTrue(exc.getCode().equals(ResponseCode.invalidTopic.getErrorCode())); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/notificationservice/dao/impl/EmailTemplateDaoImplTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/notificationservice/dao/impl/EmailTemplateDaoImplTest.java new file mode 100644 index 0000000000..e981660b7a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/notificationservice/dao/impl/EmailTemplateDaoImplTest.java @@ -0,0 +1,88 @@ +package org.sunbird.learner.actors.notificationservice.dao.impl; + +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang.StringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.notificationservice.dao.EmailTemplateDao; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CassandraOperationImpl.class, + ServiceFactory.class, + CassandraOperation.class, + CassandraUtil.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class EmailTemplateDaoImplTest { + private CassandraOperation cassandraOperation; + private static final String EMAIL_TEMPLATE = "email_template"; + private static final String DEFAULT_EMAIL_TEMPLATE_NAME = "default"; + private static final String TEMPLATE = "template"; + private EmailTemplateDao emailTemplateDao = new EmailTemplateDaoImpl(); + + @Before + public void setUp() throws Exception { + emailTemplateDao = new EmailTemplateDaoImpl(); + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + } + + @Test + public void testGetTemplateWithBlankTemplateName() { + List idList = new ArrayList<>(); + idList.add(DEFAULT_EMAIL_TEMPLATE_NAME); + Response response = new Response(); + List> orgList = new ArrayList<>(); + Map map = new HashMap<>(); + orgList.add(map); + response.put(JsonKey.RESPONSE, orgList); + when(cassandraOperation.getRecordsByPrimaryKeys( + JsonKey.SUNBIRD, EMAIL_TEMPLATE, idList, JsonKey.NAME)) + .thenReturn(response); + String resp = emailTemplateDao.getTemplate(StringUtils.EMPTY); + Assert.assertEquals(null, resp); + } + + @Test + public void testGetTemplateWithTemplateName() { + List idList = new ArrayList<>(); + idList.add("Sunbird_email_template"); + Response response = new Response(); + List> orgList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(TEMPLATE, "Course is Been completed"); + orgList.add(map); + response.put(JsonKey.RESPONSE, orgList); + when(cassandraOperation.getRecordsByPrimaryKeys( + JsonKey.SUNBIRD, EMAIL_TEMPLATE, idList, JsonKey.NAME)) + .thenReturn(response); + String resp = emailTemplateDao.getTemplate("Sunbird_email_template"); + Assert.assertEquals("Course is Been completed", resp); + } + + @Test + public void testGetInstance() { + Assert.assertEquals( + emailTemplateDao.getClass().getSimpleName(), + EmailTemplateDaoImpl.getInstance().getClass().getSimpleName()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/otp/OTPActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/otp/OTPActorTest.java new file mode 100644 index 0000000000..8034fb91ff --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/otp/OTPActorTest.java @@ -0,0 +1,379 @@ +package org.sunbird.learner.actors.otp; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.ClientErrorResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.ratelimit.dao.RateLimitDao; +import org.sunbird.ratelimit.dao.RateLimitDaoImpl; +import org.sunbird.ratelimit.limiter.OtpRateLimiter; +import org.sunbird.ratelimit.service.RateLimitService; +import org.sunbird.ratelimit.service.RateLimitServiceImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + CassandraOperationImpl.class, + RateLimitService.class, + RateLimitDaoImpl.class, + RateLimitDao.class, + RateLimitServiceImpl.class, + SunbirdMWService.class +}) +@PowerMockIgnore("javax.management.*") +public class OTPActorTest { + + private TestKit probe; + private ActorRef subject; + + private static final ActorSystem system = ActorSystem.create("system"); + private static final CassandraOperationImpl mockCassandraOperation = + mock(CassandraOperationImpl.class); + private static final Props props = Props.create(OTPActor.class); + private static final String PHONE_TYPE = "phone"; + private static final String EMAIL_TYPE = "email"; + private static final String PHONE_KEY = "0000000000"; + private static final String EMAIL_KEY = "someEmail@someDomain.anything"; + private static final String REQUEST_OTP = "000000"; + private static final String INVALID_OTP = "111111"; + private static final String USER_ID = "user123"; + + @BeforeClass + public static void before() { + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(mockCassandraOperation); + } + + @Before + public void beforeEachTestCase() { + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(mockCassandraOperation); + probe = new TestKit(system); + subject = system.actorOf(props); + PowerMockito.mockStatic(SunbirdMWService.class); + SunbirdMWService.tellToBGRouter(Mockito.any(), Mockito.any()); + } + + @Test + public void testVerifyOtpFailureWithInvalidPhoneOtp() { + Response mockedCassandraResponse = + getMockCassandraRecordByIdSuccessResponse(PHONE_KEY, PHONE_TYPE, INVALID_OTP); + verifyOtpFailureTest(true, mockedCassandraResponse); + } + + @Test + public void testVerifyOtpFailureWithInvalidEmailOtp() { + Response mockedCassandraResponse = + getMockCassandraRecordByIdSuccessResponse(EMAIL_KEY, EMAIL_TYPE, INVALID_OTP); + verifyOtpFailureTest(false, mockedCassandraResponse); + } + + @Test + public void testVerifyOtpFailureWithExpiredOtp() { + Response mockedCassandraResponse = getMockCassandraRecordByIdFailureResponse(); + verifyOtpFailureWithExpiredOtp(false, mockedCassandraResponse); + } + + @Test + public void testVerifyOtpSuccessWithPhoneOtp() { + Response mockedCassandraResponse = + getMockCassandraRecordByIdSuccessResponse(PHONE_KEY, PHONE_TYPE, REQUEST_OTP); + verifyOtpSuccessTest(true, mockedCassandraResponse); + } + + @Test + public void testVerifyOtpSuccessWithEmailOtp() { + Response mockedCassandraResponse = + getMockCassandraRecordByIdSuccessResponse(EMAIL_KEY, EMAIL_TYPE, REQUEST_OTP); + verifyOtpSuccessTest(false, mockedCassandraResponse); + } + + private Request createRequestForVerifyOtp(String key, String type) { + Request request = new Request(); + request.setOperation(ActorOperations.VERIFY_OTP.getValue()); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.TYPE, type); + innerMap.put(JsonKey.KEY, key); + innerMap.put(JsonKey.OTP, REQUEST_OTP); + request.setRequest(innerMap); + return request; + } + + private void verifyOtpSuccessTest(boolean isPhone, Response mockedCassandraResponse) { + Request request; + if (isPhone) { + request = createRequestForVerifyOtp(PHONE_KEY, PHONE_TYPE); + } else { + request = createRequestForVerifyOtp(EMAIL_KEY, EMAIL_TYPE); + } + when(mockCassandraOperation.getRecordWithTTLById( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyList())) + .thenReturn(mockedCassandraResponse); + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + private void verifyOtpFailureWithExpiredOtp(boolean isPhone, Response mockedCassandraResponse) { + Request request; + if (isPhone) { + request = createRequestForVerifyOtp(PHONE_KEY, PHONE_TYPE); + } else { + request = createRequestForVerifyOtp(EMAIL_KEY, EMAIL_TYPE); + } + when(mockCassandraOperation.getRecordWithTTLById( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyList())) + .thenReturn(mockedCassandraResponse); + subject.tell(request, probe.getRef()); + ProjectCommonException exception = + probe.expectMsgClass(duration("100 second"), ProjectCommonException.class); + Assert.assertTrue( + ((ProjectCommonException) exception) + .getCode() + .equals(ResponseCode.errorInvalidOTP.getErrorCode())); + } + + private void verifyOtpFailureTest(boolean isPhone, Response mockedCassandraResponse) { + Request request; + if (isPhone) { + request = createRequestForVerifyOtp(PHONE_KEY, PHONE_TYPE); + } else { + request = createRequestForVerifyOtp(EMAIL_KEY, EMAIL_TYPE); + } + when(mockCassandraOperation.getRecordWithTTLById( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyList())) + .thenReturn(mockedCassandraResponse); + subject.tell(request, probe.getRef()); + ClientErrorResponse errorResponse = + probe.expectMsgClass(duration("100 second"), ClientErrorResponse.class); + Assert.assertTrue( + (errorResponse.getResponseCode().name()).equals(ResponseCode.CLIENT_ERROR.name())); + } + + @Test + public void generateOtpForPhoneSuccess() { + Request request; + request = createGenerateOtpRequest(PHONE_TYPE, PHONE_KEY); + when(mockCassandraOperation.getRecordsByIdsWithSpecifiedColumnsAndTTL( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyMap())) + .thenReturn(getRateLimitRecords(5)); + + Response mockedCassandraResponse = getCassandraRecordByIdForUserResponse(); + when(mockCassandraOperation.getRecordWithTTLById( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyList())) + .thenReturn(mockedCassandraResponse); + when(mockCassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createCassandraInsertSuccessResponse()); + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + @Test + public void generateOtpForEmailSuccess() { + Request request; + request = createGenerateOtpRequest(EMAIL_TYPE, EMAIL_KEY); + when(mockCassandraOperation.getRecordsByIdsWithSpecifiedColumnsAndTTL( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyMap())) + .thenReturn(getRateLimitRecords(5)); + Response mockedCassandraResponse = getCassandraRecordByIdForUserResponse(); + when(mockCassandraOperation.getRecordWithTTLById( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyList())) + .thenReturn(mockedCassandraResponse); + when(mockCassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createCassandraInsertSuccessResponse()); + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + @Test + public void generateOtpForEmailSuccessForUser() { + Request request; + request = createOtpRequest(EMAIL_TYPE, EMAIL_KEY, USER_ID); + when(mockCassandraOperation.getRecordsByIdsWithSpecifiedColumnsAndTTL( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyMap())) + .thenReturn(getRateLimitRecords(5)); + Response mockedCassandraResponse = getCassandraRecordByIdForUserResponse(); + when(mockCassandraOperation.getRecordWithTTLById( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyList())) + .thenReturn(mockedCassandraResponse); + when(mockCassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(mockedCassandraResponse); + when(mockCassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createCassandraInsertSuccessResponse()); + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + @Test + public void generateOtpForInvalidType() { + Request request; + request = createGenerateOtpRequest("InvalidType", "InvalidType"); + when(mockCassandraOperation.getRecordsByIdsWithSpecifiedColumnsAndTTL( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyMap())) + .thenReturn(getRateLimitRecords(5)); + Response mockedCassandraResponse = getCassandraRecordByIdForUserResponse(); + when(mockCassandraOperation.getRecordWithTTLById( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyMap(), + Mockito.anyList(), + Mockito.anyList())) + .thenReturn(mockedCassandraResponse); + when(mockCassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createCassandraInsertSuccessResponse()); + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + private Response getRateLimitRecords(int count) { + Response response = new Response(); + List> results = new ArrayList<>(); + Map record = new HashMap<>(); + record.put(JsonKey.KEY, "9999888898"); + record.put(JsonKey.RATE_LIMIT_UNIT, OtpRateLimiter.HOUR.name()); + record.put(JsonKey.RATE, 10); + record.put(JsonKey.TTL, 3500); + record.put(JsonKey.COUNT, count); + results.add(record); + response.put(JsonKey.RESPONSE, results); + return response; + } + + private Response getCassandraRecordByIdForUserResponse() { + Response response = new Response(); + List> userList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.USER_ID, USER_ID); + map.put(JsonKey.CHANNEL, "anyChannel"); + map.put(JsonKey.EMAIL, EMAIL_KEY); + map.put(JsonKey.OTP, REQUEST_OTP); + userList.add(map); + response.put(JsonKey.RESPONSE, userList); + return response; + } + + private Response createCassandraInsertSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + private Request createGenerateOtpRequest(String type, String key) { + Request request = new Request(); + request.setOperation(ActorOperations.GENERATE_OTP.getValue()); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.TYPE, type); + innerMap.put(JsonKey.KEY, key); + request.setRequest(innerMap); + return request; + } + + private Request createOtpRequest(String type, String key, String userId) { + Request request = new Request(); + request.setOperation(ActorOperations.GENERATE_OTP.getValue()); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.TYPE, type); + innerMap.put(JsonKey.KEY, key); + innerMap.put(JsonKey.USER_ID, userId); + request.setRequest(innerMap); + return request; + } + + private Response getMockCassandraRecordByIdSuccessResponse(String key, String type, String otp) { + Response response = new Response(); + List> list = new ArrayList<>(); + Map otpResponse = new HashMap<>(); + otpResponse.put(JsonKey.OTP, otp); + otpResponse.put(JsonKey.TYPE, type); + otpResponse.put(JsonKey.KEY, key); + otpResponse.put(JsonKey.ATTEMPTED_COUNT, 0); + otpResponse.put("otp_ttl", 120); + list.add(otpResponse); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private Response getMockCassandraRecordByIdFailureResponse() { + Response response = new Response(); + List> list = new ArrayList<>(); + response.put(JsonKey.RESPONSE, list); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/otp/SendOTPActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/otp/SendOTPActorTest.java new file mode 100644 index 0000000000..51be380038 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/otp/SendOTPActorTest.java @@ -0,0 +1,134 @@ +package org.sunbird.learner.actors.otp; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.impl.DefaultDecryptionServiceImpl; +import org.sunbird.common.models.util.datasecurity.impl.DefaultEncryptionServivceImpl; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.notificationservice.dao.EmailTemplateDao; +import org.sunbird.learner.actors.notificationservice.dao.impl.EmailTemplateDaoImpl; +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.sms.providerimpl.Msg91SmsProviderFactory; +import org.sunbird.notification.utils.SMSFactory; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class, + CassandraOperationImpl.class, + CassandraOperation.class, + DefaultDecryptionServiceImpl.class, + DefaultEncryptionServivceImpl.class, + SMSFactory.class, + Msg91SmsProviderFactory.class, + EmailTemplateDaoImpl.class, + SunbirdMWService.class +}) +@PowerMockIgnore("javax.management.*") +@SuppressStaticInitializationFor({ + "org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class", + "org.sunbird.common.models.util.datasecurity.impl.DefaultDecryptionServiceImpl", + "org.sunbird.common.models.util.datasecurity.impl.DefaultEncryptionServivceImpl" +}) +public class SendOTPActorTest { + private TestKit probe; + private ActorRef subject; + + public static DefaultEncryptionServivceImpl encService; + public static DefaultDecryptionServiceImpl decService; + public static org.sunbird.common.models.util.datasecurity.impl.ServiceFactory dataServiceFactory; + private static final ActorSystem system = ActorSystem.create("system"); + public static final CassandraOperationImpl mockCassandraOperation = + mock(CassandraOperationImpl.class); + public static final ISmsProvider iSmsProvider = mock(ISmsProvider.class); + public static final EmailTemplateDao emailTemplateDao = mock(EmailTemplateDao.class); + private static final Props props = Props.create(SendOTPActor.class); + private Request request; + + @Before + public void beforeEachTestCase() throws Exception { + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(SMSFactory.class); + PowerMockito.mockStatic(EmailTemplateDaoImpl.class); + when(ServiceFactory.getInstance()).thenReturn(mockCassandraOperation); + when(SMSFactory.getInstance(Mockito.anyString())).thenReturn(iSmsProvider); + when(EmailTemplateDaoImpl.getInstance()).thenReturn(emailTemplateDao); + PowerMockito.mockStatic(DefaultDecryptionServiceImpl.class); + PowerMockito.mockStatic(DefaultEncryptionServivceImpl.class); + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + DefaultDecryptionServiceImpl decryptionService = + Mockito.mock(DefaultDecryptionServiceImpl.class); + PowerMockito.whenNew(DefaultDecryptionServiceImpl.class) + .withNoArguments() + .thenReturn(decryptionService); + when(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getDecryptionServiceInstance(null)) + .thenReturn(decryptionService); + probe = new TestKit(system); + subject = system.actorOf(props); + /* when(OTPUtil.getOTPExpirationInMinutes()).thenReturn("123456788");*/ + + } + + @Test + public void sendOTPTestForMobile() throws Exception { + request = createOtpRequest("phone", "anyMobileNum", "anyUserId"); + when(emailTemplateDao.getTemplate(Mockito.anyString())) + .thenReturn( + "OTP to reset your password on $installationName is $otp. This is valid for $otpExpiryInMinutes minutes only."); + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("30 second"), Response.class); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + @Test + public void sendOTPTestForEmail() throws Exception { + PowerMockito.mockStatic(SunbirdMWService.class); + request = createOtpRequest("email", "anyEmailId", "anyUserId"); + when(emailTemplateDao.getTemplate(Mockito.anyString())) + .thenReturn( + "OTP to reset your password on $installationName is $otp. This is valid for $otpExpiryInMinutes minutes only."); + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("30 second"), Response.class); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + private Request createOtpRequest(String type, String key, String userId) { + Request request = new Request(); + request.setOperation(ActorOperations.SEND_OTP.getValue()); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.TYPE, type); + innerMap.put(JsonKey.KEY, key); + innerMap.put(JsonKey.OTP, "000000"); + innerMap.put(JsonKey.USER_ID, userId); + innerMap.put(JsonKey.TEMPLATE_ID, "anyTemplatedId"); + request.setRequest(innerMap); + return request; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/role/dao/impl/RoleDaoImplTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/role/dao/impl/RoleDaoImplTest.java new file mode 100644 index 0000000000..580a1e5f41 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/role/dao/impl/RoleDaoImplTest.java @@ -0,0 +1,66 @@ +package org.sunbird.learner.actors.role.dao.impl; + +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.role.dao.RoleDao; +import org.sunbird.learner.util.Util; +import org.sunbird.models.role.Role; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CassandraOperationImpl.class, + ServiceFactory.class, + CassandraOperation.class, + CassandraUtil.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class RoleDaoImplTest { + private static final String TABLE_NAME = "role"; + private CassandraOperation cassandraOperation; + private Response response; + private RoleDao roleDao; + + @Before + public void setUp() throws Exception { + response = new Response(); + roleDao = new RoleDaoImpl(); + List> roleList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "TEACHER"); + roleList.add(map); + response.put(JsonKey.RESPONSE, roleList); + } + + @Test + public void testGetRoles() { + try { + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.getAllRecords(Util.KEY_SPACE_NAME, TABLE_NAME)).thenReturn(response); + List roleList = roleDao.getRoles(); + Assert.assertEquals("TEACHER", roleList.get(0).getName()); + + } catch (Exception e) { + Assert.assertTrue(false); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/role/group/dao/impl/RoleGroupDaoImplTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/role/group/dao/impl/RoleGroupDaoImplTest.java new file mode 100644 index 0000000000..7b892bd763 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/role/group/dao/impl/RoleGroupDaoImplTest.java @@ -0,0 +1,67 @@ +package org.sunbird.learner.actors.role.group.dao.impl; + +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.role.group.dao.RoleGroupDao; +import org.sunbird.learner.util.Util; +import org.sunbird.models.role.group.RoleGroup; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CassandraOperationImpl.class, + ServiceFactory.class, + CassandraOperation.class, + CassandraUtil.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class RoleGroupDaoImplTest { + private static final String TABLE_NAME = "role_group"; + private CassandraOperation cassandraOperation; + private Response response; + private RoleGroupDao roleGroupDao; + + @Before + public void setUp() throws Exception { + response = new Response(); + roleGroupDao = new RoleGroupDaoImpl(); + List> roleList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "Flag Reviewer"); + roleList.add(map); + response.put(JsonKey.RESPONSE, roleList); + } + + @Test + public void testGetRoles() { + try { + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.getAllRecords(Util.KEY_SPACE_NAME, TABLE_NAME)).thenReturn(response); + List roleGroups = roleGroupDao.getRoleGroups(); + Assert.assertEquals("Flag Reviewer", roleGroups.get(0).getName()); + + } catch (Exception e) { + e.printStackTrace(); + Assert.assertTrue(false); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/skill/UserSkillManagementActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/skill/UserSkillManagementActorTest.java new file mode 100644 index 0000000000..41fb552b20 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/skill/UserSkillManagementActorTest.java @@ -0,0 +1,465 @@ +package org.sunbird.learner.actors.skill; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import scala.concurrent.Promise; +import scala.concurrent.duration.FiniteDuration; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + EsClientFactory.class, + ElasticSearchHelper.class, + ElasticSearchRestHighImpl.class +}) +@PowerMockIgnore("javax.management.*") +public class UserSkillManagementActorTest { + + private static ActorSystem system; + private static final Props props = Props.create(UserSkillManagementActor.class); + private CassandraOperation cassandraOperation; + private static final String USER_ID = "userId"; + private static final String ROOT_ORG_ID = "someRootOrgId"; + private static final String ENDORSED_USER_ID = "someEndorsedUserId"; + private static final String ENDORSED_SKILL_NAME = "someEndorsedSkillName"; + private FiniteDuration duration = duration("10 second"); + private ElasticSearchService esService; + + @Before + public void beforeEachTest() { + system = ActorSystem.create("system"); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + } + + @Test + public void testAddSkillSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Response insertResponse = createCassandraSuccessResponse(); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createGetUserSuccessResponse()); + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetSkillsSuccessResponse()); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(insertResponse); + mockCassandraRequestForGetUser(false); + subject.tell( + createAddSkillRequest(USER_ID, ENDORSED_USER_ID, Arrays.asList(ENDORSED_SKILL_NAME)), + probe.getRef()); + Response response = probe.expectMsgClass(duration, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testAddSkillFailureWithInvalidUserId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + mockCassandraRequestForGetUser(true); + subject.tell( + createAddSkillRequest(USER_ID, ENDORSED_USER_ID, Collections.emptyList()), probe.getRef()); + + ProjectCommonException exception = probe.expectMsgClass(duration, ProjectCommonException.class); + Assert.assertTrue( + null != exception + && exception.getResponseCode() == ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + @Test + public void testUpdateSkillSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request actorMessage = createUpdateSkillRequest(USER_ID, Collections.emptyList()); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetUserSuccessResponse()); + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetSkillsSuccessResponse()); + + mockGetSkillResponse(ENDORSED_USER_ID); + subject.tell(actorMessage, probe.getRef()); + Response response = probe.expectMsgClass(duration, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testUpdateUserSkillSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request actorMessage = createUpdateSkillRequest(USER_ID, Arrays.asList(ENDORSED_SKILL_NAME)); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetUserSuccessResponse()); + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetSkillsSuccessResponse()); + + mockGetSkillEmptyResponse(ENDORSED_USER_ID); + subject.tell(actorMessage, probe.getRef()); + Response response = probe.expectMsgClass(duration, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testUpdateSkillFailureWithInvalidUserId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = createUpdateSkillRequest(USER_ID, Collections.emptyList()); + mockCassandraRequestForGetUser(true); + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exception = probe.expectMsgClass(duration, ProjectCommonException.class); + Assert.assertTrue( + null != exception + && exception.getResponseCode() == ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + @Test + public void testGetSkillSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + mockGetSkillResponse(USER_ID); + subject.tell(createGetSkillRequest(USER_ID, ENDORSED_USER_ID), probe.getRef()); + Response response = probe.expectMsgClass(duration, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testGetSkillWithEmptyEndorsedUserId() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + mockGetSkillResponse(USER_ID); + subject.tell(createGetSkillRequest(USER_ID, null), probe.getRef()); + ProjectCommonException ex = probe.expectMsgClass(duration, ProjectCommonException.class); + Assert.assertTrue(null != ex); + } + + @Ignore + public void testGetSkillFailureWithInvalidUserId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(createGetSkillRequest(USER_ID, ENDORSED_USER_ID), probe.getRef()); + ProjectCommonException exception = probe.expectMsgClass(duration, ProjectCommonException.class); + Assert.assertTrue( + null != exception + && exception.getResponseCode() == ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + @Test + public void testGetAllSkillsSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetSkillsSuccessResponse()); + Request actorMessage = new Request(); + actorMessage.setOperation(ActorOperations.GET_SKILLS_LIST.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response response = probe.expectMsgClass(duration, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testGetSkillsFailureWithInvalidOperationName() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + actorMessage.setOperation(ActorOperations.GET_SKILLS_LIST.getValue() + "INVALID"); + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exception = probe.expectMsgClass(duration, ProjectCommonException.class); + Assert.assertTrue(null != exception); + } + + @Test + public void testAddSkillEndorsementFailureWithInvalidEndorsedUserId() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + mockCassandraRequestForGetUser(true); + subject.tell( + createSkillEndorsementRequest(USER_ID, ENDORSED_USER_ID, ENDORSED_SKILL_NAME), + probe.getRef()); + ProjectCommonException result = probe.expectMsgClass(duration, ProjectCommonException.class); + Assert.assertTrue( + null != result && result.getResponseCode() == ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + @Test + public void testAddSkillEndorsementFailureWithInvalidUserId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + mockCassandraRequestForGetUser(true); + subject.tell( + createSkillEndorsementRequest(USER_ID, ENDORSED_USER_ID, ENDORSED_SKILL_NAME), + probe.getRef()); + ProjectCommonException exception = probe.expectMsgClass(duration, ProjectCommonException.class); + Assert.assertTrue( + null != exception + && exception.getResponseCode() == ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + @Test + @Ignore + public void testAddSkillEndorsementSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createSkillEndorsementResponse()); + + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(endorsementSkillResponse()); + subject.tell( + createSkillEndorsementRequest(USER_ID, ENDORSED_USER_ID, ENDORSED_SKILL_NAME), + probe.getRef()); + Response response = probe.expectMsgClass(duration, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + private Request createAddSkillRequest( + String userId, String endorseUserId, List skillsList) { + + Request actorMessage = new Request(); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUESTED_BY, userId); + actorMessage.setContext(innerMap); + actorMessage.put(JsonKey.ENDORSED_USER_ID, endorseUserId); + actorMessage.put(JsonKey.SKILL_NAME, skillsList); + actorMessage.setOperation(ActorOperations.ADD_SKILL.getValue()); + + return actorMessage; + } + + private Request createUpdateSkillRequest(String userid, List skills) { + Request actorMessage = new Request(); + actorMessage.put(JsonKey.USER_ID, userid); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUESTED_BY, userid); + actorMessage.setContext(innerMap); + actorMessage.put(JsonKey.SKILLS, skills); + actorMessage.setOperation(ActorOperations.UPDATE_SKILL.getValue()); + + return actorMessage; + } + + private Request createGetSkillRequest(String userId, String endorseUserId) { + Request actorMessage = new Request(); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUESTED_BY, userId); + actorMessage.setContext(innerMap); + actorMessage.put(JsonKey.ENDORSED_USER_ID, endorseUserId); + actorMessage.setOperation(ActorOperations.GET_SKILL.getValue()); + return actorMessage; + } + + private Request createSkillEndorsementRequest( + String userId, String endorsedUserId, String skillName) { + Request actorMessage = new Request(); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUESTED_BY, userId); + actorMessage.setContext(innerMap); + actorMessage.put(JsonKey.SKILL_NAME, skillName); + actorMessage.put(JsonKey.ENDORSED_USER_ID, endorsedUserId); + actorMessage.put(JsonKey.USER_ID, userId); + actorMessage.setOperation(ActorOperations.ADD_USER_SKILL_ENDORSEMENT.getValue()); + return actorMessage; + } + + private Map createGetSkillResponse() { + HashMap response = new HashMap<>(); + List> content = new ArrayList<>(); + List> skillList = new ArrayList<>(); + HashMap skillMap = new HashMap<>(); + skillMap.put(JsonKey.SKILL_NAME, "some-skill"); + skillList.add(skillMap); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.SKILLS, skillList); + content.add(innerMap); + response.put(JsonKey.CONTENT, content); + return response; + } + + private Map createGetSkillEmptyContentResponse() { + HashMap response = new HashMap<>(); + List> content = new ArrayList<>(); + List> skillList = new ArrayList<>(); + HashMap skillMap = new HashMap<>(); + skillMap.put(JsonKey.SKILL_NAME, "some-skill"); + skillList.add(skillMap); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.SKILLS, skillList); + response.put(JsonKey.CONTENT, content); + return response; + } + + private Response createGetSkillsSuccessResponse() { + Response response = new Response(); + Map userMap = new HashMap<>(); + List> result = new ArrayList<>(); + result.add(userMap); + response.put(JsonKey.RESPONSE, result); + return response; + } + + private Response createSkillEndorsementResponse() { + Response response = new Response(); + List> result = new ArrayList<>(); + Map skill = new HashMap<>(); + skill.put(JsonKey.SKILL_NAME, ENDORSED_SKILL_NAME); + skill.put(JsonKey.SKILL_NAME_TO_LOWERCASE, ENDORSED_SKILL_NAME); + skill.put(JsonKey.ENDORSERS_LIST, new ArrayList<>()); + result.add(skill); + response.put(JsonKey.RESPONSE, result); + return response; + } + + private Response createCassandraSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + private Response createGetUserSuccessResponse() { + Response response = new Response(); + Map userMap = new HashMap<>(); + userMap.put(JsonKey.ID, USER_ID); + userMap.put(JsonKey.ROOT_ORG_ID, ROOT_ORG_ID); + userMap.put(JsonKey.ENDORSERS_LIST, new ArrayList<>()); + userMap.put(JsonKey.ENDORSEMENT_COUNT, 2); + List> result = new ArrayList<>(); + result.add(userMap); + response.put(JsonKey.RESPONSE, result); + return response; + } + + private Response createGetUserFailureResponse() { + Response response = new Response(); + List> result = new ArrayList<>(); + response.put(JsonKey.RESPONSE, result); + return response; + } + + private void mockGetSkillResponse(String userId) { + Map esDtoMap = new HashMap<>(); + Map filters = new HashMap<>(); + filters.put(JsonKey.USER_ID, userId); + esDtoMap.put(JsonKey.FILTERS, filters); + List fields = new ArrayList<>(); + fields.add(JsonKey.SKILLS); + esDtoMap.put(JsonKey.FIELDS, fields); + Promise> promise = Futures.promise(); + promise.success(createGetSkillResponse()); + when(esService.search( + Mockito.eq(ElasticSearchHelper.createSearchDTO(esDtoMap)), + Mockito.eq(ProjectUtil.EsType.user.getTypeName()))) + .thenReturn(promise.future()); + Promise> promise_esDtoMap = Futures.promise(); + promise_esDtoMap.success(esDtoMap); + + when(esService.getDataByIdentifier( + Mockito.eq(ProjectUtil.EsType.user.getTypeName()), Mockito.eq(userId))) + .thenReturn(promise_esDtoMap.future()); + when(ElasticSearchHelper.getResponseFromFuture(promise_esDtoMap.future())).thenReturn(esDtoMap); + when(ElasticSearchHelper.getResponseFromFuture(promise.future())) + .thenReturn(createGetSkillResponse()); + } + + private void mockGetSkillEmptyResponse(String userId) { + Map esDtoMap = new HashMap<>(); + Map filters = new HashMap<>(); + filters.put(JsonKey.USER_ID, userId); + esDtoMap.put(JsonKey.FILTERS, filters); + List fields = new ArrayList<>(); + fields.add(JsonKey.SKILLS); + esDtoMap.put(JsonKey.FIELDS, fields); + Promise> promise = Futures.promise(); + promise.success(createGetSkillResponse()); + when(esService.search( + Mockito.eq(ElasticSearchHelper.createSearchDTO(esDtoMap)), + Mockito.eq(ProjectUtil.EsType.user.getTypeName()))) + .thenReturn(promise.future()); + Promise> promise_esDtoMap = Futures.promise(); + promise_esDtoMap.success(esDtoMap); + when(esService.getDataByIdentifier( + Mockito.eq(ProjectUtil.EsType.user.getTypeName()), Mockito.eq(userId))) + .thenReturn(promise_esDtoMap.future()); + when(ElasticSearchHelper.getResponseFromFuture(promise_esDtoMap.future())).thenReturn(esDtoMap); + when(ElasticSearchHelper.getResponseFromFuture(promise.future())) + .thenReturn(createGetSkillEmptyContentResponse()); + } + + private Response endorsementSkillResponse() { + Response response = new Response(); + List> result = new ArrayList<>(); + response.put(JsonKey.RESPONSE, result); + return response; + } + + private void mockCassandraRequestForGetUser(boolean isFailure) { + if (isFailure) + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetUserFailureResponse()); + else + when(cassandraOperation.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(createGetUserSuccessResponse()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/tenantpreference/TenantPreferenceManagementActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/tenantpreference/TenantPreferenceManagementActorTest.java new file mode 100644 index 0000000000..355d1c7397 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/tenantpreference/TenantPreferenceManagementActorTest.java @@ -0,0 +1,362 @@ +package org.sunbird.learner.actors.tenantpreference; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actor.service.BaseMWService; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; + +// import org.sunbird.user.dao.impl.UserOrgDaoImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + BaseMWService.class, + RequestRouter.class, + InterServiceCommunicationFactory.class, + ElasticSearchHelper.class, + Util.class, + // UserOrgDaoImpl.class, + DecryptionService.class, + DataCacheHandler.class, +}) +@PowerMockIgnore({"javax.management.*"}) +public class TenantPreferenceManagementActorTest { + + private ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(TenantPreferenceManagementActor.class); + private static CassandraOperationImpl cassandraOperation; + private static final String orgId = "hhjcjr79fw4p89"; + private static final String USER_ID = "vcurc633r8911"; + + @BeforeClass + public static void beforeClass() { + + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + } + + @Before + public void beforeEachTest() { + + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + + when(cassandraOperation.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(cassandraGetRecordByProperty()); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createCassandraInsertSuccessResponse()); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(createCassandraInsertSuccessResponse()); + } + + private Response createCassandraInsertSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + @Test + public void testCreateSuccessWithTenantPreferenceAlreadyExists() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + Map map = new HashMap<>(); + map.put(JsonKey.KEY, "anyKey"); + reqList.add(map); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.CREATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testCreateSuccessWithTenantPreferenceDoesNotExists() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + Map map = new HashMap<>(); + map.put(JsonKey.KEY, "differentKey"); + reqList.add(map); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.CREATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testCreateTanentPreferenceFailureWithInvalidOrgId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + Map map = new HashMap<>(); + map.put(JsonKey.ROLE, "admin"); + reqList.add(map); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, ""); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.CREATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testCreateTanentPreferenceWithInvalidReqData() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.CREATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testUpdateTanentPreferenceSuccessWithoutKeyValue() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + Map map = new HashMap<>(); + map.put(JsonKey.ROLE, "admin"); + reqList.add(map); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.UPDATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testUpdateTanentPreferenceSuccessWithSameKey() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + Map map = new HashMap<>(); + map.put(JsonKey.KEY, "anyKey"); + map.put(JsonKey.DATA, "anyData"); + reqList.add(map); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.UPDATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testUpdateTanentPreferenceSuccessWithDifferentKey() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + Map map = new HashMap<>(); + map.put(JsonKey.KEY, "differentKey"); + map.put(JsonKey.DATA, "anyData"); + reqList.add(map); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.UPDATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res.get(JsonKey.RESPONSE)); + } + + @Test + public void testUpdateTanentPreferenceFailureWithInvalidRequestData() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.UPDATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testUpdateTanentPreferenceFailureWithInvalidOrgId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + List> reqList = new ArrayList<>(); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, reqList); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, ""); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.UPDATE_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testGetTanentPreferenceSuccessWithoutKey() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.GET_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res); + } + + @Test + public void testGetTanentPreferenceSuccessWithKeysDiff() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.KEYS, Arrays.asList("anyKey")); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.GET_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res); + } + + @Test + public void testGetTanentPreferenceWithInvalidOrgId() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, ""); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation(ActorOperations.GET_TENANT_PREFERENCE.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + @Test + public void testWithInvalidOperationType() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + Map map = new HashMap<>(); + map.put(JsonKey.TERM_AND_CONDITION_STATUS, "ACCEPTED"); + + actorMessage.getRequest().put(JsonKey.TENANT_PREFERENCE, map); + actorMessage.getRequest().put(JsonKey.ROOT_ORG_ID, orgId); + actorMessage.getRequest().put(JsonKey.REQUESTED_BY, USER_ID); + actorMessage.setOperation("InvalidOperation"); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exc = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(null != exc); + } + + private static Response cassandraGetRecordByProperty() { + Response response = new Response(); + List list = new ArrayList(); + Map map = new HashMap<>(); + map.put(JsonKey.KEY, "anyKey"); + list.add(map); + response.put(JsonKey.RESPONSE, list); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/user/service/UserServiceTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/user/service/UserServiceTest.java new file mode 100644 index 0000000000..0f3691080c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/actors/user/service/UserServiceTest.java @@ -0,0 +1,134 @@ +package org.sunbird.learner.actors.user.service; + +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CassandraOperationImpl.class, + ServiceFactory.class, + CassandraOperation.class, + CassandraUtil.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class, + EncryptionService.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class UserServiceTest { + + private CassandraOperation cassandraOperation; + private EncryptionService encryptionService; + private UserService userService = new UserService(); + private Util.DbInfo userDb = Util.dbInfoMap.get(JsonKey.USER_DB); + + @Before + public void setUp() { + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + PowerMockito.mockStatic(ServiceFactory.class); + encryptionService = PowerMockito.mock(EncryptionService.class); + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null)) + .thenReturn(encryptionService); + } + + @Test(expected = Test.None.class) + public void testCheckKeyUniquenessWhenKeyBlank() { + try { + when(cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), "", "")) + .thenReturn(new Response()); + userService.checkKeyUniqueness("", "", false); + } catch (Exception e) { + Assert.assertTrue(false); + } + } + + @Test() + public void testCheckKeyUniquenessWhenKeyValueIsUnique() { + try { + Response response = new Response(); + List> userMapList = new ArrayList<>(); + response.put(JsonKey.RESPONSE, userMapList); + when(cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), "key", "value")) + .thenReturn(response); + userService.checkKeyUniqueness("key", "value", false); + } catch (Exception e) { + Assert.assertTrue(false); + } + } + + @Test() + public void testCheckKeyUniquenessWhenEmailValueIsNotUnique() { + try { + Response response = new Response(); + List> userMapList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "NAME"); + userMapList.add(map); + response.put(JsonKey.RESPONSE, userMapList); + when(cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), "email", "valueNotUnique")) + .thenReturn(response); + userService.checkKeyUniqueness("email", "valueNotUnique", false); + } catch (Exception e) { + Assert.assertEquals("Email already exists.", e.getMessage()); + } + } + + @Test() + public void testCheckKeyUniquenessWhenPhoneValueIsNotUnique() { + try { + Response response = new Response(); + List> userMapList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "NAME"); + userMapList.add(map); + response.put(JsonKey.RESPONSE, userMapList); + when(cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), "phone", "valueNotUnique")) + .thenReturn(response); + userService.checkKeyUniqueness("phone", "valueNotUnique", false); + } catch (Exception e) { + Assert.assertEquals( + "Phone already in use. Please provide different phone number.", e.getMessage()); + } + } + + @Test() + public void testCheckKeyUniquenessWhenPhoneValueIsUnique() { + try { + Response response = new Response(); + List> userMapList = new ArrayList<>(); + response.put(JsonKey.RESPONSE, userMapList); + when(encryptionService.encryptData("valueUnique")).thenReturn("valueUnique"); + when(cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), "phone", "valueUnique")) + .thenReturn(response); + userService.checkKeyUniqueness("phone", "valueUnique", true); + } catch (Exception e) { + Assert.assertTrue(false); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/organisation/external/identity/service/OrgExternalServiceTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/organisation/external/identity/service/OrgExternalServiceTest.java new file mode 100644 index 0000000000..99a18e4920 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/organisation/external/identity/service/OrgExternalServiceTest.java @@ -0,0 +1,93 @@ +package org.sunbird.learner.organisation.external.identity.service; + +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CassandraOperationImpl.class, + ServiceFactory.class, + CassandraOperation.class, + CassandraUtil.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class OrgExternalServiceTest { + + private CassandraOperation cassandraOperation; + private final String ORG_EXTERNAL_IDENTITY = "org_external_identity"; + private OrgExternalService orgExternalService; + + @Before + public void setUp() { + orgExternalService = new OrgExternalService(); + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + } + + @Test + public void testGetOrgIdFromOrgExtIdFailure() { + try { + + Map dbRequestMap = new HashMap<>(); + dbRequestMap.put(JsonKey.EXTERNAL_ID, "anyorgextid"); + dbRequestMap.put(JsonKey.PROVIDER, "anyprovider"); + Response response = new Response(); + List> orgList = new ArrayList<>(); + Map map = new HashMap<>(); + orgList.add(map); + response.put(JsonKey.RESPONSE, orgList); + when(cassandraOperation.getRecordsByCompositeKey( + Util.KEY_SPACE_NAME, ORG_EXTERNAL_IDENTITY, dbRequestMap)) + .thenReturn(response); + String resp = + orgExternalService.getOrgIdFromOrgExternalIdAndProvider("anyOrgExtid", "anyprovider"); + Assert.assertEquals(null, resp); + + } catch (Exception e) { + Assert.assertTrue(false); + } + } + + @Test + public void testGetOrgIdFromOrgExtIdSuccess() { + try { + Map dbRequestMap = new HashMap<>(); + dbRequestMap.put(JsonKey.EXTERNAL_ID, "orgextid"); + dbRequestMap.put(JsonKey.PROVIDER, "provider"); + Response response = new Response(); + List> orgList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ORG_ID, "anyOrgId"); + orgList.add(map); + response.put(JsonKey.RESPONSE, orgList); + when(cassandraOperation.getRecordsByCompositeKey( + Util.KEY_SPACE_NAME, ORG_EXTERNAL_IDENTITY, dbRequestMap)) + .thenReturn(response); + String resp = orgExternalService.getOrgIdFromOrgExternalIdAndProvider("OrgExtid", "provider"); + Assert.assertEquals("anyOrgId", resp); + + } catch (Exception e) { + Assert.assertTrue(false); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/AdminUtilHandlerTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/AdminUtilHandlerTest.java new file mode 100644 index 0000000000..0b15245929 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/AdminUtilHandlerTest.java @@ -0,0 +1,62 @@ +package org.sunbird.learner.util; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.models.adminutil.AdminUtilRequestData; +import org.sunbird.models.adminutil.AdminUtilRequestPayload; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.validator.user.UserBulkMigrationRequestValidator; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({HttpUtil.class, AdminUtilHandlerTest.class}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class AdminUtilHandlerTest { + + @Before + public void setUp() throws Exception { + PowerMockito.mockStatic(HttpUtil.class); + } + + @Test + public void testPrepareAdminUtilPayload(){ + List reqData = new ArrayList(); + reqData.add(new AdminUtilRequestData("parentId", "childId1")); + reqData.add(new AdminUtilRequestData("parentId", "childId2")); + AdminUtilRequestPayload payload = AdminUtilHandler.prepareAdminUtilPayload(reqData); + assertEquals(2,payload.getRequest().getData().size()); + } + + @Test + public void testFetchEncryptedToken() throws IOException { + List reqData = new ArrayList(); + reqData.add(new AdminUtilRequestData("parentId", "childId1")); + reqData.add(new AdminUtilRequestData("parentId", "childId2")); + + when(HttpUtil.sendPostRequest(Mockito.anyString(),Mockito.anyString(),Mockito.anyObject())).thenReturn("{\"id\": \"ekstep.api.am.adminutil.sign.payload\",\"ver\": \"1.0\",\"ets\":1591589862198,\"params\": {\"status\": \"successful\",\"err\": null,\"errmsg\": null,\"msgid\": \"\",\"resmsgid\": \"328749cb-45e3-4b26-aea6-b7f4b97d548b\"}, \"result\": {\"data\": [{\"parentId\": \"parentId\", \"sub\":\"childId1\",\"token\":\"encryptedtoken1\"},{\"parentId\": \"parentId\",\"sub\": \"childId2\",\"token\":\"encryptedtoken2\"}]}}"); + Map encryptedTokenList = AdminUtilHandler.fetchEncryptedToken(AdminUtilHandler.prepareAdminUtilPayload(reqData)); + + ArrayList> data = (ArrayList>) encryptedTokenList.get(JsonKey.DATA); + for (Object object : data) { + Map tempMap = (Map) object; + assertNotNull(tempMap.get(JsonKey.TOKEN)); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserFlagEnumTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserFlagEnumTest.java new file mode 100644 index 0000000000..36734f52b7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserFlagEnumTest.java @@ -0,0 +1,24 @@ +package org.sunbird.learner.util; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class UserFlagEnumTest { + + @Test + public void testUserFlagEnumPhoneValue() { + Assert.assertEquals(1, UserFlagEnum.PHONE_VERIFIED.getUserFlagValue()); + Assert.assertEquals(2, UserFlagEnum.EMAIL_VERIFIED.getUserFlagValue()); + Assert.assertEquals(4, UserFlagEnum.STATE_VALIDATED.getUserFlagValue()); + } + + @Test + public void testUserFlagEnumPhoneType() { + Assert.assertEquals("phoneVerified", UserFlagEnum.PHONE_VERIFIED.getUserFlagType()); + Assert.assertEquals("emailVerified", UserFlagEnum.EMAIL_VERIFIED.getUserFlagType()); + Assert.assertEquals("stateValidated", UserFlagEnum.STATE_VALIDATED.getUserFlagType()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserFlagUtilTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserFlagUtilTest.java new file mode 100644 index 0000000000..5fb322635c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserFlagUtilTest.java @@ -0,0 +1,32 @@ +package org.sunbird.learner.util; + +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.models.util.JsonKey; + +@RunWith(PowerMockRunner.class) +public class UserFlagUtilTest { + + @Test + public void testGetFlagValue() { + Assert.assertEquals( + 2, UserFlagUtil.getFlagValue(UserFlagEnum.EMAIL_VERIFIED.getUserFlagType(), true)); + Assert.assertEquals( + 1, UserFlagUtil.getFlagValue(UserFlagEnum.PHONE_VERIFIED.getUserFlagType(), true)); + Assert.assertEquals( + 4, UserFlagUtil.getFlagValue(UserFlagEnum.STATE_VALIDATED.getUserFlagType(), true)); + } + + @Test + public void testAssignUserFlagValues() { + Map userFlagMap = UserFlagUtil.assignUserFlagValues(1); + Assert.assertEquals(true, userFlagMap.get(JsonKey.PHONE_VERIFIED)); + userFlagMap = UserFlagUtil.assignUserFlagValues(2); + Assert.assertEquals(true, userFlagMap.get(JsonKey.EMAIL_VERIFIED)); + userFlagMap = UserFlagUtil.assignUserFlagValues(4); + Assert.assertEquals(true, userFlagMap.get(JsonKey.STATE_VALIDATED)); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserUtilityTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserUtilityTest.java new file mode 100644 index 0000000000..f8b0c69800 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/learner/util/UserUtilityTest.java @@ -0,0 +1,103 @@ +package org.sunbird.learner.util; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.sunbird.common.models.util.JsonKey; + +public class UserUtilityTest { + + @Test + public void encryptSpecificUserDataSuccess() { + String email = "test@test.com"; + String userName = "test_user"; + String city = "Bangalore"; + String addressLine1 = "xyz"; + Map userMap = new HashMap(); + userMap.put(JsonKey.FIRST_NAME, "test user"); + userMap.put(JsonKey.EMAIL, email); + userMap.put(JsonKey.USER_NAME, userName); + List> addressList = new ArrayList>(); + Map address = new HashMap(); + address.put(JsonKey.COUNTRY, "India"); + address.put(JsonKey.CITY, city); + address.put(JsonKey.ADDRESS_LINE1, addressLine1); + addressList.add(address); + userMap.put(JsonKey.ADDRESS, addressList); + Map response = null; + try { + response = UserUtility.encryptUserData(userMap); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + assertEquals(userMap.get(JsonKey.FIRST_NAME), response.get(JsonKey.FIRST_NAME)); + assertNotEquals(email, response.get(JsonKey.EMAIL)); + assertNotEquals( + "India", + ((List>) response.get(JsonKey.ADDRESS)).get(0).get(JsonKey.COUNTRY)); + assertNotEquals( + addressLine1, + ((List>) response.get(JsonKey.ADDRESS)) + .get(0) + .get(JsonKey.ADDRESS_LINE1)); + } + + @Test + public void encryptUserAddressDataSuccess() { + String city = "Bangalore"; + String addressLine1 = "xyz"; + String state = "Karnataka"; + List> addressList = new ArrayList>(); + Map address = new HashMap(); + address.put(JsonKey.COUNTRY, "India"); + address.put(JsonKey.CITY, city); + address.put(JsonKey.ADDRESS_LINE1, addressLine1); + address.put(JsonKey.STATE, state); + addressList.add(address); + List> response = null; + try { + response = UserUtility.encryptUserAddressData(addressList); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + assertNotEquals("India", response.get(0).get(JsonKey.COUNTRY)); + assertNotEquals(addressLine1, response.get(0).get(JsonKey.ADDRESS_LINE1)); + assertNotEquals(state, response.get(0).get(JsonKey.STATE)); + } + + @Test + public void decryptUserDataSuccess() { + String email = "test@test.com"; + String userName = "test_user"; + String city = "Bangalore"; + String addressLine1 = "xyz"; + Map userMap = new HashMap(); + userMap.put(JsonKey.FIRST_NAME, "test user"); + userMap.put(JsonKey.EMAIL, email); + userMap.put(JsonKey.USER_NAME, userName); + List> addressList = new ArrayList>(); + Map address = new HashMap(); + address.put(JsonKey.COUNTRY, "India"); + address.put(JsonKey.CITY, city); + address.put(JsonKey.ADDRESS_LINE1, addressLine1); + addressList.add(address); + userMap.put(JsonKey.ADDRESS, addressList); + Map response = null; + try { + response = UserUtility.encryptUserData(userMap); + response = UserUtility.decryptUserData(response); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + assertEquals(userMap.get(JsonKey.FIRST_NAME), response.get(JsonKey.FIRST_NAME)); + assertEquals(email, response.get(JsonKey.EMAIL)); + assertEquals(userName, response.get(JsonKey.USER_NAME)); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/metrics/actors/OrganisationMetricsActorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/metrics/actors/OrganisationMetricsActorTest.java new file mode 100644 index 0000000000..0cbf165a8c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/metrics/actors/OrganisationMetricsActorTest.java @@ -0,0 +1,396 @@ +package org.sunbird.metrics.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mashape.unirest.http.HttpMethod; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.http.HttpEntity; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import scala.concurrent.Promise; + +/** + * Junit test cases for Org creation and consumption metrics. + * + * @author arvind. + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ElasticSearchRestHighImpl.class, + HttpClientBuilder.class, + ServiceFactory.class, + EsClientFactory.class +}) +@PowerMockIgnore("javax.management.*") +public class OrganisationMetricsActorTest { + + private ActorSystem system = ActorSystem.create("system"); + private static final Props prop = Props.create(OrganisationMetricsActor.class); + private static String userId = "456-123"; + private static final String EXTERNAL_ID = "ex00001lvervk"; + private static final String PROVIDER = "pr00001kfej"; + private static final String CHANNEL = "hjryr9349"; + private static final String orgId = "ofure8ofp9yfpf9ego"; + private static ObjectMapper mapper = new ObjectMapper(); + private static Map userOrgMap = new HashMap<>(); + private static CassandraOperationImpl cassandraOperation; + private static final String HTTP_POST = "POST"; + private ElasticSearchService esService; + + @BeforeClass + public static void setUp() { + + userOrgMap = new HashMap<>(); + userOrgMap.put(JsonKey.ID, orgId); + userOrgMap.put(JsonKey.IS_ROOT_ORG, true); + userOrgMap.put(JsonKey.CHANNEL, CHANNEL); + userOrgMap.put(JsonKey.PROVIDER, PROVIDER); + userOrgMap.put(JsonKey.EXTERNAL_ID, EXTERNAL_ID); + userOrgMap.put(JsonKey.HASHTAGID, orgId); + userOrgMap.put(JsonKey.ORG_NAME, "rootOrg"); + userOrgMap.put(JsonKey.FIRST_NAME, "user_first_name"); + + PowerMockito.mockStatic(ServiceFactory.class); + + cassandraOperation = mock(CassandraOperationImpl.class); + + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + PowerMockito.mockStatic(HttpClientBuilder.class); + } + + @Before + public void before() { + PowerMockito.mockStatic(HttpClientBuilder.class); + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + Response response = createCassandraInsertSuccessResponse(); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response); + Promise> promise = Futures.promise(); + promise.success(userOrgMap); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + } + + @SuppressWarnings({"deprecation", "unchecked"}) + @Test + public void testOrgCreationMetricsSuccess() throws JsonProcessingException { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + Promise> promise = Futures.promise(); + promise.success(userOrgMap); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + mockHttpPostSuccess( + HTTP_POST, + new ByteArrayInputStream((mapper.writeValueAsString(orgCreationSuccessMap())).getBytes())); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, orgId); + actorMessage.put(JsonKey.PERIOD, "7d"); + actorMessage.setOperation(ActorOperations.ORG_CREATION_METRICS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("50 second"), Response.class); + Map data = res.getResult(); + Assert.assertEquals("7d", data.get(JsonKey.PERIOD)); + Assert.assertEquals(orgId, ((Map) data.get("org")).get(JsonKey.ORG_ID)); + Map series = (Map) data.get(JsonKey.SERIES); + Assert.assertTrue(series.containsKey("org.creation.content[@status=draft].count")); + Assert.assertTrue(series.containsKey("org.creation.content[@status=review].count")); + Assert.assertTrue(series.containsKey("org.creation.content[@status=published].count")); + List> buckets = + (List>) + ((Map) series.get("org.creation.content[@status=draft].count")) + .get("buckets"); + Assert.assertEquals(7, buckets.size()); + Map snapshot = (Map) data.get(JsonKey.SNAPSHOT); + Assert.assertTrue(snapshot.containsKey("org.creation.content.count")); + Assert.assertTrue(snapshot.containsKey("org.creation.authors.count")); + Assert.assertTrue(snapshot.containsKey("org.creation.reviewers.count")); + Assert.assertTrue(snapshot.containsKey("org.creation.content[@status=draft].count")); + Assert.assertTrue(snapshot.containsKey("org.creation.content[@status=review].count")); + Assert.assertTrue(snapshot.containsKey("org.creation.content[@status=published].count")); + } + + @SuppressWarnings({"unchecked", "deprecation"}) + @Test + public void testOrgConsumptionMetricsSuccess() throws JsonProcessingException { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + Promise> promise = Futures.promise(); + promise.success(userOrgMap); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + mockHttpPostSuccess( + HTTP_POST, + new ByteArrayInputStream( + (mapper.writeValueAsString(orgConsumptionSuccessMap())).getBytes())); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, orgId); + actorMessage.put(JsonKey.PERIOD, "7d"); + actorMessage.setOperation(ActorOperations.ORG_CONSUMPTION_METRICS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Map data = res.getResult(); + Assert.assertEquals("7d", data.get(JsonKey.PERIOD)); + Assert.assertEquals(orgId, ((Map) data.get("org")).get(JsonKey.ORG_ID)); + Map series = (Map) data.get(JsonKey.SERIES); + Assert.assertTrue(series.containsKey("org.consumption.content.users.count")); + Assert.assertTrue(series.containsKey("org.consumption.content.time_spent.sum")); + List> buckets = + (List>) + ((Map) series.get("org.consumption.content.users.count")) + .get("buckets"); + Assert.assertEquals(7, buckets.size()); + Map snapshot = (Map) data.get(JsonKey.SNAPSHOT); + Assert.assertTrue(snapshot.containsKey("org.consumption.content.session.count")); + Assert.assertTrue(snapshot.containsKey("org.consumption.content.time_spent.sum")); + Assert.assertTrue(snapshot.containsKey("org.consumption.content.time_spent.average")); + } + + @SuppressWarnings("deprecation") + @Test + public void testOrgCreationMetricsWithInvalidOrgId() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + Promise> promise = Futures.promise(); + promise.success(null); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, "ORG_001_INVALID"); + actorMessage.put(JsonKey.PERIOD, "7d"); + actorMessage.setOperation(ActorOperations.ORG_CREATION_METRICS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException e = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertEquals(ResponseCode.invalidOrgData.getErrorCode(), e.getCode()); + } + + @SuppressWarnings("deprecation") + @Test + public void testOrgConsumptionMetricsWithInvalidOrgId() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + Promise> promise = Futures.promise(); + promise.success(null); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, "ORG_001_INVALID"); + actorMessage.put(JsonKey.PERIOD, "7d"); + actorMessage.setOperation(ActorOperations.ORG_CONSUMPTION_METRICS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException e = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertEquals(ResponseCode.invalidOrgData.getErrorCode(), e.getCode()); + } + + @SuppressWarnings("deprecation") + @Test + public void testOrgCreationMetricsInvalidPeriod() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + Promise> promise = Futures.promise(); + promise.success(userOrgMap); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, orgId); + actorMessage.put(JsonKey.PERIOD, "10d"); + actorMessage.setOperation(ActorOperations.ORG_CREATION_METRICS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException e = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertEquals("INVALID_PERIOD", e.getCode()); + } + + @SuppressWarnings("deprecation") + @Test + public void testOrgConsumptionMetricsWithInvalidPeriod() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + Promise> promise = Futures.promise(); + promise.success(userOrgMap); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, orgId); + actorMessage.put(JsonKey.PERIOD, "10d"); + actorMessage.setOperation(ActorOperations.ORG_CONSUMPTION_METRICS.getValue()); + + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException e = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertEquals("INVALID_PERIOD", e.getCode()); + } + + @SuppressWarnings({"deprecation", "unchecked"}) + @Test + public void testOrgCreationMetricsReportDataSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + + Promise> promise = Futures.promise(); + promise.success(userOrgMap); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, orgId); + actorMessage.put(JsonKey.PERIOD, "7d"); + actorMessage.put(JsonKey.REQUESTED_BY, userId); + actorMessage.put(JsonKey.FORMAT, "csv"); + actorMessage.setOperation(ActorOperations.ORG_CREATION_METRICS_REPORT.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Map data = res.getResult(); + String id = (String) data.get(JsonKey.REQUEST_ID); + Assert.assertNotNull(id); + } + + @SuppressWarnings({"deprecation", "unchecked"}) + @Test + public void testOrgConsumptionMetricsReportDataSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(prop); + Promise> promise = Futures.promise(); + promise.success(userOrgMap); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + + Request actorMessage = new Request(); + actorMessage.put(JsonKey.ORG_ID, orgId); + actorMessage.put(JsonKey.PERIOD, "7d"); + actorMessage.put(JsonKey.REQUESTED_BY, userId); + actorMessage.put(JsonKey.FORMAT, "csv"); + actorMessage.setOperation(ActorOperations.ORG_CONSUMPTION_METRICS_REPORT.getValue()); + + subject.tell(actorMessage, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Map data = res.getResult(); + String id = (String) data.get(JsonKey.REQUEST_ID); + Assert.assertNotNull(id); + } + + private static void mockHttpPostSuccess(String methodType, InputStream inputStream) { + + if (HttpMethod.POST.name().equalsIgnoreCase(methodType)) { + HttpClientBuilder httpClientBuilder = PowerMockito.mock(HttpClientBuilder.class); + CloseableHttpClient client = PowerMockito.mock(CloseableHttpClient.class); + CloseableHttpResponse httpResponse = Mockito.mock(CloseableHttpResponse.class); + when(HttpClientBuilder.create()).thenReturn(httpClientBuilder); + when(httpClientBuilder.build()).thenReturn(client); + + try { + when(client.execute(Mockito.any(HttpPost.class))).thenReturn(httpResponse); + } catch (IOException e) { + e.printStackTrace(); + } + HttpEntity httpEntity = Mockito.mock(HttpEntity.class); + when(httpResponse.getEntity()).thenReturn(httpEntity); + StatusLine statusLine = Mockito.mock(StatusLine.class); + when(httpResponse.getStatusLine()).thenReturn(statusLine); + when(statusLine.getStatusCode()).thenReturn(200); + Map responseMap = new HashMap<>(); + Map resultMap = new HashMap<>(); + Map aggregateMap = new HashMap<>(); + Map statusMap = new HashMap<>(); + aggregateMap.put(JsonKey.STATUS, statusMap); + resultMap.put(JsonKey.AGGREGATIONS, aggregateMap); + responseMap.put(JsonKey.RESULT, resultMap); + try { + when(httpEntity.getContent()).thenReturn(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private Map orgCreationSuccessMap() { + + Map responseMap = new HashMap<>(); + Map resultMap = new HashMap<>(); + Map aggregateMap = new HashMap<>(); + Map statusMap = new HashMap<>(); + aggregateMap.put(JsonKey.STATUS, statusMap); + resultMap.put(JsonKey.AGGREGATIONS, aggregateMap); + responseMap.put(JsonKey.RESULT, resultMap); + return responseMap; + } + + private Map orgConsumptionSuccessMap() { + Map responseMap = new HashMap<>(); + Map resultMap = new HashMap<>(); + Map aggregateMap = new HashMap<>(); + List> metricsList = new ArrayList<>(); + Map statusMap = new HashMap<>(); + aggregateMap.put(JsonKey.STATUS, statusMap); + resultMap.put(JsonKey.METRICS, metricsList); + Map summaryMap = new HashMap<>(); + resultMap.put(JsonKey.SUMMARY, summaryMap); + responseMap.put(JsonKey.RESULT, resultMap); + return responseMap; + } + + private Response createCassandraInsertSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/ratelimit/dao/RateLimitDaoTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/ratelimit/dao/RateLimitDaoTest.java new file mode 100644 index 0000000000..92b12cdcdc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/ratelimit/dao/RateLimitDaoTest.java @@ -0,0 +1,127 @@ +package org.sunbird.ratelimit.dao; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.doAnswer; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.ratelimit.limiter.OtpRateLimiter; +import org.sunbird.ratelimit.limiter.RateLimit; + +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*"}) +public class RateLimitDaoTest { + + private static final String KEY = "9999888898"; + private static final int HOUR_LIMIT = 10; + + @InjectMocks private RateLimitDao rateLimitdDao = RateLimitDaoImpl.getInstance(); + + @Mock private CassandraOperation cassandraOperation; + + @Before + public void beforeEachTest() { + MockitoAnnotations.initMocks(this); + when(cassandraOperation.batchInsertWithTTL( + Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.anyList())) + .thenReturn(getSuccessResponse()); + } + + @Test + public void testInsertRateLimitsSuccess() { + doAnswer( + (Answer) + invocation -> { + List> rateLimits = invocation.getArgumentAt(2, List.class); + assertTrue(CollectionUtils.isNotEmpty(rateLimits)); + assertSame(1, rateLimits.size()); + assertSame(1, rateLimits.get(0).get(JsonKey.COUNT)); + return null; + }) + .when(cassandraOperation) + .batchInsertWithTTL( + Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.anyList()); + rateLimitdDao.insertRateLimits(getRateLimits()); + } + + @Test(expected = ProjectCommonException.class) + public void testInsertRateLimitsFailureWithInvalidData() { + try { + rateLimitdDao.insertRateLimits(getInvalidRateLimits()); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.SERVER_ERROR.getResponseCode(), e.getResponseCode()); + throw e; + } + } + + @Test + public void testGetRateLimitsSuccess() { + when(cassandraOperation.getRecordsByIdsWithSpecifiedColumnsAndTTL( + Mockito.anyString(), + Mockito.anyString(), + Mockito.any(), + Mockito.anyList(), + Mockito.any())) + .then( + (Answer) + invocation -> { + return getRateLimitRecords(); + }); + + List> results = rateLimitdDao.getRateLimits(KEY); + assertTrue(CollectionUtils.isNotEmpty(results)); + assertSame(KEY, results.get(0).get(JsonKey.KEY)); + assertSame(5, results.get(0).get(JsonKey.COUNT)); + } + + private List getRateLimits() { + List rateLimits = new ArrayList<>(); + rateLimits.add( + new RateLimit(KEY, OtpRateLimiter.HOUR.name(), 20, OtpRateLimiter.HOUR.getTTL())); + return rateLimits; + } + + private List getInvalidRateLimits() { + List rateLimits = new ArrayList<>(); + rateLimits.add(new RateLimit(KEY, null, 0, OtpRateLimiter.HOUR.getTTL())); + return rateLimits; + } + + private Response getRateLimitRecords() { + List> results = new ArrayList<>(); + Map record = new HashMap<>(); + record.put(JsonKey.KEY, KEY); + record.put(JsonKey.RATE_LIMIT_UNIT, OtpRateLimiter.HOUR.name()); + record.put(JsonKey.RATE, HOUR_LIMIT); + record.put(JsonKey.TTL, 3500); + record.put(JsonKey.COUNT, 5); + results.add(record); + Response response = new Response(); + response.put(JsonKey.RESPONSE, results); + return response; + } + + private Response getSuccessResponse() { + Response response = new Response(); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/ratelimit/service/RateLimitServiceTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/ratelimit/service/RateLimitServiceTest.java new file mode 100644 index 0000000000..db48c8323f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/ratelimit/service/RateLimitServiceTest.java @@ -0,0 +1,119 @@ +package org.sunbird.ratelimit.service; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.anyList; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.ratelimit.dao.RateLimitDao; +import org.sunbird.ratelimit.limiter.OtpRateLimiter; +import org.sunbird.ratelimit.limiter.RateLimit; +import org.sunbird.ratelimit.limiter.RateLimiter; + +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*"}) +public class RateLimitServiceTest { + + private static final String KEY = "9999888898"; + private static final int HOUR_LIMIT = 10; + + @InjectMocks private RateLimitService rateLimitService = new RateLimitServiceImpl(); + + @Mock private RateLimitDao rateLimitdDao; + + private RateLimiter hourRateLimiter = OtpRateLimiter.HOUR; + + private RateLimiter dayRateLimiter = OtpRateLimiter.DAY; + + @Before + public void beforeEachTest() { + MockitoAnnotations.initMocks(this); + doNothing().when(rateLimitdDao).insertRateLimits(anyList()); + } + + @Test + public void testThrottleByKeyOnGoingSuccess() { + when(rateLimitdDao.getRateLimits(anyString())).thenReturn(getRateLimitRecords(5)); + Map countsByRateLimiter = new HashMap<>(); + countsByRateLimiter.put(hourRateLimiter.name(), 6); + assertRateLimitsOnInsert(countsByRateLimiter); + rateLimitService.throttleByKey(KEY, new RateLimiter[] {hourRateLimiter}); + } + + @Test + public void testThrottleByKeyNew() { + when(rateLimitdDao.getRateLimits(anyString())).thenReturn(null); + Map countsByRateLimiter = new HashMap<>(); + countsByRateLimiter.put(hourRateLimiter.name(), 1); + assertRateLimitsOnInsert(countsByRateLimiter); + rateLimitService.throttleByKey(KEY, new RateLimiter[] {hourRateLimiter}); + } + + @Test + public void testThrottleByKeyMultipleLimit() { + when(rateLimitdDao.getRateLimits(anyString())).thenReturn(getRateLimitRecords(5)); + Map countsByRateLimiter = new HashMap<>(); + countsByRateLimiter.put(hourRateLimiter.name(), 6); + countsByRateLimiter.put(dayRateLimiter.name(), 1); + assertRateLimitsOnInsert(countsByRateLimiter); + rateLimitService.throttleByKey(KEY, new RateLimiter[] {hourRateLimiter, dayRateLimiter}); + } + + @Test(expected = ProjectCommonException.class) + public void testThrottleByKeyFailure() { + when(rateLimitdDao.getRateLimits(anyString())).thenReturn(getRateLimitRecords(HOUR_LIMIT)); + try { + rateLimitService.throttleByKey(KEY, new RateLimiter[] {hourRateLimiter}); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.TOO_MANY_REQUESTS.getResponseCode(), e.getResponseCode()); + throw e; + } + } + + private List> getRateLimitRecords(int count) { + List> results = new ArrayList<>(); + Map record = new HashMap<>(); + record.put(JsonKey.KEY, KEY); + record.put(JsonKey.RATE_LIMIT_UNIT, OtpRateLimiter.HOUR.name()); + record.put(JsonKey.RATE, HOUR_LIMIT); + record.put(JsonKey.TTL, 3500); + record.put(JsonKey.COUNT, count); + results.add(record); + return results; + } + + private void assertRateLimitsOnInsert(Map countsByRateLimiter) { + doAnswer( + (Answer) + invocation -> { + List rateLimits = invocation.getArgumentAt(0, List.class); + assertTrue(CollectionUtils.isNotEmpty(rateLimits)); + assertSame(countsByRateLimiter.size(), rateLimits.size()); + rateLimits.forEach( + rateLimit -> { + assertSame( + countsByRateLimiter.get(rateLimit.getUnit()), rateLimit.getCount()); + }); + return null; + }) + .when(rateLimitdDao) + .insertRateLimits(anyList()); + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/validator/user/UserBulkMigrationRequestValidatorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/validator/user/UserBulkMigrationRequestValidatorTest.java new file mode 100644 index 0000000000..705048fee9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/validator/user/UserBulkMigrationRequestValidatorTest.java @@ -0,0 +1,256 @@ +package org.sunbird.validator.user; + +import java.util.ArrayList; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.sunbird.bean.MigrationUser; +import org.sunbird.bean.ShadowUserUpload; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; + +@PrepareForTest(UserBulkMigrationRequestValidator.class) +public class UserBulkMigrationRequestValidatorTest { + private static final int MAX_ROW_SUPPORTED = 20000; + + @Test + public void testRowsCountFailureWithEmptyCSVFile() { + List migrationUserList = new ArrayList<>(); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals(ResponseCode.noDataForConsumption.getErrorMessage(), e.getMessage()); + } + } + + @Test + public void testRowsCountFailureWithMoreCsvRowsSupported() { + List migrationUserList = new ArrayList<>(); + for (int i = 0; i < MAX_ROW_SUPPORTED + 1; i++) { + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUserList.add(migrationUser); + } + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("2024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals( + ResponseCode.csvRowsExceeds.getErrorMessage().concat("supported:" + MAX_ROW_SUPPORTED), + e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithBlankName() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setPhone("9876543210"); + migrationUser.setInputStatus(JsonKey.ACTIVE); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setUserExternalId("user ext id"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals("[ In Row 1:the Column name:is missing ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithBlankEmail() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setInputStatus(JsonKey.ACTIVE); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setName("Shadow User Name"); + migrationUser.setUserExternalId("user ext id"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals("[ In Row 1:the Column email:is missing ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithInvalidEmail() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setInputStatus(JsonKey.ACTIVE); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setEmail("wrongemail"); + migrationUser.setName("Shadow User Name"); + migrationUser.setUserExternalId("user ext id"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + System.out.println(e.getMessage()); + Assert.assertEquals("[ In Row 1:the Column email:is invalid ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithInvalidPhone() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setInputStatus(JsonKey.ACTIVE); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setPhone("987897"); + migrationUser.setName("Shadow User Name"); + migrationUser.setUserExternalId("user ext id"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals("[ In Row 1:the Column phone:is invalid ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithBlankUserExtId() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setInputStatus(JsonKey.ACTIVE); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setPhone("9876543210"); + migrationUser.setName("Shadow User Name"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals("[ In Row 1:the Column userExternalId:is missing ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithBlankInputStatus() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setPhone("9876543210"); + migrationUser.setUserExternalId("any user ext id"); + migrationUser.setName("Shadow User Name"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals("[ In Row 1:the Column input status:is missing ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithInvalidInputStatus() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setInputStatus("wrong input status"); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setPhone("9876543210"); + migrationUser.setUserExternalId("any user ext id"); + migrationUser.setName("Shadow User Name"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals("[ In Row 1:the Column input status:is invalid ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithDuplicateUserExtId() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setInputStatus("Active"); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setPhone("9876543210"); + migrationUser.setUserExternalId("any user ext id"); + migrationUser.setName("Shadow User Name"); + migrationUserList.add(migrationUser); + MigrationUser anotherMigrationUser = new MigrationUser(); + anotherMigrationUser.setChannel("TN"); + anotherMigrationUser.setInputStatus("Active"); + anotherMigrationUser.setOrgExternalId("org ext id"); + anotherMigrationUser.setPhone("9876543210"); + anotherMigrationUser.setUserExternalId("any user ext id"); + anotherMigrationUser.setName("Shadow User Name"); + migrationUserList.add(anotherMigrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + Assert.assertEquals("[ In Row 2:the Column userExternalId:is duplicate ]", e.getMessage()); + } + } + + @Test + public void testShadowUserMigrationWithInvalidName() { + List migrationUserList = new ArrayList<>(); + MigrationUser migrationUser = new MigrationUser(); + migrationUser.setChannel("TN"); + migrationUser.setInputStatus("Active"); + migrationUser.setOrgExternalId("org ext id"); + migrationUser.setPhone("9876543210"); + migrationUser.setUserExternalId("any user ext id"); + migrationUser.setName("###Shadow User Name"); + migrationUserList.add(migrationUser); + try { + new ShadowUserUpload.ShadowUserUploadBuilder() + .setProcessId(ProjectUtil.generateUniqueId()) + .setFileSize("1024") + .setValues(migrationUserList) + .validate(); + } catch (Exception e) { + System.out.println(e.getMessage()); + Assert.assertEquals("[ In Row 1:the Column name:is invalid ]", e.getMessage()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/validator/user/UserBulkUploadRequestValidatorTest.java b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/validator/user/UserBulkUploadRequestValidatorTest.java new file mode 100644 index 0000000000..5f95692e87 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/java/org/sunbird/validator/user/UserBulkUploadRequestValidatorTest.java @@ -0,0 +1,47 @@ +package org.sunbird.validator.user; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.models.user.UserType; + +public class UserBulkUploadRequestValidatorTest { + + @Test + public void testValidateOrganisationIdWithMandatoryParamMissing() { + Map userMap = new HashMap<>(); + userMap.put(JsonKey.USER_TYPE, UserType.TEACHER.getTypeName()); + try { + UserBulkUploadRequestValidator.validateUserBulkUploadRequest(userMap); + } catch (Exception e) { + Assert.assertEquals("Mandatory parameter orgId or orgExternalId is missing.", e.getMessage()); + } + } + + @Test + public void testValidateUserTypeWithMissingUserTypeParam() { + Map userMap = new HashMap<>(); + try { + userMap.put(JsonKey.USER_TYPE, "invalid"); + UserBulkUploadRequestValidator.validateUserBulkUploadRequest(userMap); + } catch (Exception e) { + Assert.assertEquals( + "Invalid userType: invalid. Valid values are: [TEACHER, OTHER].", e.getMessage()); + } + } + + @Test + public void testUserBulkRequestValidatorSuccess() { + Map userMap = new HashMap<>(); + try { + userMap.put(JsonKey.USER_TYPE, UserType.TEACHER.getTypeName()); + userMap.put(JsonKey.ORG_ID, "anyOrgId"); + UserBulkUploadRequestValidator.validateUserBulkUploadRequest(userMap); + } catch (Exception e) { + System.out.println(e.getMessage()); + Assert.assertTrue(false); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkOrgUploadEmptyFile.csv b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkOrgUploadEmptyFile.csv new file mode 100644 index 0000000000..cfa3c1c62e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkOrgUploadEmptyFile.csv @@ -0,0 +1 @@ +orgName,isRootOrg,channel,externalId,provider,description,homeUrl,orgCode,orgType,preferredLanguage,theme,contactDetail,hashTagId \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkOrgUploadSample.csv b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkOrgUploadSample.csv new file mode 100644 index 0000000000..5e0450b4a3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkOrgUploadSample.csv @@ -0,0 +1,2 @@ +orgName,isRootOrg,channel,externalId,provider,description,homeUrl,orgCode,orgType,preferredLanguage,theme,contactDetail,hashTagId +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkUploadUserSample.csv b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkUploadUserSample.csv new file mode 100644 index 0000000000..31bf051a44 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkUploadUserSample.csv @@ -0,0 +1,2 @@ +firstName,lastName,phone,email,userName,countryCode,phoneVerified,emailVerified,roles,position,location,dob,gender,language,profileSummary,subject,webPages +xyz1234516,Kumar15,9453500000,bk3@yahoo.com,bk3hoo,91,true,true,,pos,loc,1992-10-12,MALE,"ENGLISH,KANADA",summary,"HINDI,MATH,PHYSICS", diff --git a/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkUploadUserWithInvalidHeaders.csv b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkUploadUserWithInvalidHeaders.csv new file mode 100644 index 0000000000..a86e04bcfa --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/resources/BulkUploadUserWithInvalidHeaders.csv @@ -0,0 +1 @@ +firstName,lastName,phone,email,userName,countryCode,password,phoneVerified,emailVerified,roles,position,location,dob,gender,language,profileSummary,subject,webPages diff --git a/actors/sunbird-lms-mw/actors/common/src/test/resources/FrameworkForTextbookTocActorTest.json b/actors/sunbird-lms-mw/actors/common/src/test/resources/FrameworkForTextbookTocActorTest.json new file mode 100644 index 0000000000..ce216c1eb6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/resources/FrameworkForTextbookTocActorTest.json @@ -0,0 +1 @@ +{ "identifier":"Identifier","frameworkCategories":{"medium":"Medium","gradeLevel":"Grade","subject":"Subject"},"hierarchy":{"Textbook":"Textbook Name","L:1":"Level 1 Textbook Unit","L:2":"Level 2 Textbook Unit","L:3":"Level 3 Textbook Unit","L:4":"Level 4 Textbook Unit"},"metadata":{"description":"Description","dialcodeRequired":"QR Code Required?","dialcodes":"QR Code","purpose":"Purpose of Content to be linked","topic":"Mapped Topics","keywords":"Keywords"}} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/common/src/test/resources/MandatoryValueForTextbookTocActorTest.json b/actors/sunbird-lms-mw/actors/common/src/test/resources/MandatoryValueForTextbookTocActorTest.json new file mode 100644 index 0000000000..bd644ecf05 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/common/src/test/resources/MandatoryValueForTextbookTocActorTest.json @@ -0,0 +1 @@ +{"Textbook":"Textbook Name","L:1":"Level 1 Textbook Unit"} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/core/src/main/java/org/sunbird/learner/actors/ThreadDumpActor.java b/actors/sunbird-lms-mw/actors/core/src/main/java/org/sunbird/learner/actors/ThreadDumpActor.java new file mode 100644 index 0000000000..7bc336cc6c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/core/src/main/java/org/sunbird/learner/actors/ThreadDumpActor.java @@ -0,0 +1,79 @@ +package org.sunbird.learner.actors; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Mahesh Kumar Gangula */ +@ActorConfig( + tasks = {}, + asyncTasks = {"takeThreadDump"} +) +public class ThreadDumpActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + takeThreadDump(); + Response response = new Response(); + response.setResponseCode(ResponseCode.success); + sender().tell(response, self()); + } + + private void takeThreadDump() { + final StringBuilder dump = new StringBuilder(); + final StringBuilder details = new StringBuilder(); + final StringBuilder info = new StringBuilder(); + final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + final ThreadInfo[] threadInfos = + threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100); + details.append("Thread id | Thread name | CPU time | User time | Blocked time\n\n"); + for (ThreadInfo threadInfo : threadInfos) { + dump.append('"'); + dump.append(threadInfo.getThreadName()); + dump.append("\" "); + final Thread.State state = threadInfo.getThreadState(); + dump.append("\n java.lang.Thread.State: "); + dump.append(state); + final StackTraceElement[] stackTraceElements = threadInfo.getStackTrace(); + for (final StackTraceElement stackTraceElement : stackTraceElements) { + dump.append("\n at "); + dump.append(stackTraceElement); + } + dump.append("\n\n"); + + long cputime = threadMXBean.getThreadCpuTime(threadInfo.getThreadId()); + long usertime = threadMXBean.getThreadUserTime(threadInfo.getThreadId()); + long blockedtime = threadInfo.getBlockedTime(); + details.append( + threadInfo.getThreadId() + + " | " + + threadInfo.getThreadName() + + " | " + + cputime + + " | " + + usertime + + " | " + + blockedtime + + "\n\n"); + + info.append(threadInfo.toString() + "\n\n"); + } + + System.out.println("=== thread-dump start ==="); + System.out.println(dump.toString()); + System.out.println("=== thread-dump end ===\n\n"); + + System.out.println("=== thread-cpu start ==="); + System.out.println(details.toString()); + System.out.println("=== thread-cpu end ===\n\n"); + + System.out.println("=== thread-info start ==="); + System.out.println(info.toString()); + System.out.println("=== thread-info end ===\n\n"); + } +} diff --git a/actors/sunbird-lms-mw/actors/location/pom.xml b/actors/sunbird-lms-mw/actors/location/pom.xml new file mode 100644 index 0000000000..91700d0d0f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + org.sunbird + mw-actors + 1.0-SNAPSHOT + ../pom.xml + + location + Location + + UTF-8 + + + + org.sunbird + actor-common + 1.0-SNAPSHOT + + + com.typesafe.akka + akka-testkit_2.11 + ${learner.akka.version} + test + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + **/*Spec.java + **/*Test.java + + + + + + diff --git a/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/BaseLocationActor.java b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/BaseLocationActor.java new file mode 100644 index 0000000000..3551295e6e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/BaseLocationActor.java @@ -0,0 +1,89 @@ +package org.sunbird.location.actors; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.request.Request; +import org.sunbird.dto.SearchDTO; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.telemetry.util.TelemetryWriter; + +/** @author Amit Kumar */ +public abstract class BaseLocationActor extends BaseActor { + + public void generateTelemetryForLocation( + String targetObjId, Map data, String operation, Map context) { + // object of telemetry event... + try { + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + targetObject = + TelemetryUtil.generateTargetObject(targetObjId, JsonKey.LOCATION, operation, null); + if (!MapUtils.isEmpty(data) + && StringUtils.isNotEmpty((String) data.get(GeoLocationJsonKey.PARENT_ID))) { + TelemetryUtil.generateCorrelatedObject( + (String) data.get(GeoLocationJsonKey.PARENT_ID), + JsonKey.LOCATION, + null, + correlatedObject); + } + TelemetryUtil.telemetryProcessingCall(data, targetObject, correlatedObject, context); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + public void generateSearchTelemetryEvent( + SearchDTO searchDto, + String[] types, + Map result, + Map context) { + try { + Map params = new HashMap<>(); + params.put(JsonKey.QUERY, searchDto.getQuery()); + params.put(JsonKey.FILTERS, searchDto.getAdditionalProperties().get(JsonKey.FILTERS)); + params.put(JsonKey.SORT, searchDto.getSortBy()); + params.put(JsonKey.TOPN, generateTopNResult(result)); + params.put(JsonKey.SIZE, result.get(JsonKey.COUNT)); + params.put(JsonKey.TYPE, String.join(",", types)); + + Request request = new Request(); + request.setRequest(telemetryRequestForSearch(context, params)); + TelemetryWriter.write(request); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + private List> generateTopNResult(Map result) { + List> dataMapList = + (List>) result.get(JsonKey.RESPONSE); + Integer topN = + Integer.parseInt(PropertiesCache.getInstance().getProperty(JsonKey.SEARCH_TOP_N)); + int count = Math.min(topN, dataMapList.size()); + List> list = new ArrayList<>(); + for (int i = 0; i < count; i++) { + Map m = new HashMap<>(); + m.put(JsonKey.ID, dataMapList.get(i).get(JsonKey.ID)); + list.add(m); + } + return list; + } + + private static Map telemetryRequestForSearch( + Map telemetryContext, Map params) { + Map map = new HashMap<>(); + map.put(JsonKey.CONTEXT, telemetryContext); + map.put(JsonKey.PARAMS, params); + map.put(JsonKey.TELEMETRY_EVENT_TYPE, "SEARCH"); + return map; + } +} diff --git a/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/LocationActor.java b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/LocationActor.java new file mode 100644 index 0000000000..78ec205bc4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/LocationActor.java @@ -0,0 +1,296 @@ +package org.sunbird.location.actors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.*; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.location.dao.LocationDao; +import org.sunbird.location.dao.impl.LocationDaoFactory; +import org.sunbird.location.util.LocationRequestValidator; +import org.sunbird.models.location.Location; +import org.sunbird.models.location.apirequest.UpsertLocationRequest; + +/** + * This class will handle all location related request. + * + * @author Amit Kumar + */ +@ActorConfig( + tasks = { + "createLocation", + "updateLocation", + "searchLocation", + "deleteLocation", + "getRelatedLocationIds" + }, + asyncTasks = {} +) +public class LocationActor extends BaseLocationActor { + + private LocationDao locationDao = LocationDaoFactory.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.LOCATION); + String operation = request.getOperation(); + switch (operation) { + case "createLocation": + createLocation(request); + break; + case "updateLocation": + updateLocation(request); + break; + case "searchLocation": + searchLocation(request); + break; + case "deleteLocation": + deleteLocation(request); + break; + case "getRelatedLocationIds": + getRelatedLocationIds(request); + break; + default: + onReceiveUnsupportedOperation("LocationActor"); + } + } + + private void getRelatedLocationIds(Request request) { + Response response = new Response(); + List relatedLocationIds = + getValidatedRelatedLocationIds((List) request.get(JsonKey.LOCATION_CODES)); + response.getResult().put(JsonKey.RESPONSE, relatedLocationIds); + sender().tell(response, self()); + } + + private void createLocation(Request request) { + try { + ObjectMapper mapper = new ObjectMapper(); + UpsertLocationRequest locationRequest = + ProjectUtil.convertToRequestPojo(request, UpsertLocationRequest.class); + validateUpsertLocnReq(locationRequest, JsonKey.CREATE); + // put unique identifier in request for Id + String id = ProjectUtil.generateUniqueId(); + locationRequest.setId(id); + Location location = mapper.convertValue(locationRequest, Location.class); + Response response = locationDao.create(location); + sender().tell(response, self()); + ProjectLogger.log("Insert location data to ES"); + saveDataToES(mapper.convertValue(location, Map.class), JsonKey.INSERT); + generateTelemetryForLocation( + id, mapper.convertValue(location, Map.class), JsonKey.CREATE, request.getContext()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void updateLocation(Request request) { + try { + ObjectMapper mapper = new ObjectMapper(); + UpsertLocationRequest locationRequest = + ProjectUtil.convertToRequestPojo(request, UpsertLocationRequest.class); + validateUpsertLocnReq(locationRequest, JsonKey.UPDATE); + Location location = mapper.convertValue(locationRequest, Location.class); + Response response = locationDao.update(location); + sender().tell(response, self()); + ProjectLogger.log("Update location data to ES"); + saveDataToES(mapper.convertValue(location, Map.class), JsonKey.UPDATE); + generateTelemetryForLocation( + location.getId(), + mapper.convertValue(location, Map.class), + JsonKey.UPDATE, + request.getContext()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void searchLocation(Request request) { + try { + Response response = searchLocation(request.getRequest()); + sender().tell(response, self()); + SearchDTO searchDto = Util.createSearchDto(request.getRequest()); + String[] types = {ProjectUtil.EsType.location.getTypeName()}; + generateSearchTelemetryEvent(searchDto, types, response.getResult(), request.getContext()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private Response searchLocation(Map searchMap) { + return locationDao.search(searchMap); + } + + private void deleteLocation(Request request) { + try { + String locationId = (String) request.getRequest().get(JsonKey.LOCATION_ID); + LocationRequestValidator.isLocationHasChild(locationId); + Response response = locationDao.delete(locationId); + sender().tell(response, self()); + ProjectLogger.log("Delete location data from ES"); + deleteDataFromES(locationId); + generateTelemetryForLocation( + locationId, new HashMap<>(), JsonKey.DELETE, request.getContext()); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + sender().tell(ex, self()); + } + } + + private void saveDataToES(Map locData, String opType) { + Request request = new Request(); + request.setOperation(LocationActorOperation.UPSERT_LOCATION_TO_ES.getValue()); + request.getRequest().put(JsonKey.LOCATION, locData); + request.getRequest().put(JsonKey.OPERATION_TYPE, opType); + try { + tellToAnother(request); + } catch (Exception ex) { + ProjectLogger.log( + "LocationActor:saveDataToES: Exception occurred with error message = ", ex.getMessage()); + } + } + + private void deleteDataFromES(String locId) { + Request request = new Request(); + request.setOperation(LocationActorOperation.DELETE_LOCATION_FROM_ES.getValue()); + request.getRequest().put(JsonKey.LOCATION_ID, locId); + try { + tellToAnother(request); + } catch (Exception ex) { + ProjectLogger.log( + "LocationActor:saveDataToES: Exception occurred with error message = ", ex.getMessage()); + } + } + + private void validateUpsertLocnReq(UpsertLocationRequest locationRequest, String operation) { + if (StringUtils.isNotEmpty(locationRequest.getType())) { + LocationRequestValidator.isValidLocationType(locationRequest.getType()); + } + LocationRequestValidator.isValidParentIdAndCode(locationRequest, operation); + } + + public List getValidatedRelatedLocationIds(List codeList) { + Set locationIds = null; + List codes = new ArrayList<>(codeList); + List locationList = getSearchResult(JsonKey.CODE, codeList); + List locationIdList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(locationList)) { + if (locationList.size() != codes.size()) { + List resCodeList = + locationList.stream().map(Location::getCode).collect(Collectors.toList()); + List invalidCodeList = + codes.stream().filter(s -> !resCodeList.contains(s)).collect(Collectors.toList()); + throwInvalidParameterValueException(invalidCodeList); + } else { + locationIds = getValidatedRelatedLocationSet(locationList); + } + } else { + throwInvalidParameterValueException(codeList); + } + locationIdList.addAll(locationIds); + return locationIdList; + } + + private List getSearchResult(String param, Object value) { + Map filters = new HashMap<>(); + Map searchRequestMap = new HashMap<>(); + filters.put(param, value); + searchRequestMap.put(JsonKey.FILTERS, filters); + Response response = searchLocation(searchRequestMap); + if (response != null) { + List> responseList = + (List>) response.getResult().get(JsonKey.RESPONSE); + ObjectMapper mapper = new ObjectMapper(); + return responseList + .stream() + .map(s -> mapper.convertValue(s, Location.class)) + .collect(Collectors.toList()); + } else { + return new ArrayList<>(); + } + } + + private Location getLocation(String locationId) { + List locations = getSearchResult(JsonKey.ID, locationId); + if (locations.isEmpty()) return null; + + return locations.get(0); + } + + private void throwInvalidParameterValueException(List codeList) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameterValue.getErrorMessage(), codeList, JsonKey.LOCATION_CODE), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + public Set getValidatedRelatedLocationSet(List locationList) { + Set locationSet = new HashSet<>(); + for (Location requestedLocation : locationList) { + Set parentLocnSet = getParentLocations(requestedLocation); + if (CollectionUtils.sizeIsEmpty(locationSet)) { + locationSet.addAll(parentLocnSet); + } else { + for (Location currentLocation : parentLocnSet) { + String type = currentLocation.getType(); + locationSet + .stream() + .forEach( + location -> { + if (type.equalsIgnoreCase(location.getType()) + && !(currentLocation.getId().equals(location.getId()))) { + throw new ProjectCommonException( + ResponseCode.conflictingOrgLocations.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.conflictingOrgLocations.getErrorMessage(), + requestedLocation.getCode(), + location.getCode(), + type), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + locationSet.add(currentLocation); + } + } + } + return locationSet.stream().map(Location::getId).collect(Collectors.toSet()); + } + + private Set getParentLocations(Location locationObj) { + Set locationSet = new LinkedHashSet<>(); + Location location = locationObj; + int count = getOrder(location.getType()); + locationSet.add(location); + while (count > 0) { + Location parent = null; + if (getOrder(location.getType()) == 0 && StringUtils.isNotEmpty(location.getId())) { + parent = getLocation(location.getId()); + } else if (StringUtils.isNotEmpty(location.getParentId())) { + parent = getLocation(location.getParentId()); + } + if (null != parent) { + locationSet.add(parent); + location = parent; + } + count--; + } + return locationSet; + } + + public int getOrder(String type) { + return DataCacheHandler.getLocationOrderMap().get(type); + } +} diff --git a/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/LocationBackgroundActor.java b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/LocationBackgroundActor.java new file mode 100644 index 0000000000..b285a8014b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/actors/LocationBackgroundActor.java @@ -0,0 +1,52 @@ +package org.sunbird.location.actors; + +import java.util.Map; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; + +/** + * This class will handle all background service for locationActor. + * + * @author Amit Kumar + */ +@ActorConfig( + tasks = {}, + asyncTasks = {"upsertLocationDataToES", "deleteLocationDataFromES"} +) +public class LocationBackgroundActor extends BaseLocationActor { + + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + ProjectLogger.log("LocationBackgroundActor onReceive called"); + String operation = request.getOperation(); + + switch (operation) { + case "upsertLocationDataToES": + upsertLocationDataToES(request); + break; + case "deleteLocationDataFromES": + deleteLocationDataFromES(request); + break; + default: + onReceiveUnsupportedOperation("LocationBackgroundActor"); + } + } + + private void deleteLocationDataFromES(Request request) { + String locationId = (String) request.get(JsonKey.LOCATION_ID); + esService.delete(ProjectUtil.EsType.location.getTypeName(), locationId); + } + + private void upsertLocationDataToES(Request request) { + Map location = (Map) request.getRequest().get(JsonKey.LOCATION); + esService.upsert( + ProjectUtil.EsType.location.getTypeName(), (String) location.get(JsonKey.ID), location); + } +} diff --git a/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/LocationDao.java b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/LocationDao.java new file mode 100644 index 0000000000..3d9cd95a25 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/LocationDao.java @@ -0,0 +1,44 @@ +package org.sunbird.location.dao; + +import java.util.Map; +import org.sunbird.common.models.response.Response; +import org.sunbird.models.location.Location; + +/** @author Amit Kumar */ +public interface LocationDao { + /** + * @param location Location Details + * @return response Response + */ + Response create(Location location); + + /** + * @param location Location Details + * @return response Response + */ + Response update(Location location); + + /** + * @param locationId its a unique identity for Location + * @return response Response + */ + Response delete(String locationId); + + /** + * @param searchQueryMap Map it contains the filters to search Location from ES + * @return response Response + */ + Response search(Map searchQueryMap); + + /** + * @param locationId + * @return response Response + */ + Response read(String locationId); + + /** + * @param queryMap + * @return response Response + */ + Response getRecordByProperty(Map queryMap); +} diff --git a/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/impl/LocationDaoFactory.java b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/impl/LocationDaoFactory.java new file mode 100644 index 0000000000..88587488f6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/impl/LocationDaoFactory.java @@ -0,0 +1,25 @@ +package org.sunbird.location.dao.impl; + +import org.sunbird.location.dao.LocationDao; + +/** @author Amit Kumar */ +public class LocationDaoFactory { + + /** private default constructor. */ + private LocationDaoFactory() {} + + private static LocationDao locationDao; + + static { + locationDao = new LocationDaoImpl(); + } + + /** + * This method will provide singleton instance for LocationDaoImpl. + * + * @return LocationDao + */ + public static LocationDao getInstance() { + return locationDao; + } +} diff --git a/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/impl/LocationDaoImpl.java b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/impl/LocationDaoImpl.java new file mode 100644 index 0000000000..c9d8518aca --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/dao/impl/LocationDaoImpl.java @@ -0,0 +1,105 @@ +package org.sunbird.location.dao.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.location.dao.LocationDao; +import org.sunbird.models.location.Location; +import scala.concurrent.Future; + +/** @author Amit Kumar */ +public class LocationDaoImpl implements LocationDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ObjectMapper mapper = new ObjectMapper(); + private static final String KEYSPACE_NAME = "sunbird"; + private static final String LOCATION_TABLE_NAME = "location"; + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + private static final String DEFAULT_SORT_BY = "ASC"; + + @Override + public Response create(Location location) { + Map map = mapper.convertValue(location, Map.class); + Response response = cassandraOperation.insertRecord(KEYSPACE_NAME, LOCATION_TABLE_NAME, map); + // need to send ID along with success msg + response.put(JsonKey.ID, map.get(JsonKey.ID)); + return response; + } + + @Override + public Response update(Location location) { + Map map = mapper.convertValue(location, Map.class); + return cassandraOperation.updateRecord(KEYSPACE_NAME, LOCATION_TABLE_NAME, map); + } + + @Override + public Response delete(String locationId) { + return cassandraOperation.deleteRecord(KEYSPACE_NAME, LOCATION_TABLE_NAME, locationId); + } + + @Override + public Response search(Map searchQueryMap) { + SearchDTO searchDto = Util.createSearchDto(searchQueryMap); + addSortBy(searchDto); + String type = ProjectUtil.EsType.location.getTypeName(); + Future> resultF = esUtil.search(searchDto, type); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + Response response = new Response(); + if (result != null) { + response.put(JsonKey.COUNT, result.get(JsonKey.COUNT)); + response.put(JsonKey.RESPONSE, result.get(JsonKey.CONTENT)); + } else { + List> list = new ArrayList<>(); + response.put(JsonKey.COUNT, list.size()); + response.put(JsonKey.RESPONSE, list); + } + return response; + } + + @Override + public Response read(String locationId) { + return cassandraOperation.getRecordById(KEYSPACE_NAME, LOCATION_TABLE_NAME, locationId); + } + + @Override + public Response getRecordByProperty(Map queryMap) { + return cassandraOperation.getRecordsByProperty( + KEYSPACE_NAME, + LOCATION_TABLE_NAME, + (String) queryMap.get(GeoLocationJsonKey.PROPERTY_NAME), + queryMap.get(GeoLocationJsonKey.PROPERTY_VALUE)); + } + + public SearchDTO addSortBy(SearchDTO searchDtO) { + if (MapUtils.isNotEmpty(searchDtO.getAdditionalProperties()) + && searchDtO.getAdditionalProperties().containsKey(JsonKey.FILTERS) + && searchDtO.getAdditionalProperties().get(JsonKey.FILTERS) instanceof Map + && ((Map) searchDtO.getAdditionalProperties().get(JsonKey.FILTERS)) + .containsKey(JsonKey.TYPE)) { + if (MapUtils.isEmpty(searchDtO.getSortBy())) { + ProjectLogger.log( + "LocationDaoImpl:search:addSortBy added sort type name attribute.", + LoggerEnum.INFO.name()); + searchDtO.getSortBy().put(JsonKey.NAME, DEFAULT_SORT_BY); + } + } + + return searchDtO; + } +} diff --git a/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/util/LocationRequestValidator.java b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/util/LocationRequestValidator.java new file mode 100644 index 0000000000..72677273b6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/main/java/org/sunbird/location/util/LocationRequestValidator.java @@ -0,0 +1,350 @@ +package org.sunbird.location.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.learner.util.Util; +import org.sunbird.location.dao.LocationDao; +import org.sunbird.location.dao.impl.LocationDaoImpl; +import org.sunbird.models.location.apirequest.UpsertLocationRequest; +import scala.concurrent.Future; + +/** @author Amit Kumar */ +public class LocationRequestValidator { + + private LocationRequestValidator() {} + + private static LocationDao locationDao = new LocationDaoImpl(); + protected static List> locationTypeGroupList = new ArrayList<>(); + protected static List typeList = new ArrayList<>(); + private static ObjectMapper mapper = new ObjectMapper(); + private static ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + + static { + List subTypeList = + Arrays.asList( + ProjectUtil.getConfigValue(GeoLocationJsonKey.SUNBIRD_VALID_LOCATION_TYPES).split(";")); + for (String str : subTypeList) { + typeList.addAll( + ((Arrays.asList(str.split(","))) + .stream() + .map( + x -> { + return x.toLowerCase(); + })) + .collect(Collectors.toList())); + locationTypeGroupList.add( + ((Arrays.asList(str.split(","))) + .stream() + .map( + x -> { + return x.toLowerCase(); + })) + .collect(Collectors.toList())); + } + } + + /** + * This method will validate location code + * + * @param code + * @return boolean + */ + public static boolean isValidLocationCode(String code) { + Map reqMap = new HashMap<>(); + reqMap.put(GeoLocationJsonKey.PROPERTY_NAME, GeoLocationJsonKey.CODE); + reqMap.put(GeoLocationJsonKey.PROPERTY_VALUE, code); + Response response = locationDao.getRecordByProperty(reqMap); + List> locationMapList = + (List>) response.get(JsonKey.RESPONSE); + return (!locationMapList.isEmpty()); + } + + /** + * This method will validate location type + * + * @param type + * @return + */ + public static boolean isValidLocationType(String type) { + if (null != type && !typeList.contains(type.toLowerCase())) { + throw new ProjectCommonException( + ResponseCode.invalidValue.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidValue.getErrorMessage(), + GeoLocationJsonKey.LOCATION_TYPE, + type, + typeList), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return true; + } + + /** + * This method will validate parentId , parentCode for given type. + * + * @param locationRequest represents the location request object which has to be validate. + * @param opType type of location. + * @return boolean If parent id and code are valid return true else false. + */ + public static boolean isValidParentIdAndCode( + UpsertLocationRequest locationRequest, String opType) { + String type = locationRequest.getType(); + if (StringUtils.isNotEmpty(type)) { + List locationTypeList = getLocationSubTypeListForType(type); + // if type is of top level then no need to validate parentCode and parentId + if (!locationTypeList.get(0).equalsIgnoreCase(type.toLowerCase())) { + // while creating new location, if locationType is not top level then type and parent id is + // mandatory + if ((StringUtils.isEmpty(locationRequest.getParentCode()) + && StringUtils.isEmpty(locationRequest.getParentId()))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + (GeoLocationJsonKey.PARENT_ID + " or " + GeoLocationJsonKey.PARENT_CODE)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } else if (locationTypeList.get(0).equalsIgnoreCase(type.toLowerCase())) { + if (StringUtils.isNotEmpty(locationRequest.getParentCode()) + || StringUtils.isNotEmpty(locationRequest.getParentId())) { + throw new ProjectCommonException( + ResponseCode.parentNotAllowed.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.parentNotAllowed.getErrorMessage(), + (GeoLocationJsonKey.PARENT_ID + " or " + GeoLocationJsonKey.PARENT_CODE)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + // if type is top level then parentCode and parentId is null + locationRequest.setParentCode(null); + locationRequest.setParentId(null); + } + } + if (StringUtils.isNotEmpty(locationRequest.getCode())) { + isValidLocationCode(locationRequest, opType); + } + validateParentIDAndParentCode(locationRequest, opType); + return true; + } + + private static List getLocationSubTypeListForType(String type) { + for (List subList : locationTypeGroupList) { + if (subList.contains(type.toLowerCase())) { + return subList; + } + } + return (new ArrayList<>()); + } + + private static void validateParentIDAndParentCode( + UpsertLocationRequest locationRequest, String opType) { + String parentCode = locationRequest.getParentCode(); + String parentId = locationRequest.getParentId(); + if (StringUtils.isNotEmpty(parentCode)) { + Map map = getLocation(parentCode); + parentId = (String) map.get(JsonKey.ID); + locationRequest.setParentId((String) map.get(JsonKey.ID)); + } + if (StringUtils.isNotEmpty(parentId)) { + String operation = GeoLocationJsonKey.PARENT_ID; + if (StringUtils.isNotEmpty(parentCode)) { + operation = GeoLocationJsonKey.PARENT_CODE; + } + Map parentLocation = getLocationById(parentId, operation); + validateParentLocationType( + mapper.convertValue(parentLocation, UpsertLocationRequest.class), + locationRequest, + opType); + } + } + + /** + * This method will validate the parent location type means parent should be only one level up + * from child. + * + * @param parentLocation represents parent location request object. + * @param location represents child location request object. + * @return boolean If child location has valid hierarchy with parent return true otherwise false. + */ + private static boolean validateParentLocationType( + UpsertLocationRequest parentLocation, UpsertLocationRequest location, String opType) { + String parentType = parentLocation.getType(); + String currentLocType = location.getType(); + Map locn = null; + if (opType.equalsIgnoreCase(JsonKey.UPDATE)) { + locn = getLocationById(location.getId(), JsonKey.LOCATION_ID); + currentLocType = (String) locn.get(GeoLocationJsonKey.LOCATION_TYPE); + } + Map currentLocTypeoOrdermap = + getLocationTypeOrderMap(currentLocType.toLowerCase()); + Map parentLocTypeoOrdermap = + getLocationTypeOrderMap(currentLocType.toLowerCase()); + if ((currentLocTypeoOrdermap.get(currentLocType.toLowerCase()) + - parentLocTypeoOrdermap.get(parentType.toLowerCase())) + != 1) { + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameter.getErrorMessage(), + (GeoLocationJsonKey.PARENT_ID + " or " + GeoLocationJsonKey.PARENT_CODE)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return false; + } + + private static Map getLocationTypeOrderMap(String type) { + List list = getLocationSubTypeListForType(type); + Map locTypeOrderMap = new LinkedHashMap<>(); + for (int i = 0; i < list.size(); i++) { + locTypeOrderMap.put(list.get(i), i); + } + return locTypeOrderMap; + } + + /** + * This method will return location details based on id + * + * @param id + * @return Map location details + */ + private static Map getLocationById(String id, String parameter) { + Future> locationF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.location.getTypeName(), id); + Map location = + (Map) ElasticSearchHelper.getResponseFromFuture(locationF); + if (MapUtils.isEmpty(location)) { + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ProjectUtil.formatMessage(ResponseCode.invalidParameter.getErrorMessage(), parameter), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return location; + } + + /** + * This method will validate location code and if code is valid will return location . + * + * @param code Value of location code we are looking for. + * @return location details Map + */ + private static Map getLocation(String code) { + Map filters = new HashMap<>(); + filters.put(GeoLocationJsonKey.CODE, code); + Map map = new HashMap<>(); + map.put(JsonKey.FILTERS, filters); + List> locationMapList = + getESSearchResult( + map, + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.location.getTypeName()); + if (CollectionUtils.isNotEmpty(locationMapList)) { + return locationMapList.get(0); + } else { + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameter.getErrorMessage(), GeoLocationJsonKey.PARENT_CODE), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * This method will check whether passed locationId is the parent of any location + * + * @param locationId + * @return boolean + */ + public static boolean isLocationHasChild(String locationId) { + Map location = getLocationById(locationId, JsonKey.LOCATION_ID); + Map locTypeoOrdermap = + getLocationTypeOrderMap( + ((String) location.get(GeoLocationJsonKey.LOCATION_TYPE)).toLowerCase()); + List list = new ArrayList<>(locTypeoOrdermap.values()); + list.sort(Comparator.reverseOrder()); + int order = + locTypeoOrdermap.get( + ((String) location.get(GeoLocationJsonKey.LOCATION_TYPE)).toLowerCase()); + // location type with last order can be deleted without validation + if (order != list.get(0)) { + Map filters = new HashMap<>(); + filters.put(GeoLocationJsonKey.PARENT_ID, location.get(JsonKey.ID)); + Map map = new HashMap<>(); + map.put(JsonKey.FILTERS, filters); + List> locationMapList = + getESSearchResult( + map, + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.location.getTypeName()); + if (CollectionUtils.isNotEmpty(locationMapList)) { + throw new ProjectCommonException( + ResponseCode.invalidLocationDeleteRequest.getErrorCode(), + ResponseCode.invalidLocationDeleteRequest.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + return true; + } + + public static List> getESSearchResult( + Map searchQueryMap, String esIndex, String esType) { + SearchDTO searchDto = Util.createSearchDto(searchQueryMap); + Future> resultF = esUtil.search(searchDto, esType); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + return (List>) result.get(JsonKey.CONTENT); + } + + public static boolean isValidLocationCode(UpsertLocationRequest locationRequest, String opType) { + Map filters = new HashMap<>(); + filters.put(GeoLocationJsonKey.CODE, locationRequest.getCode()); + Map map = new HashMap<>(); + map.put(JsonKey.FILTERS, filters); + List> locationMapList = + getESSearchResult( + map, + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.location.getTypeName()); + if (!locationMapList.isEmpty()) { + if (opType.equalsIgnoreCase(JsonKey.CREATE)) { + throw new ProjectCommonException( + ResponseCode.alreadyExists.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.alreadyExists.getErrorMessage(), + GeoLocationJsonKey.CODE, + locationRequest.getCode()), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else if (opType.equalsIgnoreCase(JsonKey.UPDATE)) { + Map locn = locationMapList.get(0); + if (!(((String) locn.get(JsonKey.ID)).equalsIgnoreCase(locationRequest.getId()))) { + throw new ProjectCommonException( + ResponseCode.alreadyExists.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.alreadyExists.getErrorMessage(), + GeoLocationJsonKey.CODE, + locationRequest.getCode()), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } + return true; + } +} diff --git a/actors/sunbird-lms-mw/actors/location/src/test/java/org/sunbird/location/actors/LocationActorTest.java b/actors/sunbird-lms-mw/actors/location/src/test/java/org/sunbird/location/actors/LocationActorTest.java new file mode 100644 index 0000000000..0ae19fe18c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/test/java/org/sunbird/location/actors/LocationActorTest.java @@ -0,0 +1,221 @@ +package org.sunbird.location.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LocationActorOperation; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + EsClientFactory.class, + ElasticSearchHelper.class +}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class LocationActorTest { + + private static final ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(LocationActor.class); + private static Map data; + private static ElasticSearchRestHighImpl esSearch; + + @BeforeClass + public static void init() { + + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(ServiceFactory.class); + CassandraOperationImpl cassandraOperation = mock(CassandraOperationImpl.class); + esSearch = mock(ElasticSearchRestHighImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esSearch); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + when(cassandraOperation.deleteRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getSuccessResponse()); + } + + @Before + public void setUp() { + + Map esRespone = new HashMap<>(); + esRespone.put(JsonKey.CONTENT, new ArrayList<>()); + esRespone.put(GeoLocationJsonKey.LOCATION_TYPE, "STATE"); + Promise> promise = Futures.promise(); + promise.success(esRespone); + + when(esSearch.search(Mockito.any(SearchDTO.class), Mockito.anyString())) + .thenReturn(promise.future()); + when(esSearch.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + data = getDataMap(); + } + + @Test + public void testCreateLocationSuccess() { + Map res = new HashMap<>(data); + res.remove(GeoLocationJsonKey.PARENT_CODE); + res.remove(GeoLocationJsonKey.PARENT_ID); + boolean result = testScenario(LocationActorOperation.CREATE_LOCATION, true, null, null); + assertTrue(result); + } + + @Test + public void testUpdateLocationSuccess() { + + boolean result = testScenario(LocationActorOperation.UPDATE_LOCATION, true, data, null); + assertTrue(result); + } + + @Test + public void testDeleteLocationSuccess() { + + boolean result = testScenario(LocationActorOperation.DELETE_LOCATION, true, data, null); + assertTrue(result); + } + + @Test + public void testSearchLocationSuccess() { + + boolean result = testScenario(LocationActorOperation.SEARCH_LOCATION, true, data, null); + assertTrue(result); + } + + @Test + public void testCreateLocationFailureWithInvalidValue() { + + data.put(GeoLocationJsonKey.LOCATION_TYPE, "anyLocationType"); + boolean result = + testScenario( + LocationActorOperation.CREATE_LOCATION, false, data, ResponseCode.invalidValue); + assertTrue(result); + } + + @Test + public void testCreateLocationFailureWithoutMandatoryParams() { + + data.put(GeoLocationJsonKey.LOCATION_TYPE, "block"); + boolean result = + testScenario( + LocationActorOperation.CREATE_LOCATION, + false, + data, + ResponseCode.mandatoryParamsMissing); + assertTrue(result); + } + + @Test + public void testCreateLocationFailureWithParentLocationNotAllowed() { + + data.put(GeoLocationJsonKey.PARENT_CODE, "anyCode"); + boolean result = + testScenario( + LocationActorOperation.CREATE_LOCATION, false, data, ResponseCode.parentNotAllowed); + assertTrue(result); + } + + @Test + public void testDeleteLocationFailureWithInvalidLocationDeleteRequest() { + Promise> promise = Futures.promise(); + promise.success(getContentMapFromES()); + when(esSearch.search(Mockito.any(SearchDTO.class), Mockito.anyString())) + .thenReturn(promise.future()); + boolean result = + testScenario( + LocationActorOperation.DELETE_LOCATION, + false, + data, + ResponseCode.invalidLocationDeleteRequest); + assertTrue(result); + } + + private Map getContentMapFromES() { + + List> lst = new ArrayList<>(); + Map innerMap = new HashMap<>(); + innerMap.put("any", "any"); + lst.add(innerMap); + Map map = new HashMap<>(); + map.put(JsonKey.CONTENT, lst); + return map; + } + + private boolean testScenario( + LocationActorOperation actorOperation, + boolean isSuccess, + Map data, + ResponseCode errorCode) { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request actorMessage = new Request(); + + if (data != null) actorMessage.getRequest().putAll(data); + actorMessage.setOperation(actorOperation.getValue()); + subject.tell(actorMessage, probe.getRef()); + + if (isSuccess) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + private static Map getDataMap() { + + data = new HashMap(); + data.put(GeoLocationJsonKey.LOCATION_TYPE, "STATE"); + data.put(GeoLocationJsonKey.CODE, "S01"); + data.put(JsonKey.NAME, "DUMMY_STATE"); + data.put(JsonKey.ID, "id_01"); + return data; + } + + private static Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/location/src/test/java/org/sunbird/location/dao/impl/LocationDaoImplTest.java b/actors/sunbird-lms-mw/actors/location/src/test/java/org/sunbird/location/dao/impl/LocationDaoImplTest.java new file mode 100644 index 0000000000..3456f5b7ce --- /dev/null +++ b/actors/sunbird-lms-mw/actors/location/src/test/java/org/sunbird/location/dao/impl/LocationDaoImplTest.java @@ -0,0 +1,48 @@ +package org.sunbird.location.dao.impl; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.dto.SearchDTO; + +public class LocationDaoImplTest { + + @Test + public void addSortBySuccess() { + LocationDaoImpl dao = new LocationDaoImpl(); + SearchDTO searchDto = createSearchDtoObj(); + searchDto = dao.addSortBy(searchDto); + Assert.assertTrue(searchDto.getSortBy().size() == 1); + } + + @Test + public void sortByNotAddedInCaseFilterWontHaveTypeKey() { + LocationDaoImpl dao = new LocationDaoImpl(); + SearchDTO searchDto = createSearchDtoObj(); + ((Map) searchDto.getAdditionalProperties().get(JsonKey.FILTERS)) + .remove(JsonKey.TYPE); + searchDto = dao.addSortBy(searchDto); + Assert.assertTrue(searchDto.getSortBy().size() == 0); + } + + @Test + public void sortByNotAddedInCasePresent() { + LocationDaoImpl dao = new LocationDaoImpl(); + SearchDTO searchDto = createSearchDtoObj(); + searchDto.getSortBy().put("some key", "DESC"); + searchDto = dao.addSortBy(searchDto); + Assert.assertTrue(searchDto.getSortBy().size() == 1); + } + + private SearchDTO createSearchDtoObj() { + SearchDTO searchDto = new SearchDTO(); + Map propertyMap = new HashMap(); + Map filterMap = new HashMap(); + filterMap.put(JsonKey.TYPE, "state"); + propertyMap.put(JsonKey.FILTERS, filterMap); + searchDto.setAdditionalProperties(propertyMap); + return searchDto; + } +} diff --git a/actors/sunbird-lms-mw/actors/organization/pom.xml b/actors/sunbird-lms-mw/actors/organization/pom.xml new file mode 100644 index 0000000000..c964763d68 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/organization/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + org.sunbird + mw-actors + 1.0-SNAPSHOT + ../pom.xml + + organization + Organization + + UTF-8 + + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + **/*Spec.java + **/*Test.java + + + + + + diff --git a/actors/sunbird-lms-mw/actors/pom.xml b/actors/sunbird-lms-mw/actors/pom.xml new file mode 100644 index 0000000000..38edc15f6b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + org.sunbird + sunbird-lms-mw + 1.0-SNAPSHOT + ../pom.xml + + mw-actors + pom + Middleware Actors + + 2.5.19 + + + common + user + organization + badge + location + systemsettings + + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/.gitignore new file mode 100644 index 0000000000..2f6bbd3b09 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/.gitignore @@ -0,0 +1,9 @@ +**/target/** +**/.project +**/.settings +/.idea +/*.iml +*.iml +*.log +**/velocity.log* +**/.DS_Store \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/pom.xml new file mode 100644 index 0000000000..d701334d5d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/pom.xml @@ -0,0 +1,87 @@ + + 4.0.0 + org.sunbird + auth-verifier + 1.0-SNAPSHOT + Sunbird Auth Verifier + + + 2.3.1 + 1.8 + 1.8 + UTF-8 + UTF-8 + 1.1.1 + + + + com.fasterxml.jackson.core + jackson-databind + 2.10.1 + + + org.sunbird + common-util + 0.0.1-SNAPSHOT + + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + **/*Spec.java + **/*Test.java + + + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/Base64Util.java b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/Base64Util.java new file mode 100644 index 0000000000..619330d242 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/Base64Util.java @@ -0,0 +1,741 @@ +package org.sunbird.auth.verifier; + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.io.UnsupportedEncodingException; + +/** + * Utilities for encoding and decoding the Base64 representation of + * binary data. See RFCs 2045 and 3548. + */ +public class Base64Util { + /** + * Default values for encoder/decoder flags. + */ + public static final int DEFAULT = 0; + + /** + * Encoder flag bit to omit the padding '=' characters at the end + * of the output (if any). + */ + public static final int NO_PADDING = 1; + + /** + * Encoder flag bit to omit all line terminators (i.e., the output + * will be on one long line). + */ + public static final int NO_WRAP = 2; + + /** + * Encoder flag bit to indicate lines should be terminated with a + * CRLF pair instead of just an LF. Has no effect if {@code + * NO_WRAP} is specified as well. + */ + public static final int CRLF = 4; + + /** + * Encoder/decoder flag bit to indicate using the "URL and + * filename safe" variant of Base64 (see RFC 3548 section 4) where + * {@code -} and {@code _} are used in place of {@code +} and + * {@code /}. + */ + public static final int URL_SAFE = 8; + + /** + * Flag to pass to {Base64OutputStream} to indicate that it + * should not close the output stream it is wrapping when it + * itself is closed. + */ + public static final int NO_CLOSE = 16; + + // -------------------------------------------------------- + // shared code + // -------------------------------------------------------- + + private Base64Util() { + } // don't instantiate + + // -------------------------------------------------------- + // decoding + // -------------------------------------------------------- + + /** + * Decode the Base64-encoded data in input and return the data in + * a new byte array. + *

+ *

The padding '=' characters at the end are considered optional, but + * if any are present, there must be the correct number of them. + * + * @param str the input String to decode, which is converted to + * bytes using the default charset + * @param flags controls certain features of the decoded output. + * Pass {@code DEFAULT} to decode standard Base64. + * @throws IllegalArgumentException if the input contains + * incorrect padding + */ + public static byte[] decode(String str, int flags) { + return decode(str.getBytes(), flags); + } + + /** + * Decode the Base64-encoded data in input and return the data in + * a new byte array. + *

+ *

The padding '=' characters at the end are considered optional, but + * if any are present, there must be the correct number of them. + * + * @param input the input array to decode + * @param flags controls certain features of the decoded output. + * Pass {@code DEFAULT} to decode standard Base64. + * @throws IllegalArgumentException if the input contains + * incorrect padding + */ + public static byte[] decode(byte[] input, int flags) { + return decode(input, 0, input.length, flags); + } + + /** + * Decode the Base64-encoded data in input and return the data in + * a new byte array. + *

+ *

The padding '=' characters at the end are considered optional, but + * if any are present, there must be the correct number of them. + * + * @param input the data to decode + * @param offset the position within the input array at which to start + * @param len the number of bytes of input to decode + * @param flags controls certain features of the decoded output. + * Pass {@code DEFAULT} to decode standard Base64. + * @throws IllegalArgumentException if the input contains + * incorrect padding + */ + public static byte[] decode(byte[] input, int offset, int len, int flags) { + // Allocate space for the most data the input could represent. + // (It could contain less if it contains whitespace, etc.) + Decoder decoder = new Decoder(flags, new byte[len * 3 / 4]); + + if (!decoder.process(input, offset, len, true)) { + throw new IllegalArgumentException("bad base-64"); + } + + // Maybe we got lucky and allocated exactly enough output space. + if (decoder.op == decoder.output.length) { + return decoder.output; + } + + // Need to shorten the array, so allocate a new one of the + // right size and copy. + byte[] temp = new byte[decoder.op]; + System.arraycopy(decoder.output, 0, temp, 0, decoder.op); + return temp; + } + + /** + * Base64-encode the given data and return a newly allocated + * String with the result. + * + * @param input the data to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static String encodeToString(byte[] input, int flags) { + try { + return new String(encode(input, flags), "US-ASCII"); + } catch (UnsupportedEncodingException e) { + // US-ASCII is guaranteed to be available. + throw new AssertionError(e); + } + } + + // -------------------------------------------------------- + // encoding + // -------------------------------------------------------- + + /** + * Base64-encode the given data and return a newly allocated + * String with the result. + * + * @param input the data to encode + * @param offset the position within the input array at which to + * start + * @param len the number of bytes of input to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static String encodeToString(byte[] input, int offset, int len, int flags) { + try { + return new String(encode(input, offset, len, flags), "US-ASCII"); + } catch (UnsupportedEncodingException e) { + // US-ASCII is guaranteed to be available. + throw new AssertionError(e); + } + } + + /** + * Base64-encode the given data and return a newly allocated + * byte[] with the result. + * + * @param input the data to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static byte[] encode(byte[] input, int flags) { + return encode(input, 0, input.length, flags); + } + + /** + * Base64-encode the given data and return a newly allocated + * byte[] with the result. + * + * @param input the data to encode + * @param offset the position within the input array at which to + * start + * @param len the number of bytes of input to encode + * @param flags controls certain features of the encoded output. + * Passing {@code DEFAULT} results in output that + * adheres to RFC 2045. + */ + public static byte[] encode(byte[] input, int offset, int len, int flags) { + Encoder encoder = new Encoder(flags, null); + + // Compute the exact length of the array we will produce. + int output_len = len / 3 * 4; + + // Account for the tail of the data and the padding bytes, if any. + if (encoder.do_padding) { + if (len % 3 > 0) { + output_len += 4; + } + } else { + switch (len % 3) { + case 0: + break; + case 1: + output_len += 2; + break; + case 2: + output_len += 3; + break; + } + } + + // Account for the newlines, if any. + if (encoder.do_newline && len > 0) { + output_len += (((len - 1) / (3 * Encoder.LINE_GROUPS)) + 1) * + (encoder.do_cr ? 2 : 1); + } + + encoder.output = new byte[output_len]; + encoder.process(input, offset, len, true); + + assert encoder.op == output_len; + + return encoder.output; + } + + /* package */ static abstract class Coder { + public byte[] output; + public int op; + + /** + * Encode/decode another block of input data. this.output is + * provided by the caller, and must be big enough to hold all + * the coded data. On exit, this.opwill be set to the length + * of the coded data. + * + * @param finish true if this is the final call to process for + * this object. Will finalize the coder state and + * include any final bytes in the output. + * @return true if the input so far is good; false if some + * error has been detected in the input stream.. + */ + public abstract boolean process(byte[] input, int offset, int len, boolean finish); + + /** + * @return the maximum number of bytes a call to process() + * could produce for the given number of input bytes. This may + * be an overestimate. + */ + public abstract int maxOutputSize(int len); + } + + /* package */ static class Decoder extends Coder { + /** + * Lookup table for turning bytes into their position in the + * Base64 alphabet. + */ + private static final int DECODE[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + + /** + * Decode lookup table for the "web safe" variant (RFC 3548 + * sec. 4) where - and _ replace + and /. + */ + private static final int DECODE_WEBSAFE[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + + /** + * Non-data values in the DECODE arrays. + */ + private static final int SKIP = -1; + private static final int EQUALS = -2; + final private int[] alphabet; + /** + * States 0-3 are reading through the next input tuple. + * State 4 is having read one '=' and expecting exactly + * one more. + * State 5 is expecting no more data or padding characters + * in the input. + * State 6 is the error state; an error has been detected + * in the input and no future input can "fix" it. + */ + private int state; // state number (0 to 6) + private int value; + + public Decoder(int flags, byte[] output) { + this.output = output; + + alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE; + state = 0; + value = 0; + } + + /** + * @return an overestimate for the number of bytes {@code + * len} bytes could decode to. + */ + public int maxOutputSize(int len) { + return len * 3 / 4 + 10; + } + + /** + * Decode another block of input data. + * + * @return true if the state machine is still healthy. false if + * bad base-64 data has been detected in the input stream. + */ + public boolean process(byte[] input, int offset, int len, boolean finish) { + if (this.state == 6) return false; + + int p = offset; + len += offset; + + // Using local variables makes the decoder about 12% + // faster than if we manipulate the member variables in + // the loop. (Even alphabet makes a measurable + // difference, which is somewhat surprising to me since + // the member variable is final.) + int state = this.state; + int value = this.value; + int op = 0; + final byte[] output = this.output; + final int[] alphabet = this.alphabet; + + while (p < len) { + // Try the fast path: we're starting a new tuple and the + // next four bytes of the input stream are all data + // bytes. This corresponds to going through states + // 0-1-2-3-0. We expect to use this method for most of + // the data. + // + // If any of the next four bytes of input are non-data + // (whitespace, etc.), value will end up negative. (All + // the non-data values in decode are small negative + // numbers, so shifting any of them up and or'ing them + // together will result in a value with its top bit set.) + // + // You can remove this whole block and the output should + // be the same, just slower. + if (state == 0) { + while (p + 4 <= len && + (value = ((alphabet[input[p] & 0xff] << 18) | + (alphabet[input[p + 1] & 0xff] << 12) | + (alphabet[input[p + 2] & 0xff] << 6) | + (alphabet[input[p + 3] & 0xff]))) >= 0) { + output[op + 2] = (byte) value; + output[op + 1] = (byte) (value >> 8); + output[op] = (byte) (value >> 16); + op += 3; + p += 4; + } + if (p >= len) break; + } + + // The fast path isn't available -- either we've read a + // partial tuple, or the next four input bytes aren't all + // data, or whatever. Fall back to the slower state + // machine implementation. + + int d = alphabet[input[p++] & 0xff]; + + switch (state) { + case 0: + if (d >= 0) { + value = d; + ++state; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + + case 1: + if (d >= 0) { + value = (value << 6) | d; + ++state; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + + case 2: + if (d >= 0) { + value = (value << 6) | d; + ++state; + } else if (d == EQUALS) { + // Emit the last (partial) output tuple; + // expect exactly one more padding character. + output[op++] = (byte) (value >> 4); + state = 4; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + + case 3: + if (d >= 0) { + // Emit the output triple and return to state 0. + value = (value << 6) | d; + output[op + 2] = (byte) value; + output[op + 1] = (byte) (value >> 8); + output[op] = (byte) (value >> 16); + op += 3; + state = 0; + } else if (d == EQUALS) { + // Emit the last (partial) output tuple; + // expect no further data or padding characters. + output[op + 1] = (byte) (value >> 2); + output[op] = (byte) (value >> 10); + op += 2; + state = 5; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + + case 4: + if (d == EQUALS) { + ++state; + } else if (d != SKIP) { + this.state = 6; + return false; + } + break; + + case 5: + if (d != SKIP) { + this.state = 6; + return false; + } + break; + } + } + + if (!finish) { + // We're out of input, but a future call could provide + // more. + this.state = state; + this.value = value; + this.op = op; + return true; + } + + // Done reading input. Now figure out where we are left in + // the state machine and finish up. + + switch (state) { + case 0: + // Output length is a multiple of three. Fine. + break; + case 1: + // Read one extra input byte, which isn't enough to + // make another output byte. Illegal. + this.state = 6; + return false; + case 2: + // Read two extra input bytes, enough to emit 1 more + // output byte. Fine. + output[op++] = (byte) (value >> 4); + break; + case 3: + // Read three extra input bytes, enough to emit 2 more + // output bytes. Fine. + output[op++] = (byte) (value >> 10); + output[op++] = (byte) (value >> 2); + break; + case 4: + // Read one padding '=' when we expected 2. Illegal. + this.state = 6; + return false; + case 5: + // Read all the padding '='s we expected and no more. + // Fine. + break; + } + + this.state = state; + this.op = op; + return true; + } + } + + /* package */ static class Encoder extends Coder { + /** + * Emit a new line every this many output tuples. Corresponds to + * a 76-character line length (the maximum allowable according to + * RFC 2045). + */ + public static final int LINE_GROUPS = 19; + + /** + * Lookup table for turning Base64 alphabet positions (6 bits) + * into output bytes. + */ + private static final byte ENCODE[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', + }; + + /** + * Lookup table for turning Base64 alphabet positions (6 bits) + * into output bytes. + */ + private static final byte ENCODE_WEBSAFE[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', + }; + final public boolean do_padding; + final public boolean do_newline; + final public boolean do_cr; + final private byte[] tail; + final private byte[] alphabet; + /* package */ int tailLen; + private int count; + + public Encoder(int flags, byte[] output) { + this.output = output; + + do_padding = (flags & NO_PADDING) == 0; + do_newline = (flags & NO_WRAP) == 0; + do_cr = (flags & CRLF) != 0; + alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE; + + tail = new byte[2]; + tailLen = 0; + + count = do_newline ? LINE_GROUPS : -1; + } + + /** + * @return an overestimate for the number of bytes {@code + * len} bytes could encode to. + */ + public int maxOutputSize(int len) { + return len * 8 / 5 + 10; + } + + public boolean process(byte[] input, int offset, int len, boolean finish) { + // Using local variables makes the encoder about 9% faster. + final byte[] alphabet = this.alphabet; + final byte[] output = this.output; + int op = 0; + int count = this.count; + + int p = offset; + len += offset; + int v = -1; + + // First we need to concatenate the tail of the previous call + // with any input bytes available now and see if we can empty + // the tail. + + switch (tailLen) { + case 0: + // There was no tail. + break; + + case 1: + if (p + 2 <= len) { + // A 1-byte tail with at least 2 bytes of + // input available now. + v = ((tail[0] & 0xff) << 16) | + ((input[p++] & 0xff) << 8) | + (input[p++] & 0xff); + tailLen = 0; + } + ; + break; + + case 2: + if (p + 1 <= len) { + // A 2-byte tail with at least 1 byte of input. + v = ((tail[0] & 0xff) << 16) | + ((tail[1] & 0xff) << 8) | + (input[p++] & 0xff); + tailLen = 0; + } + break; + } + + if (v != -1) { + output[op++] = alphabet[(v >> 18) & 0x3f]; + output[op++] = alphabet[(v >> 12) & 0x3f]; + output[op++] = alphabet[(v >> 6) & 0x3f]; + output[op++] = alphabet[v & 0x3f]; + if (--count == 0) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + count = LINE_GROUPS; + } + } + + // At this point either there is no tail, or there are fewer + // than 3 bytes of input available. + + // The main loop, turning 3 input bytes into 4 output bytes on + // each iteration. + while (p + 3 <= len) { + v = ((input[p] & 0xff) << 16) | + ((input[p + 1] & 0xff) << 8) | + (input[p + 2] & 0xff); + output[op] = alphabet[(v >> 18) & 0x3f]; + output[op + 1] = alphabet[(v >> 12) & 0x3f]; + output[op + 2] = alphabet[(v >> 6) & 0x3f]; + output[op + 3] = alphabet[v & 0x3f]; + p += 3; + op += 4; + if (--count == 0) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + count = LINE_GROUPS; + } + } + + if (finish) { + // Finish up the tail of the input. Note that we need to + // consume any bytes in tail before any bytes + // remaining in input; there should be at most two bytes + // total. + + if (p - tailLen == len - 1) { + int t = 0; + v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4; + tailLen -= t; + output[op++] = alphabet[(v >> 6) & 0x3f]; + output[op++] = alphabet[v & 0x3f]; + if (do_padding) { + output[op++] = '='; + output[op++] = '='; + } + if (do_newline) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + } + } else if (p - tailLen == len - 2) { + int t = 0; + v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) | + (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2); + tailLen -= t; + output[op++] = alphabet[(v >> 12) & 0x3f]; + output[op++] = alphabet[(v >> 6) & 0x3f]; + output[op++] = alphabet[v & 0x3f]; + if (do_padding) { + output[op++] = '='; + } + if (do_newline) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + } + } else if (do_newline && op > 0 && count != LINE_GROUPS) { + if (do_cr) output[op++] = '\r'; + output[op++] = '\n'; + } + + assert tailLen == 0; + assert p == len; + } else { + // Save the leftovers in tail to be consumed on the next + // call to encodeInternal. + + if (p == len - 1) { + tail[tailLen++] = input[p]; + } else if (p == len - 2) { + tail[tailLen++] = input[p]; + tail[tailLen++] = input[p + 1]; + } + } + + this.op = op; + this.count = count; + + return true; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/CryptoUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/CryptoUtil.java new file mode 100755 index 0000000000..d9554c4546 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/CryptoUtil.java @@ -0,0 +1,21 @@ +package org.sunbird.auth.verifier; + +import java.nio.charset.Charset; +import java.security.*; + +public class CryptoUtil { + private static final Charset US_ASCII = Charset.forName("US-ASCII"); + + public static boolean verifyRSASign(String payLoad, byte[] signature, PublicKey key, String algorithm) { + Signature sign; + try { + sign = Signature.getInstance(algorithm); + sign.initVerify(key); + sign.update(payLoad.getBytes(US_ASCII)); + return sign.verify(signature); + } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { + return false; + } + } + +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/KeyData.java b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/KeyData.java new file mode 100644 index 0000000000..db6c332085 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/KeyData.java @@ -0,0 +1,29 @@ +package org.sunbird.auth.verifier; + +import java.security.PublicKey; + +public class KeyData { + private String keyId; + private PublicKey publicKey; + + public KeyData(String keyId, PublicKey publicKey) { + this.keyId = keyId; + this.publicKey = publicKey; + } + + public String getKeyId() { + return keyId; + } + + public void setKeyId(String keyId) { + this.keyId = keyId; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/KeyManager.java b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/KeyManager.java new file mode 100644 index 0000000000..2f21498f53 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/KeyManager.java @@ -0,0 +1,64 @@ +package org.sunbird.auth.verifier; + +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +import java.io.FileInputStream; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +public class KeyManager { + + private static PropertiesCache propertiesCache = PropertiesCache.getInstance(); + + private static Map keyMap = new HashMap(); + + public static void init() { + String basePath = null; + String keyPrefix = null; + try { + ProjectLogger.log("KeyManager:init: Start", LoggerEnum.INFO.name()); + basePath = propertiesCache.getProperty(JsonKey.ACCESS_TOKEN_PUBLICKEY_BASEPATH); + keyPrefix = propertiesCache.getProperty(JsonKey.ACCESS_TOKEN_PUBLICKEY_KEYPREFIX); + int keyCount = Integer.parseInt(propertiesCache.getProperty(JsonKey.ACCESS_TOKEN_PUBLICKEY_KEYCOUNT)); + ProjectLogger.log("KeyManager:init: basePath: "+basePath+ " keyPrefix: "+keyPrefix+ " keys count: "+keyCount, LoggerEnum.INFO.name()); + for(int i = 1; i <= keyCount; i++) { + String keyId = keyPrefix + i; + keyMap.put(keyId, new KeyData(keyId, loadPublicKey(basePath + keyId))); + } + } catch (Exception e) { + ProjectLogger.log("KeyManager:init: exception in loading publickeys ", LoggerEnum.ERROR.name()); + e.printStackTrace(); + } + + } + + public static KeyData getPublicKey(String keyId) { + return keyMap.get(keyId); + } + + private static PublicKey loadPublicKey(String path) throws Exception { + FileInputStream in = new FileInputStream(path); + byte[] keyBytes = new byte[in.available()]; + in.read(keyBytes); + in.close(); + + String publicKey = new String(keyBytes, "UTF-8"); + publicKey = publicKey + .replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", ""); + keyBytes = Base64Util.decode(publicKey.getBytes("UTF-8"), Base64Util.DEFAULT); + + + X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(keyBytes); + KeyFactory kf = KeyFactory.getInstance("RSA"); + return kf.generatePublic(X509publicKey); + + } + +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/ManagedTokenValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/ManagedTokenValidator.java new file mode 100755 index 0000000000..fa16ab8e97 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/auth-verifier/src/main/java/org/sunbird/auth/verifier/ManagedTokenValidator.java @@ -0,0 +1,55 @@ +package org.sunbird.auth.verifier; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; + +import java.util.Map; + +public class ManagedTokenValidator { + + private static ObjectMapper mapper = new ObjectMapper(); + + /** managedtoken is validated and requestedByUserID, requestedForUserID values are validated aganist the managedEncToken + * @param managedEncToken + * @param requestedByUserId + * @param requestedForUserId + * @return + */ + public static String verify(String managedEncToken, String requestedByUserId, String requestedForUserId) { + boolean isValid = false; + String managedFor = JsonKey.UNAUTHORIZED; + try { + String[] tokenElements = managedEncToken.split("\\."); + String header = tokenElements[0]; + String body = tokenElements[1]; + String signature = tokenElements[2]; + String payLoad = header + JsonKey.DOT_SEPARATOR + body; + Map headerData = mapper.readValue(new String(decodeFromBase64(header)) , Map.class); + String keyId = headerData.get("kid").toString(); + ProjectLogger.log("ManagedTokenValidator:verify: keyId: "+keyId, + LoggerEnum.INFO.name()); + Map tokenBody = mapper.readValue(new String(decodeFromBase64(body)) , Map.class); + String parentId = tokenBody.get(JsonKey.PARENT_ID); + String muaId = tokenBody.get(JsonKey.SUB); + ProjectLogger.log("ManagedTokenValidator: parent uuid: " + parentId + + " managedBy uuid: " + muaId + " requestedByUserID: "+ requestedByUserId + " requestedForUserId: "+ requestedForUserId, LoggerEnum.INFO.name()); + ProjectLogger.log("ManagedTokenValidator: key modified value: " + keyId, LoggerEnum.INFO.name()); + isValid = CryptoUtil.verifyRSASign(payLoad, decodeFromBase64(signature), KeyManager.getPublicKey(keyId).getPublicKey(), JsonKey.SHA_256_WITH_RSA); + isValid &= parentId.equalsIgnoreCase(requestedByUserId) && muaId.equalsIgnoreCase(requestedForUserId); + if(isValid) { + managedFor = muaId; + } + } catch (Exception ex) { + ProjectLogger.log("Exception in ManagedTokenValidator: verify ",LoggerEnum.ERROR); + ex.printStackTrace(); + } + + return managedFor; + } + + private static byte[] decodeFromBase64(String data) { + return Base64Util.decode(data, 11); + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/pom.xml new file mode 100644 index 0000000000..dfcf6d715c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + org.sunbird + sunbird-util + 1.0-SNAPSHOT + pom + Sunbird Utils + + sunbird-cassandra-utils + sunbird-es-utils + sunbird-platform-core + sunbird-notification + auth-verifier + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/.gitignore new file mode 100644 index 0000000000..37ec9ad9d9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/.gitignore @@ -0,0 +1,8 @@ +/target/ +.classpath +.project +.settings +/bin/ + +*.iml +*.log diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/pom.xml new file mode 100644 index 0000000000..090c277df7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/pom.xml @@ -0,0 +1,116 @@ + + 4.0.0 + org.sunbird + sunbird-cassandra-utils + 1.0-SNAPSHOT + Sunbird Cassandra Utils + + + 2.3.1 + 1.8 + 1.8 + UTF-8 + UTF-8 + 1.1.1 + 3.7.0 + + + + com.datastax.cassandra + cassandra-driver-core + 3.7.0 + shaded + + + + io.netty + * + + + slf4j-log4j12 + org.slf4j + + + + + com.datastax.cassandra + cassandra-driver-mapping + ${cassandra.driver.version} + + + log4j + log4j + 1.2.17 + + + com.fasterxml.jackson.core + jackson-databind + 2.10.1 + + + org.sunbird + common-util + 0.0.1-SNAPSHOT + + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + **/*Spec.java + **/*Test.java + + + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandra/CassandraOperation.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandra/CassandraOperation.java new file mode 100644 index 0000000000..ba26cfe95d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandra/CassandraOperation.java @@ -0,0 +1,464 @@ +/** */ +package org.sunbird.cassandra; + +import com.datastax.driver.core.ResultSet; +import com.google.common.util.concurrent.FutureCallback; +import java.util.List; +import java.util.Map; +import org.sunbird.common.models.response.Response; + +/** + * @desc this interface will hold functions for cassandra db interaction + * @author Amit Kumar + */ +public interface CassandraOperation { + + /** + * @desc This method is used to insert/update record in cassandra db (if primary key exist in + * request ,it will update else will insert the record in cassandra db. By default cassandra + * insert operation does upsert operation. Upsert means that Cassandra will insert a row if a + * primary key does not exist already otherwise if primary key already exists, it will update + * that row.) + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @param request Map(i.e map of column name and their value) + * @return Response Response + */ + public Response upsertRecord(String keyspaceName, String tableName, Map request); + + /** + * @desc This method is used to insert record in cassandra db + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param request Map(i.e map of column name and their value) + * @return Response Response + */ + public Response insertRecord(String keyspaceName, String tableName, Map request); + + /** + * @desc This method is used to update record in cassandra db + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param request Map(i.e map of column name and their value) + * @return Response Response + */ + public Response updateRecord(String keyspaceName, String tableName, Map request); + + /** + * @desc This method is used to delete record in cassandra db by their primary key(identifier) + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param identifier String + * @return Response Response + */ + public Response deleteRecord(String keyspaceName, String tableName, String identifier); + + /** + * @desc This method is used to delete record in cassandra db by their primary composite key + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param compositeKeyMap Column map for composite primary key + */ + public void deleteRecord( + String keyspaceName, String tableName, Map compositeKeyMap); + + /** + * @desc This method is used to delete one or more records from Cassandra DB corresponding to + * given list of primary keys + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param identifierList List of primary keys of records to be deleted + * @return Status of delete records operation + */ + public boolean deleteRecords(String keyspaceName, String tableName, List identifierList); + + /** + * @desc This method is used to fetch record based on given parameter and it's value (it only + * fetch the record on indexed property or column or it will throw exception.) + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @param propertyName String + * @param propertyValue Value to be used for matching in select query + * @return Response Response + */ + public Response getRecordsByProperty( + String keyspaceName, String tableName, String propertyName, Object propertyValue); + + /** + * Fetch records with specified columns (select all if null) for given column name and value. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param propertyName Column name + * @param propertyValue Column value + * @param fields List of columns to be returned in each record + * @return Response consisting of fetched records + */ + Response getRecordsByProperty( + String keyspaceName, + String tableName, + String propertyName, + Object propertyValue, + List fields); + + /** + * @desc This method is used to fetch record based on given parameter and it's list of value (for + * In Query , for example : SELECT * FROM mykeyspace.mytable WHERE id IN (‘A’,’B’,C’) ) + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @param propertyName String + * @param propertyValueList List + * @return Response Response + */ + public Response getRecordsByProperty( + String keyspaceName, String tableName, String propertyName, List propertyValueList); + + /** + * Fetch records with specified columns (select all if null) for given column name with matching + * value in the list. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param propertyName Column name + * @param propertyValueList List of values to be used for matching in select query + * @param fields List of columns to be returned in each record + * @return Response consisting of fetched records + */ + Response getRecordsByProperty( + String keyspaceName, + String tableName, + String propertyName, + List propertyValueList, + List fields); + + /** + * Fetch records with specified indexed column + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param propertyName Indexed Column name + * @param propertyValue Value to be used for matching in select query + * @return Response consisting of fetched records + */ + Response getRecordsByIndexedProperty( + String keyspaceName, String tableName, String propertyName, Object propertyValue); + + /** + * @desc This method is used to fetch record based on given parameter list and their values + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @param propertyMap Map propertyMap)(i.e map of column name and their value) + * @return Response Response + */ + public Response getRecordsByProperties( + String keyspaceName, String tableName, Map propertyMap); + + /** + * Fetch records with specified columns (select all if null) for given column map (name, value + * pairs). + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param propertyMap Map describing columns to be used in where clause of select query. + * @param fields List of columns to be returned in each record + * @return Response consisting of fetched records + */ + Response getRecordsByProperties( + String keyspaceName, String tableName, Map propertyMap, List fields); + + /** + * @desc This method is used to fetch properties value based on id + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @param id String + * @param properties String varargs + * @return Response. + */ + public Response getPropertiesValueById( + String keyspaceName, String tableName, String id, String... properties); + + /** + * @desc This method is used to fetch all records for table(i.e Select * from tableName) + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @return Response Response + */ + public Response getAllRecords(String keyspaceName, String tableName); + + /** + * Method to update the record on basis of composite primary key. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param updateAttributes Column map to be used in set clause of update query + * @param compositeKey Column map for composite primary key + * @return Response consisting of update query status + */ + Response updateRecord( + String keyspaceName, + String tableName, + Map updateAttributes, + Map compositeKey); + + /** + * Method to get record by primary key. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param key Primary key + * @return Response consisting of matched record + */ + Response getRecordById(String keyspaceName, String tableName, String key); + + /** + * Method to get record by composite primary key. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param key Column map representing composite primary key + * @return Response consisting of matched record + */ + Response getRecordById(String keyspaceName, String tableName, Map key); + + /** + * Method to get record by primary key consisting of only specified fields (return all if null). + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param key Primary key + * @param fields List of columns to be returned in each record + * @return Response consisting of matched record + */ + Response getRecordById(String keyspaceName, String tableName, String key, List fields); + + /** + * Method to get record by composity primary key consisting of only specified fields (return all + * if null). + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param key Column map representing composite primary key + * @param fields List of columns to be returned in each record + * @return Response consisting of matched record + */ + Response getRecordById( + String keyspaceName, String tableName, Map key, List fields); + + /** + * Method to get record by primary key consisting of only specified fields (return all if null). + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param key Primary key + * @param ttlFields List of columns to be returned in each record with ttl + * @param fields List of columns to be returned in each record + * @return Response consisting of matched record + */ + Response getRecordWithTTLById( + String keyspaceName, + String tableName, + Map key, + List ttlFields, + List fields); + + /** + * Method to perform batch insert operation. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param records List of records in the batch insert operation + * @return Response indicating status of operation + */ + Response batchInsert(String keyspaceName, String tableName, List> records); + + /** + * Method to perform batch update operation. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param records List of map consisting of two maps with exactly two keys: PK: Column map for + * primary key, NonPK: Column map for properties with new values to be updated + * @return Response indicating status of operation + */ + Response batchUpdate( + String keyspaceName, String tableName, List>> records); + + Response batchUpdateById( + String keyspaceName, String tableName, List> records); + + /** + * Fetch records with composite key. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param compositeKeyMap Column map for composite primary key + * @return Response consisting of fetched records + */ + Response getRecordsByCompositeKey( + String keyspaceName, String tableName, Map compositeKeyMap); + + /** + * Fetch records with specified columns for given identifiers. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param properties List of columns to be returned in each record + * @param ids List of identifiers + * @return Response consisting of fetched records + */ + Response getRecordsByIdsWithSpecifiedColumns( + String keyspaceName, String tableName, List properties, List ids); + + /** + * Fetch records for given primary keys. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param primaryKeys List of primary key values + * @param primaryKeyColumnName Name of the primary key column + * @return Response consisting of fetched records + */ + Response getRecordsByPrimaryKeys( + String keyspaceName, String tableName, List primaryKeys, String primaryKeyColumnName); + + /** + * Insert record with TTL expiration + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param request Map consisting of column name and value + * @param ttl Time to live after which inserted record will be auto deleted + * @return Response indicating status of operation + */ + public Response insertRecordWithTTL( + String keyspaceName, String tableName, Map request, int ttl); + + /** + * Update record with TTL expiration + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param request Map consisting of column name and value + * @param ttl Time to live after which inserted record will be auto deleted + * @param compositeKey Column map for composite primary key + * @return Response indicating status of operation + */ + public Response updateRecordWithTTL( + String keyspaceName, + String tableName, + Map request, + Map compositeKey, + int ttl); + /** + * Fetch records with specified columns that match given partition / primary key. Multiple records + * would be fetched in case partition key is specified. + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param primaryKeys Column and value map for partition / primary key + * @param properties List of columns to be returned in each record + * @param ttlPropertiesWithAlias Map containing TTL column as key and alias as value. + * @return Response consisting of fetched records + */ + Response getRecordsByIdsWithSpecifiedColumnsAndTTL( + String keyspaceName, + String tableName, + Map primaryKeys, + List properties, + Map ttlPropertiesWithAlias); + + /** + * Perform batch insert with different TTL values + * + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param records List of records in the batch insert operation + * @param ttls TTL (in seconds) for each record to be inserted. TTL is ignored if value is not a + * positive number. + * @return Response indicating status of operation + */ + Response batchInsertWithTTL( + String keyspaceName, String tableName, List> records, List ttls); + + public Response getRecords( + String keyspace, String table, Map filters, List fields); + + /** + * Apply callback on cassandra async read call. + * + * @param keySpace Keyspace name + * @param table Table name + * @param filters Column and value map for filtering + * @param fields List of columns to be returned in each record + * @param callback action callback to be applied on resultset when it is returned. + */ + public void applyOperationOnRecordsAsync( + String keySpace, + String table, + Map filters, + List fields, + FutureCallback callback); + + public Response getRecordByObjectType( + String keyspace, + String tableName, + String columnName, + String key, + int value, + String objectType); + + public Response performBatchAction( + String keyspaceName, String tableName, Map inputData); + + /** + * this method will be used to do CONTAINS query in list + * + * @param keyspace + * @param tableName + * @param key + * @param Value + * @return + */ + Response searchValueInList(String keyspace, String tableName, String key, String Value); + + /** + * this method will be used to do CONTAINS query in list with the AND operations + * + * @param keyspace + * @param tableName + * @param key + * @param Value + * @param propertyMap + * @return + */ + Response searchValueInList( + String keyspace, String tableName, String key, String Value, Map propertyMap); + + /** + * @param keySpace + * @param table + * @param primaryKey + * @param column + * @param key + * @param value + * @return + */ + public Response updateAddMapRecord( + String keySpace, + String table, + Map primaryKey, + String column, + String key, + Object value); + + /** + * @param keySpace + * @param table + * @param primaryKey + * @param column + * @param key + * @return + */ + public Response updateRemoveMapRecord( + String keySpace, String table, Map primaryKey, String column, String key); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraannotation/ClusteringKey.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraannotation/ClusteringKey.java new file mode 100644 index 0000000000..6205ab46c6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraannotation/ClusteringKey.java @@ -0,0 +1,15 @@ +package org.sunbird.cassandraannotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicate the field as part of the cassandra clustering key. + * + * @author arvind. + */ +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ClusteringKey {} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraannotation/PartitioningKey.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraannotation/PartitioningKey.java new file mode 100644 index 0000000000..bf8d21c88f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraannotation/PartitioningKey.java @@ -0,0 +1,15 @@ +package org.sunbird.cassandraannotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicate the field as part of the cassandra partitioning key. + * + * @author arvind. + */ +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface PartitioningKey {} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraimpl/CassandraDACImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraimpl/CassandraDACImpl.java new file mode 100644 index 0000000000..a3688195dc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraimpl/CassandraDACImpl.java @@ -0,0 +1,162 @@ +package org.sunbird.cassandraimpl; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.ResultSetFuture; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.querybuilder.Select; +import com.datastax.driver.core.querybuilder.Update; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.Constants; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; + +public class CassandraDACImpl extends CassandraOperationImpl { + + public Response getRecords( + String keySpace, String table, Map filters, List fields) { + Response response = new Response(); + Session session = connectionManager.getSession(keySpace); + try { + Select select; + if (CollectionUtils.isNotEmpty(fields)) { + select = QueryBuilder.select((String[]) fields.toArray()).from(keySpace, table); + } else { + select = QueryBuilder.select().all().from(keySpace, table); + } + + if (MapUtils.isNotEmpty(filters)) { + Select.Where where = select.where(); + for (Map.Entry filter : filters.entrySet()) { + Object value = filter.getValue(); + if (value instanceof List) { + where = where.and(QueryBuilder.in(filter.getKey(), ((List) filter.getValue()))); + } else { + where = where.and(QueryBuilder.eq(filter.getKey(), filter.getValue())); + } + } + } + + ResultSet results = null; + results = session.execute(select); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + table + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return response; + } + + public void applyOperationOnRecordsAsync( + String keySpace, + String table, + Map filters, + List fields, + FutureCallback callback) { + Session session = connectionManager.getSession(keySpace); + try { + Select select; + if (CollectionUtils.isNotEmpty(fields)) { + select = QueryBuilder.select((String[]) fields.toArray()).from(keySpace, table); + } else { + select = QueryBuilder.select().all().from(keySpace, table); + } + + if (MapUtils.isNotEmpty(filters)) { + Select.Where where = select.where(); + for (Map.Entry filter : filters.entrySet()) { + Object value = filter.getValue(); + if (value instanceof List) { + where = where.and(QueryBuilder.in(filter.getKey(), ((List) filter.getValue()))); + } else { + where = where.and(QueryBuilder.eq(filter.getKey(), filter.getValue())); + } + } + } + ResultSetFuture future = session.executeAsync(select); + Futures.addCallback(future, callback, Executors.newFixedThreadPool(1)); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + table + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + public Response updateAddMapRecord( + String keySpace, + String table, + Map primaryKey, + String column, + String key, + Object value) { + return updateMapRecord(keySpace, table, primaryKey, column, key, value, true); + } + + public Response updateRemoveMapRecord( + String keySpace, String table, Map primaryKey, String column, String key) { + return updateMapRecord(keySpace, table, primaryKey, column, key, null, false); + } + + public Response updateMapRecord( + String keySpace, + String table, + Map primaryKey, + String column, + String key, + Object value, + boolean add) { + Update update = QueryBuilder.update(keySpace, table); + if (add) { + update.with(QueryBuilder.put(column, key, value)); + } else { + update.with(QueryBuilder.remove(column, key)); + } + if (MapUtils.isEmpty(primaryKey)) { + ProjectLogger.log( + Constants.EXCEPTION_MSG_FETCH + table + " : primary key is a must for update call", + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + Update.Where where = update.where(); + for (Map.Entry filter : primaryKey.entrySet()) { + Object filterValue = filter.getValue(); + if (filterValue instanceof List) { + where = where.and(QueryBuilder.in(filter.getKey(), ((List) filter.getValue()))); + } else { + where = where.and(QueryBuilder.eq(filter.getKey(), filter.getValue())); + } + } + try { + Response response = new Response(); + ProjectLogger.log("Remove Map-Key Query: " + update.toString(), LoggerEnum.INFO); + connectionManager.getSession(keySpace).execute(update); + response.put(Constants.RESPONSE, Constants.SUCCESS); + return response; + } catch (Exception e) { + e.printStackTrace(); + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + table + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraimpl/CassandraOperationImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraimpl/CassandraOperationImpl.java new file mode 100644 index 0000000000..b17b6ac99d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/cassandraimpl/CassandraOperationImpl.java @@ -0,0 +1,1205 @@ +package org.sunbird.cassandraimpl; + +import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; + +import com.datastax.driver.core.BatchStatement; +import com.datastax.driver.core.BoundStatement; +import com.datastax.driver.core.PreparedStatement; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.Statement; +import com.datastax.driver.core.exceptions.NoHostAvailableException; +import com.datastax.driver.core.exceptions.QueryExecutionException; +import com.datastax.driver.core.exceptions.QueryValidationException; +import com.datastax.driver.core.querybuilder.*; +import com.datastax.driver.core.querybuilder.Select.Builder; +import com.datastax.driver.core.querybuilder.Select.Selection; +import com.datastax.driver.core.querybuilder.Select.Where; +import com.datastax.driver.core.querybuilder.Update.Assignments; +import com.google.common.util.concurrent.FutureCallback; +import java.text.MessageFormat; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.Constants; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.CassandraConnectionManager; +import org.sunbird.helper.CassandraConnectionMngrFactory; + +/** + * @author Amit Kumar + * @desc this class will hold functions for cassandra db interaction + */ +public abstract class CassandraOperationImpl implements CassandraOperation { + + protected CassandraConnectionManager connectionManager; + + public CassandraOperationImpl() { + connectionManager = CassandraConnectionMngrFactory.getInstance(); + } + + @Override + public Response insertRecord(String keyspaceName, String tableName, Map request) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service insertRecord method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + String query = CassandraUtil.getPreparedStatement(keyspaceName, tableName, request); + PreparedStatement statement = connectionManager.getSession(keyspaceName).prepare(query); + BoundStatement boundStatement = new BoundStatement(statement); + Iterator iterator = request.values().iterator(); + Object[] array = new Object[request.keySet().size()]; + int i = 0; + while (iterator.hasNext()) { + array[i++] = iterator.next(); + } + connectionManager.getSession(keyspaceName).execute(boundStatement.bind(array)); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (Exception e) { + if (e.getMessage().contains(JsonKey.UNKNOWN_IDENTIFIER) + || e.getMessage().contains(JsonKey.UNDEFINED_IDENTIFIER)) { + ProjectLogger.log( + "Exception occured while inserting record to " + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + CassandraUtil.processExceptionForUnknownIdentifier(e), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + ProjectLogger.log( + "Exception occured while inserting record to " + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.dbInsertionError.getErrorCode(), + ResponseCode.dbInsertionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("insertRecord", startTime); + return response; + } + + @Override + public Response updateRecord(String keyspaceName, String tableName, Map request) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service updateRecord method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + String query = CassandraUtil.getUpdateQueryStatement(keyspaceName, tableName, request); + PreparedStatement statement = connectionManager.getSession(keyspaceName).prepare(query); + Object[] array = new Object[request.size()]; + int i = 0; + String str = ""; + int index = query.lastIndexOf(Constants.SET.trim()); + str = query.substring(index + 4); + str = str.replace(Constants.EQUAL_WITH_QUE_MARK, ""); + str = str.replace(Constants.WHERE_ID, ""); + str = str.replace(Constants.SEMICOLON, ""); + String[] arr = str.split(","); + for (String key : arr) { + array[i++] = request.get(key.trim()); + } + array[i] = request.get(Constants.IDENTIFIER); + BoundStatement boundStatement = statement.bind(array); + connectionManager.getSession(keyspaceName).execute(boundStatement); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (Exception e) { + e.printStackTrace(); + if (e.getMessage().contains(JsonKey.UNKNOWN_IDENTIFIER)) { + ProjectLogger.log( + Constants.EXCEPTION_MSG_UPDATE + tableName + " : " + e.getMessage(), + e, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + CassandraUtil.processExceptionForUnknownIdentifier(e), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + ProjectLogger.log( + Constants.EXCEPTION_MSG_UPDATE + tableName + " : " + e.getMessage(), + e, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.dbUpdateError.getErrorCode(), + ResponseCode.dbUpdateError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("updateRecord", startTime); + return response; + } + + @Override + public Response deleteRecord(String keyspaceName, String tableName, String identifier) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service deleteRecord method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + Delete.Where delete = + QueryBuilder.delete() + .from(keyspaceName, tableName) + .where(eq(Constants.IDENTIFIER, identifier)); + connectionManager.getSession(keyspaceName).execute(delete); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_DELETE + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("deleteRecord", startTime); + return response; + } + + @Override + public Response getRecordsByProperty( + String keyspaceName, String tableName, String propertyName, Object propertyValue) { + return getRecordsByProperty(keyspaceName, tableName, propertyName, propertyValue, null); + } + + @Override + public Response getRecordsByProperty( + String keyspaceName, + String tableName, + String propertyName, + Object propertyValue, + List fields) { + Response response = new Response(); + Session session = connectionManager.getSession(keyspaceName); + try { + Builder selectBuilder; + if (CollectionUtils.isNotEmpty(fields)) { + selectBuilder = QueryBuilder.select((String[]) fields.toArray()); + } else { + selectBuilder = QueryBuilder.select().all(); + } + Statement selectStatement = + selectBuilder.from(keyspaceName, tableName).where(eq(propertyName, propertyValue)); + ResultSet results = null; + results = session.execute(selectStatement); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return response; + } + + @Override + public Response getRecordsByProperty( + String keyspaceName, String tableName, String propertyName, List propertyValueList) { + return getRecordsByProperty(keyspaceName, tableName, propertyName, propertyValueList, null); + } + + @Override + public Response getRecordsByProperty( + String keyspaceName, + String tableName, + String propertyName, + List propertyValueList, + List fields) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service getRecordsByProperty method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + Builder selectBuilder; + if (CollectionUtils.isNotEmpty(fields)) { + selectBuilder = QueryBuilder.select(fields.toArray(new String[fields.size()])); + } else { + selectBuilder = QueryBuilder.select().all(); + } + Statement selectStatement = + selectBuilder + .from(keyspaceName, tableName) + .where(QueryBuilder.in(propertyName, propertyValueList)); + ResultSet results = connectionManager.getSession(keyspaceName).execute(selectStatement); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordsByProperty", startTime); + return response; + } + + @Override + public Response getRecordsByProperties( + String keyspaceName, String tableName, Map propertyMap) { + return getRecordsByProperties(keyspaceName, tableName, propertyMap, null); + } + + @Override + public Response getRecordsByProperties( + String keyspaceName, String tableName, Map propertyMap, List fields) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service getRecordsByProperties method started at ==" + startTime, + LoggerEnum.INFO); + Response response = new Response(); + try { + Builder selectBuilder; + if (CollectionUtils.isNotEmpty(fields)) { + String[] dbFields = fields.toArray(new String[fields.size()]); + selectBuilder = QueryBuilder.select(dbFields); + } else { + selectBuilder = QueryBuilder.select().all(); + } + Select selectQuery = selectBuilder.from(keyspaceName, tableName); + if (MapUtils.isNotEmpty(propertyMap)) { + Where selectWhere = selectQuery.where(); + for (Entry entry : propertyMap.entrySet()) { + if (entry.getValue() instanceof List) { + List list = (List) entry.getValue(); + if (null != list) { + Object[] propertyValues = list.toArray(new Object[list.size()]); + Clause clause = QueryBuilder.in(entry.getKey(), propertyValues); + selectWhere.and(clause); + } + } else { + Clause clause = eq(entry.getKey(), entry.getValue()); + selectWhere.and(clause); + } + } + } + ResultSet results = + connectionManager.getSession(keyspaceName).execute(selectQuery.allowFiltering()); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordsByProperties", startTime); + return response; + } + + @Override + public Response getPropertiesValueById( + String keyspaceName, String tableName, String id, String... properties) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service getPropertiesValueById method started at ==" + startTime, + LoggerEnum.INFO); + Response response = new Response(); + try { + String selectQuery = CassandraUtil.getSelectStatement(keyspaceName, tableName, properties); + PreparedStatement statement = connectionManager.getSession(keyspaceName).prepare(selectQuery); + BoundStatement boundStatement = new BoundStatement(statement); + ResultSet results = + connectionManager.getSession(keyspaceName).execute(boundStatement.bind(id)); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getPropertiesValueById", startTime); + return response; + } + + @Override + public Response getAllRecords(String keyspaceName, String tableName) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service getAllRecords method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + Select selectQuery = QueryBuilder.select().all().from(keyspaceName, tableName); + ResultSet results = connectionManager.getSession(keyspaceName).execute(selectQuery); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getAllRecords", startTime); + return response; + } + + @Override + public Response upsertRecord(String keyspaceName, String tableName, Map request) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service upsertRecord method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + String query = CassandraUtil.getPreparedStatement(keyspaceName, tableName, request); + PreparedStatement statement = connectionManager.getSession(keyspaceName).prepare(query); + BoundStatement boundStatement = new BoundStatement(statement); + Iterator iterator = request.values().iterator(); + Object[] array = new Object[request.keySet().size()]; + int i = 0; + while (iterator.hasNext()) { + array[i++] = iterator.next(); + } + connectionManager.getSession(keyspaceName).execute(boundStatement.bind(array)); + response.put(Constants.RESPONSE, Constants.SUCCESS); + + } catch (Exception e) { + if (e.getMessage().contains(JsonKey.UNKNOWN_IDENTIFIER)) { + ProjectLogger.log(Constants.EXCEPTION_MSG_UPSERT + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + CassandraUtil.processExceptionForUnknownIdentifier(e), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + ProjectLogger.log(Constants.EXCEPTION_MSG_UPSERT + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("upsertRecord", startTime); + return response; + } + + @Override + public Response updateRecord( + String keyspaceName, + String tableName, + Map request, + Map compositeKey) { + + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service updateRecord method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + Session session = connectionManager.getSession(keyspaceName); + Update update = QueryBuilder.update(keyspaceName, tableName); + Assignments assignments = update.with(); + Update.Where where = update.where(); + request + .entrySet() + .stream() + .forEach( + x -> { + assignments.and(QueryBuilder.set(x.getKey(), x.getValue())); + }); + compositeKey + .entrySet() + .stream() + .forEach( + x -> { + where.and(eq(x.getKey(), x.getValue())); + }); + Statement updateQuery = where; + session.execute(updateQuery); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_UPDATE + tableName + " : " + e.getMessage(), e); + if (e.getMessage().contains(JsonKey.UNKNOWN_IDENTIFIER)) { + throw new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + CassandraUtil.processExceptionForUnknownIdentifier(e), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + throw new ProjectCommonException( + ResponseCode.dbUpdateError.getErrorCode(), + ResponseCode.dbUpdateError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("updateRecord", startTime); + return response; + } + + private Response getRecordByIdentifier( + String keyspaceName, String tableName, Object key, List fields) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service getRecordBy key method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + Session session = connectionManager.getSession(keyspaceName); + Builder selectBuilder; + if (CollectionUtils.isNotEmpty(fields)) { + selectBuilder = QueryBuilder.select(fields.toArray(new String[fields.size()])); + } else { + selectBuilder = QueryBuilder.select().all(); + } + Select selectQuery = selectBuilder.from(keyspaceName, tableName); + Where selectWhere = selectQuery.where(); + if (key instanceof String) { + selectWhere.and(eq(Constants.IDENTIFIER, key)); + } else if (key instanceof Map) { + Map compositeKey = (Map) key; + compositeKey + .entrySet() + .stream() + .forEach( + x -> { + CassandraUtil.createQuery(x.getKey(), x.getValue(), selectWhere); + }); + } + ResultSet results = session.execute(selectWhere); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordByIdentifier", startTime); + return response; + } + + @Override + public Response getRecordById(String keyspaceName, String tableName, String key) { + return getRecordByIdentifier(keyspaceName, tableName, key, null); + } + + @Override + public Response getRecordById(String keyspaceName, String tableName, Map key) { + return getRecordByIdentifier(keyspaceName, tableName, key, null); + } + + @Override + public Response getRecordById( + String keyspaceName, String tableName, String key, List fields) { + return getRecordByIdentifier(keyspaceName, tableName, key, fields); + } + + @Override + public Response getRecordById( + String keyspaceName, String tableName, Map key, List fields) { + return getRecordByIdentifier(keyspaceName, tableName, key, fields); + } + + @Override + public Response getRecordWithTTLById( + String keyspaceName, + String tableName, + Map key, + List ttlFields, + List fields) { + return getRecordWithTTLByIdentifier(keyspaceName, tableName, key, ttlFields, fields); + } + + public Response getRecordWithTTLByIdentifier( + String keyspaceName, + String tableName, + Map key, + List ttlFields, + List fields) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service getRecordBy key method started at ==" + startTime, + LoggerEnum.INFO.name()); + Response response = new Response(); + try { + Session session = connectionManager.getSession(keyspaceName); + Selection select = QueryBuilder.select(); + for (String field : fields) { + select.column(field); + } + for (String field : ttlFields) { + select.ttl(field).as(field + "_ttl"); + } + Select.Where selectWhere = select.from(keyspaceName, tableName).where(); + key.entrySet() + .stream() + .forEach( + x -> { + selectWhere.and(QueryBuilder.eq(x.getKey(), x.getValue())); + }); + + ResultSet results = session.execute(selectWhere); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordByIdentifier", startTime); + return response; + } + + @Override + public Response batchInsert( + String keyspaceName, String tableName, List> records) { + + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service batchInsert method started at ==" + startTime, LoggerEnum.INFO); + + Session session = connectionManager.getSession(keyspaceName); + Response response = new Response(); + BatchStatement batchStatement = new BatchStatement(); + ResultSet resultSet = null; + + try { + for (Map map : records) { + Insert insert = QueryBuilder.insertInto(keyspaceName, tableName); + map.entrySet() + .stream() + .forEach( + x -> { + insert.value(x.getKey(), x.getValue()); + }); + batchStatement.add(insert); + } + resultSet = session.execute(batchStatement); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (QueryExecutionException + | QueryValidationException + | NoHostAvailableException + | IllegalStateException e) { + ProjectLogger.log("Cassandra Batch Insert Failed." + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("batchInsert", startTime); + return response; + } + + /** + * This method updates all the records in a batch + * + * @param keyspaceName + * @param tableName + * @param records + * @return + */ + // @Override + public Response batchUpdateById( + String keyspaceName, String tableName, List> records) { + + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service batchUpdateById method started at ==" + startTime, LoggerEnum.INFO); + Session session = connectionManager.getSession(keyspaceName); + Response response = new Response(); + BatchStatement batchStatement = new BatchStatement(); + ResultSet resultSet = null; + + try { + for (Map map : records) { + Update update = createUpdateStatement(keyspaceName, tableName, map); + batchStatement.add(update); + } + resultSet = session.execute(batchStatement); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (QueryExecutionException + | QueryValidationException + | NoHostAvailableException + | IllegalStateException e) { + ProjectLogger.log("Cassandra Batch Update Failed." + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("batchUpdateById", startTime); + return response; + } + + /** + * This method performs batch operations of insert and update on a same table, further other + * operations can be added to if it is necessary. + * + * @param keySpaceName + * @param tableName + * @param inputData + * @return + */ + @Override + public Response performBatchAction( + String keySpaceName, String tableName, Map inputData) { + + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service performBatchAction method started at ==" + startTime, + LoggerEnum.INFO.name()); + + Session session = connectionManager.getSession(keySpaceName); + Response response = new Response(); + BatchStatement batchStatement = new BatchStatement(); + ResultSet resultSet = null; + try { + inputData.forEach( + (key, inputMap) -> { + Map record = (Map) inputMap; + if (key.equals(JsonKey.INSERT)) { + Insert insert = createInsertStatement(keySpaceName, tableName, record); + batchStatement.add(insert); + } else if (key.equals(JsonKey.UPDATE)) { + Update update = createUpdateStatement(keySpaceName, tableName, record); + batchStatement.add(update); + } + }); + resultSet = session.execute(batchStatement); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (QueryExecutionException + | QueryValidationException + | NoHostAvailableException + | IllegalStateException e) { + ProjectLogger.log( + "Cassandra performBatchAction Failed." + e.getMessage(), LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("performBatchAction", startTime); + return response; + } + + private Insert createInsertStatement( + String keySpaceName, String tableName, Map record) { + Insert insert = QueryBuilder.insertInto(keySpaceName, tableName); + record + .entrySet() + .stream() + .forEach( + x -> { + insert.value(x.getKey(), x.getValue()); + }); + return insert; + } + + private Update createUpdateStatement( + String keySpaceName, String tableName, Map record) { + Update update = QueryBuilder.update(keySpaceName, tableName); + Assignments assignments = update.with(); + Update.Where where = update.where(); + record + .entrySet() + .stream() + .forEach( + x -> { + if (Constants.ID.equals(x.getKey())) { + where.and(eq(x.getKey(), x.getValue())); + } else { + assignments.and(QueryBuilder.set(x.getKey(), x.getValue())); + } + }); + return update; + } + + @Override + public Response batchUpdate( + String keyspaceName, String tableName, List>> list) { + + Session session = connectionManager.getSession(keyspaceName); + BatchStatement batchStatement = new BatchStatement(); + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Cassandra Service batchUpdate method started at ==" + startTime, LoggerEnum.INFO); + Response response = new Response(); + ResultSet resultSet = null; + try { + for (Map> record : list) { + Map primaryKey = record.get(JsonKey.PRIMARY_KEY); + Map nonPKRecord = record.get(JsonKey.NON_PRIMARY_KEY); + batchStatement.add( + CassandraUtil.createUpdateQuery(primaryKey, nonPKRecord, keyspaceName, tableName)); + } + resultSet = session.execute(batchStatement); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (Exception ex) { + ProjectLogger.log("Cassandra Batch Update failed " + ex.getMessage(), ex); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("batchUpdate", startTime); + return response; + } + + private void logQueryElapseTime(String operation, long startTime) { + + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + String message = + "Cassandra operation {0} started at {1} and completed at {2}. Total time elapsed is {3}."; + MessageFormat mf = new MessageFormat(message); + ProjectLogger.log( + mf.format(new Object[] {operation, startTime, stopTime, elapsedTime}), LoggerEnum.PERF_LOG); + } + + @Override + public Response getRecordsByIndexedProperty( + String keyspaceName, String tableName, String propertyName, Object propertyValue) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "CassandraOperationImpl:getRecordsByIndexedProperty called at " + startTime, + LoggerEnum.INFO); + Response response = new Response(); + try { + Select selectQuery = QueryBuilder.select().all().from(keyspaceName, tableName); + selectQuery.where().and(eq(propertyName, propertyValue)); + ResultSet results = + connectionManager.getSession(keyspaceName).execute(selectQuery.allowFiltering()); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log( + "CassandraOperationImpl:getRecordsByIndexedProperty: " + + Constants.EXCEPTION_MSG_FETCH + + tableName + + " : " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordsByIndexedProperty", startTime); + return response; + } + + @Override + public void deleteRecord( + String keyspaceName, String tableName, Map compositeKeyMap) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "CassandraOperationImpl: deleteRecord by composite key called at " + startTime, + LoggerEnum.INFO); + try { + Delete delete = QueryBuilder.delete().from(keyspaceName, tableName); + Delete.Where deleteWhere = delete.where(); + compositeKeyMap + .entrySet() + .stream() + .forEach( + x -> { + Clause clause = eq(x.getKey(), x.getValue()); + deleteWhere.and(clause); + }); + connectionManager.getSession(keyspaceName).execute(delete); + } catch (Exception e) { + ProjectLogger.log( + "CassandraOperationImpl: deleteRecord by composite key. " + + Constants.EXCEPTION_MSG_DELETE + + tableName + + " : " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("deleteRecordByCompositeKey", startTime); + } + + @Override + public boolean deleteRecords(String keyspaceName, String tableName, List identifierList) { + long startTime = System.currentTimeMillis(); + ResultSet resultSet; + ProjectLogger.log( + "CassandraOperationImpl: deleteRecords called at " + startTime, LoggerEnum.INFO); + try { + Delete delete = QueryBuilder.delete().from(keyspaceName, tableName); + Delete.Where deleteWhere = delete.where(); + Clause clause = QueryBuilder.in(JsonKey.ID, identifierList); + deleteWhere.and(clause); + resultSet = connectionManager.getSession(keyspaceName).execute(delete); + } catch (Exception e) { + ProjectLogger.log( + "CassandraOperationImpl: deleteRecords by list of primary key. " + + Constants.EXCEPTION_MSG_DELETE + + tableName + + " : " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("deleteRecords", startTime); + return resultSet.wasApplied(); + } + + @Override + public Response getRecordsByCompositeKey( + String keyspaceName, String tableName, Map compositeKeyMap) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "CassandraOperationImpl: getRecordsByCompositeKey called at " + startTime, LoggerEnum.INFO); + Response response = new Response(); + try { + Builder selectBuilder = QueryBuilder.select().all(); + Select selectQuery = selectBuilder.from(keyspaceName, tableName); + Where selectWhere = selectQuery.where(); + for (Entry entry : compositeKeyMap.entrySet()) { + Clause clause = eq(entry.getKey(), entry.getValue()); + selectWhere.and(clause); + } + ResultSet results = connectionManager.getSession(keyspaceName).execute(selectQuery); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log( + "CassandraOperationImpl:getRecordsByCompositeKey: " + + Constants.EXCEPTION_MSG_FETCH + + tableName + + " : " + + e.getMessage()); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordsByCompositeKey", startTime); + return response; + } + + @Override + public Response getRecordsByIdsWithSpecifiedColumns( + String keyspaceName, String tableName, List properties, List ids) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "CassandraOperationImpl: getRecordsByIdsWithSpecifiedColumns call started at " + startTime, + LoggerEnum.INFO); + Response response = new Response(); + try { + Builder selectBuilder; + if (CollectionUtils.isNotEmpty(properties)) { + selectBuilder = QueryBuilder.select(properties.toArray(new String[properties.size()])); + } else { + selectBuilder = QueryBuilder.select().all(); + } + response = executeSelectQuery(keyspaceName, tableName, ids, selectBuilder, ""); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordsByIdsWithSpecifiedColumns", startTime); + return response; + } + + private Response executeSelectQuery( + String keyspaceName, + String tableName, + List ids, + Builder selectBuilder, + String primaryKeyColumnName) { + Response response; + Select selectQuery = selectBuilder.from(keyspaceName, tableName); + Where selectWhere = selectQuery.where(); + Clause clause = null; + if (StringUtils.isBlank(primaryKeyColumnName)) { + clause = QueryBuilder.in(JsonKey.ID, ids.toArray(new Object[ids.size()])); + } else { + clause = QueryBuilder.in(primaryKeyColumnName, ids.toArray(new Object[ids.size()])); + } + + selectWhere.and(clause); + ResultSet results = connectionManager.getSession(keyspaceName).execute(selectQuery); + response = CassandraUtil.createResponse(results); + return response; + } + + @Override + public Response getRecordsByPrimaryKeys( + String keyspaceName, + String tableName, + List primaryKeys, + String primaryKeyColumnName) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "CassandraOperationImpl: getRecordsByPrimaryKeys call started at " + startTime, + LoggerEnum.INFO); + Response response = new Response(); + try { + Builder selectBuilder = QueryBuilder.select().all(); + response = + executeSelectQuery( + keyspaceName, tableName, primaryKeys, selectBuilder, primaryKeyColumnName); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordsByPrimaryKeys", startTime); + return response; + } + + @Override + public Response insertRecordWithTTL( + String keyspaceName, String tableName, Map request, int ttl) { + long startTime = System.currentTimeMillis(); + Insert insert = QueryBuilder.insertInto(keyspaceName, tableName); + request + .entrySet() + .stream() + .forEach( + x -> { + insert.value(x.getKey(), x.getValue()); + }); + insert.using(QueryBuilder.ttl(ttl)); + ProjectLogger.log( + "CassandraOperationImpl:insertRecordWithTTL: query = " + insert.getQueryString(), + LoggerEnum.INFO.name()); + ResultSet results = connectionManager.getSession(keyspaceName).execute(insert); + Response response = CassandraUtil.createResponse(results); + logQueryElapseTime("insertRecordWithTTL", startTime); + return response; + } + + @Override + public Response updateRecordWithTTL( + String keyspaceName, + String tableName, + Map request, + Map compositeKey, + int ttl) { + long startTime = System.currentTimeMillis(); + Session session = connectionManager.getSession(keyspaceName); + Update update = QueryBuilder.update(keyspaceName, tableName); + Assignments assignments = update.with(); + Update.Where where = update.where(); + request + .entrySet() + .stream() + .forEach( + x -> { + assignments.and(QueryBuilder.set(x.getKey(), x.getValue())); + }); + compositeKey + .entrySet() + .stream() + .forEach( + x -> { + where.and(eq(x.getKey(), x.getValue())); + }); + update.using(QueryBuilder.ttl(ttl)); + ProjectLogger.log( + "CassandraOperationImpl:updateRecordWithTTL: query = " + update.getQueryString(), + LoggerEnum.INFO.name()); + ResultSet results = session.execute(update); + Response response = CassandraUtil.createResponse(results); + logQueryElapseTime("updateRecordWithTTL", startTime); + return response; + } + + @Override + public Response getRecordsByIdsWithSpecifiedColumnsAndTTL( + String keyspaceName, + String tableName, + Map primaryKeys, + List properties, + Map ttlPropertiesWithAlias) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "CassandraOperationImpl:getRecordsByIdsWithSpecifiedColumnsAndTTL: call started at " + + startTime, + LoggerEnum.INFO); + Response response = new Response(); + try { + + Selection selection = QueryBuilder.select(); + + if (CollectionUtils.isNotEmpty(properties)) { + properties + .stream() + .forEach( + property -> { + selection.column(property); + }); + } + + if (MapUtils.isNotEmpty(ttlPropertiesWithAlias)) { + ttlPropertiesWithAlias + .entrySet() + .stream() + .forEach( + property -> { + if (StringUtils.isBlank(property.getValue())) { + ProjectLogger.log( + "CassandraOperationImpl:getRecordsByIdsWithSpecifiedColumnsAndTTL: Alias not provided for ttl key = " + + property.getKey(), + LoggerEnum.ERROR); + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); + } + selection.ttl(property.getKey()).as(property.getValue()); + }); + } + Select select = selection.from(keyspaceName, tableName); + primaryKeys + .entrySet() + .stream() + .forEach( + primaryKey -> { + select.where().and(eq(primaryKey.getKey(), primaryKey.getValue())); + }); + ProjectLogger.log("Query =" + select.getQueryString(), LoggerEnum.INFO); + ResultSet results = connectionManager.getSession(keyspaceName).execute(select); + response = CassandraUtil.createResponse(results); + } catch (Exception e) { + ProjectLogger.log(Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("getRecordsByIdsWithSpecifiedColumnsAndTTL", startTime); + return response; + } + + @Override + public Response batchInsertWithTTL( + String keyspaceName, + String tableName, + List> records, + List ttls) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "CassandraOperationImpl:batchInsertWithTTL: call started at " + startTime, LoggerEnum.INFO); + if (CollectionUtils.isEmpty(records) || CollectionUtils.isEmpty(ttls)) { + ProjectLogger.log( + "CassandraOperationImpl:batchInsertWithTTL: records or ttls is empty", LoggerEnum.ERROR); + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); + } + if (ttls.size() != records.size()) { + ProjectLogger.log( + "CassandraOperationImpl:batchInsertWithTTL: Mismatch of records and ttls list size", + LoggerEnum.ERROR); + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); + } + Session session = connectionManager.getSession(keyspaceName); + Response response = new Response(); + BatchStatement batchStatement = new BatchStatement(); + ResultSet resultSet = null; + Iterator ttlIterator = ttls.iterator(); + try { + for (Map map : records) { + Insert insert = QueryBuilder.insertInto(keyspaceName, tableName); + map.entrySet() + .stream() + .forEach( + x -> { + insert.value(x.getKey(), x.getValue()); + }); + if (ttlIterator.hasNext()) { + Integer ttlVal = ttlIterator.next(); + if (ttlVal != null & ttlVal > 0) { + insert.using(QueryBuilder.ttl(ttlVal)); + } + } + batchStatement.add(insert); + } + resultSet = session.execute(batchStatement); + response.put(Constants.RESPONSE, Constants.SUCCESS); + } catch (QueryExecutionException + | QueryValidationException + | NoHostAvailableException + | IllegalStateException e) { + ProjectLogger.log( + "CassandraOperationImpl:batchInsertWithTTL: Exception occurred with error message = " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + logQueryElapseTime("batchInsertWithTTL", startTime); + return response; + } + + @Override + public Response getRecordByObjectType( + String keyspace, + String tableName, + String columnName, + String key, + int value, + String objectType) { + Select selectQuery = QueryBuilder.select().column(columnName).from(keyspace, tableName); + Clause clause = QueryBuilder.lt(key, value); + selectQuery.where(eq(JsonKey.OBJECT_TYPE, objectType)).and(clause); + selectQuery.allowFiltering(); + ResultSet resultSet = connectionManager.getSession(keyspace).execute(selectQuery); + Response response = CassandraUtil.createResponse(resultSet); + return response; + } + + @Override + public Response getRecords( + String keyspace, String table, Map filters, List fields) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void applyOperationOnRecordsAsync( + String keySpace, + String table, + Map filters, + List fields, + FutureCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public Response searchValueInList(String keyspace, String tableName, String key, String value) { + return searchValueInList(keyspace, tableName, key, value, null); + } + + @Override + public Response searchValueInList( + String keyspace, + String tableName, + String key, + String value, + Map propertyMap) { + Select selectQuery = QueryBuilder.select().all().from(keyspace, tableName); + Clause clause = QueryBuilder.contains(key, value); + selectQuery.where(clause); + if (MapUtils.isNotEmpty(propertyMap)) { + for (Entry entry : propertyMap.entrySet()) { + if (entry.getValue() instanceof List) { + List list = (List) entry.getValue(); + if (null != list) { + Object[] propertyValues = list.toArray(new Object[list.size()]); + Clause clauseList = QueryBuilder.in(entry.getKey(), propertyValues); + selectQuery.where(clauseList); + } + } else { + Clause clauseMap = eq(entry.getKey(), entry.getValue()); + selectQuery.where(clauseMap); + } + } + } + ResultSet resultSet = connectionManager.getSession(keyspace).execute(selectQuery); + Response response = CassandraUtil.createResponse(resultSet); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/common/CassandraUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/common/CassandraUtil.java new file mode 100644 index 0000000000..0420f55a68 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/common/CassandraUtil.java @@ -0,0 +1,347 @@ +package org.sunbird.common; + +import com.datastax.driver.core.RegularStatement; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.querybuilder.Select.Where; +import com.datastax.driver.core.querybuilder.Update; +import com.datastax.driver.core.querybuilder.Update.Assignments; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import org.sunbird.cassandraannotation.ClusteringKey; +import org.sunbird.cassandraannotation.PartitioningKey; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.CassandraPropertyReader; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * @desc This class will provide all required helper method for cassandra db operation. + * @author Amit Kumar + */ +public final class CassandraUtil { + + private static final CassandraPropertyReader propertiesCache = + CassandraPropertyReader.getInstance(); + private static final String SERIAL_VERSION_UID = "serialVersionUID"; + + private CassandraUtil() {} + + /** + * @desc This method is used to create prepared statement based on table name and column name + * provided in request + * @param keyspaceName Keyspace name + * @param tableName Table name + * @param map Map where key is column name and value is column value + * @return Prepared statement + */ + public static String getPreparedStatement( + String keyspaceName, String tableName, Map map) { + StringBuilder query = new StringBuilder(); + query.append( + Constants.INSERT_INTO + keyspaceName + Constants.DOT + tableName + Constants.OPEN_BRACE); + Set keySet = map.keySet(); + query.append(String.join(",", keySet) + Constants.VALUES_WITH_BRACE); + StringBuilder commaSepValueBuilder = new StringBuilder(); + for (int i = 0; i < keySet.size(); i++) { + commaSepValueBuilder.append(Constants.QUE_MARK); + if (i != keySet.size() - 1) { + commaSepValueBuilder.append(Constants.COMMA); + } + } + query.append(commaSepValueBuilder + Constants.CLOSING_BRACE); + ProjectLogger.log(query.toString()); + return query.toString(); + } + + /** + * @desc This method is used for creating response from the resultset i.e return map + * or map + * @param results ResultSet + * @return Response Response + */ + public static Response createResponse(ResultSet results) { + Response response = new Response(); + List> responseList = new ArrayList<>(); + Map columnsMapping = fetchColumnsMapping(results); + Iterator rowIterator = results.iterator(); + rowIterator.forEachRemaining( + row -> { + Map rowMap = new HashMap<>(); + columnsMapping + .entrySet() + .stream() + .forEach(entry -> rowMap.put(entry.getKey(), row.getObject(entry.getValue()))); + responseList.add(rowMap); + }); + ProjectLogger.log(responseList.toString()); + response.put(Constants.RESPONSE, responseList); + return response; + } + + public static Map fetchColumnsMapping(ResultSet results) { + return results + .getColumnDefinitions() + .asList() + .stream() + .collect( + Collectors.toMap( + d -> propertiesCache.readProperty(d.getName()).trim(), d -> d.getName())); + } + + /** + * @desc This method is used to create update query statement based on table name and column name + * provided + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @param map Map + * @return String String + */ + public static String getUpdateQueryStatement( + String keyspaceName, String tableName, Map map) { + StringBuilder query = + new StringBuilder( + Constants.UPDATE + keyspaceName + Constants.DOT + tableName + Constants.SET); + Set key = new HashSet<>(map.keySet()); + key.remove(Constants.IDENTIFIER); + query.append(String.join(" = ? ,", key)); + query.append( + Constants.EQUAL_WITH_QUE_MARK + Constants.WHERE_ID + Constants.EQUAL_WITH_QUE_MARK); + ProjectLogger.log(query.toString()); + return query.toString(); + } + + /** + * @desc This method is used to create prepared statement based on table name and column name + * provided as varargs + * @param keyspaceName String (data base keyspace name) + * @param tableName String + * @param properties(String varargs) + * @return String String + */ + public static String getSelectStatement( + String keyspaceName, String tableName, String... properties) { + StringBuilder query = new StringBuilder(Constants.SELECT); + query.append(String.join(",", properties)); + query.append( + Constants.FROM + + keyspaceName + + Constants.DOT + + tableName + + Constants.WHERE + + Constants.IDENTIFIER + + Constants.EQUAL + + " ?; "); + ProjectLogger.log(query.toString()); + return query.toString(); + } + + public static String processExceptionForUnknownIdentifier(Exception e) { + // Unknown identifier + return ProjectUtil.formatMessage( + ResponseCode.invalidPropertyError.getErrorMessage(), + e.getMessage() + .replace(JsonKey.UNKNOWN_IDENTIFIER, "") + .replace(JsonKey.UNDEFINED_IDENTIFIER, "")) + .trim(); + } + + /** + * Method to create the update query for composite keys. Create two separate map one for primary + * key and other one for attributes which are going to set. + * + * @param clazz class of Model class corresponding to table. + * @return Map containing two submap with keys PK(containing primary key attributes) and + * NonPk(containing updatable attributes). + */ + public static Map> batchUpdateQuery(T clazz) { + Field[] fieldList = clazz.getClass().getDeclaredFields(); + + Map primaryKeyMap = new HashMap<>(); + Map nonPKMap = new HashMap<>(); + try { + for (Field field : fieldList) { + String fieldName = null; + Object fieldValue = null; + Boolean isFieldPrimaryKeyPart = false; + if (Modifier.isPrivate(field.getModifiers())) { + field.setAccessible(true); + } + Annotation[] annotations = field.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof PartitioningKey) { + isFieldPrimaryKeyPart = true; + } else if (annotation instanceof ClusteringKey) { + isFieldPrimaryKeyPart = true; + } + } + fieldName = field.getName(); + fieldValue = field.get(clazz); + if (!(fieldName.equalsIgnoreCase(SERIAL_VERSION_UID))) { + if (isFieldPrimaryKeyPart) { + primaryKeyMap.put(fieldName, fieldValue); + } else { + nonPKMap.put(fieldName, fieldValue); + } + } + } + } catch (Exception ex) { + ProjectLogger.log("Exception occurred - batchUpdateQuery", ex); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + Map> map = new HashMap<>(); + map.put(JsonKey.PRIMARY_KEY, primaryKeyMap); + map.put(JsonKey.NON_PRIMARY_KEY, nonPKMap); + return map; + } + + /** + * Method to create the composite primary key. + * + * @param clazz class of Model class corresponding to table. + * @return Map containing primary key attributes. + */ + public static Map getPrimaryKey(T clazz) { + Field[] fieldList = clazz.getClass().getDeclaredFields(); + Map primaryKeyMap = new HashMap<>(); + + try { + for (Field field : fieldList) { + String fieldName = null; + Object fieldValue = null; + Boolean isFieldPrimaryKeyPart = false; + if (Modifier.isPrivate(field.getModifiers())) { + field.setAccessible(true); + } + Annotation[] annotations = field.getDeclaredAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof PartitioningKey) { + isFieldPrimaryKeyPart = true; + } else if (annotation instanceof ClusteringKey) { + isFieldPrimaryKeyPart = true; + } + } + fieldName = field.getName(); + fieldValue = field.get(clazz); + if (!(fieldName.equalsIgnoreCase(SERIAL_VERSION_UID))) { + if (isFieldPrimaryKeyPart) { + primaryKeyMap.put(fieldName, fieldValue); + } + } + } + } catch (Exception ex) { + ProjectLogger.log("Exception occurred - getPrimaryKey", ex); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return primaryKeyMap; + } + + /** + * Method to create the where clause. + * + * @param key represents the column name. + * @param value represents the column value. + * @param where where clause. + */ + public static void createWhereQuery(String key, Object value, Where where) { + if (value instanceof Map) { + Map map = (Map) value; + map.entrySet() + .stream() + .forEach( + x -> { + if (Constants.LTE.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.lte(key, x.getValue())); + } else if (Constants.LT.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.lt(key, x.getValue())); + } else if (Constants.GTE.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.gte(key, x.getValue())); + } else if (Constants.GT.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.gt(key, x.getValue())); + } + }); + } else if (value instanceof List) { + where.and(QueryBuilder.in(key, (List) value)); + } else { + where.and(QueryBuilder.eq(key, value)); + } + } + + /** + * Method to create the cassandra update query. + * + * @param primaryKey map representing the composite primary key. + * @param nonPKRecord map contains the fields that has to update. + * @param keyspaceName cassandra keyspace name. + * @param tableName cassandra table name. + * @return RegularStatement. + */ + public static RegularStatement createUpdateQuery( + Map primaryKey, + Map nonPKRecord, + String keyspaceName, + String tableName) { + + Update update = QueryBuilder.update(keyspaceName, tableName); + Assignments assignments = update.with(); + Update.Where where = update.where(); + nonPKRecord + .entrySet() + .stream() + .forEach( + x -> { + assignments.and(QueryBuilder.set(x.getKey(), x.getValue())); + }); + primaryKey + .entrySet() + .stream() + .forEach( + x -> { + where.and(QueryBuilder.eq(x.getKey(), x.getValue())); + }); + return where; + } + + public static void createQuery(String key, Object value, Where where) { + if (value instanceof Map) { + Map map = (Map) value; + map.entrySet() + .stream() + .forEach( + x -> { + if (Constants.LTE.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.lte(key, x.getValue())); + } else if (Constants.LT.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.lt(key, x.getValue())); + } else if (Constants.GTE.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.gte(key, x.getValue())); + } else if (Constants.GT.equalsIgnoreCase(x.getKey())) { + where.and(QueryBuilder.gt(key, x.getValue())); + } + }); + } else if (value instanceof List) { + where.and(QueryBuilder.in(key, (List) value)); + } else { + where.and(QueryBuilder.eq(key, value)); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/common/Constants.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/common/Constants.java new file mode 100644 index 0000000000..3f28ea368d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/common/Constants.java @@ -0,0 +1,65 @@ +package org.sunbird.common; + +/* + * @author Amit Kumar + */ +public interface Constants { + + // CASSANDRA CONFIG PROPERTIES + public static final String CORE_CONNECTIONS_PER_HOST_FOR_LOCAL = "coreConnectionsPerHostForLocal"; + public static final String CORE_CONNECTIONS_PER_HOST_FOR_REMOTE = + "coreConnectionsPerHostForRemote"; + public static final String MAX_CONNECTIONS_PER_HOST_FOR_LOCAl = "maxConnectionsPerHostForLocal"; + public static final String MAX_CONNECTIONS_PER_HOST_FOR_REMOTE = "maxConnectionsPerHostForRemote"; + public static final String MAX_REQUEST_PER_CONNECTION = "maxRequestsPerConnection"; + public static final String HEARTBEAT_INTERVAL = "heartbeatIntervalSeconds"; + public static final String POOL_TIMEOUT = "poolTimeoutMillis"; + public static final String CONTACT_POINT = "contactPoint"; + public static final String PORT = "port"; + public static final String QUERY_LOGGER_THRESHOLD = "queryLoggerConstantThreshold"; + public static final String CASSANDRA_PROPERTIES_FILE = "cassandra.config.properties"; + + // CONSTANT + public static final String COURSE_ID = "courseId"; + public static final String USER_ID = "userId"; + public static final String CONTENT_ID = "contentId"; + public static final String IDENTIFIER = "id"; + public static final String SUCCESS = "SUCCESS"; + public static final String RESPONSE = "response"; + public static final String SESSION_IS_NULL = "cassandra session is null for this "; + public static final String CLUSTER_IS_NULL = "cassandra cluster value is null for this "; + public static final String QUE_MARK = "?"; + public static final String INSERT_INTO = "INSERT INTO "; + public static final String OPEN_BRACE_WITH_SPACE = " ("; + public static final String DOT = "."; + public static final String VALUES_WITH_BRACE = ") VALUES ("; + public static final String COMMA_WITH_SPACE = ", "; + public static final String CLOSING_BRACE = ");"; + public static final String OPEN_BRACE = "("; + public static final String COMMA = ","; + public static final String COMMA_BRAC = "),"; + public static final String UPDATE = "UPDATE "; + public static final String SET = " SET "; + public static final String WHERE = " where "; + public static final String SELECT = "SELECT "; + public static final String FROM = " FROM "; + public static final String INCORRECT_DATA = "Incorrect Data"; + public static final String EQUAL = " = "; + public static final String WHERE_ID = "where id"; + public static final String EQUAL_WITH_QUE_MARK = " = ? "; + public static final String SEMICOLON = ";"; + public static final String IF_EXISTS = " IF EXISTS;"; + public static final String ALREADY_EXIST = "Record with this primary key already exist."; + public static final String IF_NOT_EXISTS = " IF NOT EXISTS;"; + public static final String EXCEPTION_MSG_FETCH = "Exception occurred while fetching record from "; + public static final String EXCEPTION_MSG_UPSERT = + "Exception occured while upserting record from "; + public static final String EXCEPTION_MSG_DELETE = + "Exception occurred while deleting record from "; + public static final String EXCEPTION_MSG_UPDATE = "Exception occurred while updating record to "; + public static final String LTE = "<="; + public static final String LT = "<"; + public static final String GTE = ">="; + public static final String GT = ">"; + public static final String ID = "id"; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionManager.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionManager.java new file mode 100644 index 0000000000..3c56abaf8f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionManager.java @@ -0,0 +1,34 @@ +package org.sunbird.helper; + +import com.datastax.driver.core.Session; +import java.util.List; + +/** + * Interface for cassandra connection manager , implementation would be Standalone and Embedde + * cassandra connection manager . + */ +public interface CassandraConnectionManager { + + /** + * Method to create the cassandra connection . + * + * @param hosts + */ + void createConnection(String[] hosts); + + /** + * Method to get the cassandra session oject on basis of keyspace name provided . + * + * @param keyspaceName + * @return Session + */ + Session getSession(String keyspaceName); + + /** + * Method to get the cassandra cluster oject on basis of keyspace name provided . + * + * @param keyspaceName + * @return List + */ + List getTableList(String keyspaceName); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionManagerImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionManagerImpl.java new file mode 100644 index 0000000000..39e7b29b0f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionManagerImpl.java @@ -0,0 +1,162 @@ +package org.sunbird.helper; + +import com.datastax.driver.core.*; +import com.datastax.driver.core.policies.DefaultRetryPolicy; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.Constants; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.*; +import org.sunbird.common.responsecode.ResponseCode; + +public class CassandraConnectionManagerImpl implements CassandraConnectionManager { + private static Cluster cluster; + private static Map cassandraSessionMap = new ConcurrentHashMap<>(2); + + static { + registerShutDownHook(); + } + + @Override + public void createConnection(String[] hosts) { + createCassandraConnection(hosts); + } + + @Override + public Session getSession(String keyspace) { + Session session = cassandraSessionMap.get(keyspace); + if (null != session) { + return session; + } else { + Session session2 = cluster.connect(keyspace); + cassandraSessionMap.put(keyspace, session2); + return session2; + } + } + + private void createCassandraConnection(String[] hosts) { + try { + PropertiesCache cache = PropertiesCache.getInstance(); + PoolingOptions poolingOptions = new PoolingOptions(); + poolingOptions.setCoreConnectionsPerHost( + HostDistance.LOCAL, + Integer.parseInt(cache.getProperty(Constants.CORE_CONNECTIONS_PER_HOST_FOR_LOCAL))); + poolingOptions.setMaxConnectionsPerHost( + HostDistance.LOCAL, + Integer.parseInt(cache.getProperty(Constants.MAX_CONNECTIONS_PER_HOST_FOR_LOCAl))); + poolingOptions.setCoreConnectionsPerHost( + HostDistance.REMOTE, + Integer.parseInt(cache.getProperty(Constants.CORE_CONNECTIONS_PER_HOST_FOR_REMOTE))); + poolingOptions.setMaxConnectionsPerHost( + HostDistance.REMOTE, + Integer.parseInt(cache.getProperty(Constants.MAX_CONNECTIONS_PER_HOST_FOR_REMOTE))); + poolingOptions.setMaxRequestsPerConnection( + HostDistance.LOCAL, + Integer.parseInt(cache.getProperty(Constants.MAX_REQUEST_PER_CONNECTION))); + poolingOptions.setHeartbeatIntervalSeconds( + Integer.parseInt(cache.getProperty(Constants.HEARTBEAT_INTERVAL))); + poolingOptions.setPoolTimeoutMillis( + Integer.parseInt(cache.getProperty(Constants.POOL_TIMEOUT))); + + cluster = createCluster(hosts, poolingOptions); + + final Metadata metadata = cluster.getMetadata(); + String msg = String.format("Connected to cluster: %s", metadata.getClusterName()); + ProjectLogger.log(msg); + + for (final Host host : metadata.getAllHosts()) { + msg = + String.format( + "Datacenter: %s; Host: %s; Rack: %s", + host.getDatacenter(), host.getAddress(), host.getRack()); + ProjectLogger.log(msg); + } + } catch (Exception e) { + ProjectLogger.log("Error occured while creating cassandra connection :", e); + throw new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + e.getMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + private static Cluster createCluster(String[] hosts, PoolingOptions poolingOptions) { + Cluster.Builder builder = + Cluster.builder() + .addContactPoints(hosts) + .withProtocolVersion(ProtocolVersion.V3) + .withRetryPolicy(DefaultRetryPolicy.INSTANCE) + .withTimestampGenerator(new AtomicMonotonicTimestampGenerator()) + .withPoolingOptions(poolingOptions); + + ConsistencyLevel consistencyLevel = getConsistencyLevel(); + ProjectLogger.log( + "CassandraConnectionManagerImpl:createCluster: Consistency level = " + consistencyLevel, + LoggerEnum.INFO); + + if (consistencyLevel != null) { + builder.withQueryOptions(new QueryOptions().setConsistencyLevel(consistencyLevel)); + } + + return builder.build(); + } + + private static ConsistencyLevel getConsistencyLevel() { + String consistency = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_CASSANDRA_CONSISTENCY_LEVEL); + + ProjectLogger.log( + "CassandraConnectionManagerImpl:getConsistencyLevel: level = " + consistency, + LoggerEnum.INFO); + + if (StringUtils.isBlank(consistency)) return null; + + try { + return ConsistencyLevel.valueOf(consistency.toUpperCase()); + } catch (IllegalArgumentException exception) { + ProjectLogger.log( + "CassandraConnectionManagerImpl:getConsistencyLevel: Exception occurred with error message = " + + exception.getMessage(), + LoggerEnum.ERROR); + } + return null; + } + + @Override + public List getTableList(String keyspacename) { + Collection tables = cluster.getMetadata().getKeyspace(keyspacename).getTables(); + + // to convert to list of the names + return tables.stream().map(tm -> tm.getName()).collect(Collectors.toList()); + } + + /** Register the hook for resource clean up. this will be called when jvm shut down. */ + public static void registerShutDownHook() { + Runtime runtime = Runtime.getRuntime(); + runtime.addShutdownHook(new ResourceCleanUp()); + ProjectLogger.log("Cassandra ShutDownHook registered."); + } + + /** + * This class will be called by registerShutDownHook to register the call inside jvm , when jvm + * terminate it will call the run method to clean up the resource. + */ + static class ResourceCleanUp extends Thread { + @Override + public void run() { + try { + ProjectLogger.log("started resource cleanup Cassandra."); + for (Map.Entry entry : cassandraSessionMap.entrySet()) { + cassandraSessionMap.get(entry.getKey()).close(); + } + cluster.close(); + ProjectLogger.log("completed resource cleanup Cassandra."); + } catch (Exception ex) { + ProjectLogger.log("Error :", ex); + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionMngrFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionMngrFactory.java new file mode 100644 index 0000000000..4c23657488 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/CassandraConnectionMngrFactory.java @@ -0,0 +1,17 @@ +package org.sunbird.helper; + +public class CassandraConnectionMngrFactory { + + private static CassandraConnectionManager instance; + + public static CassandraConnectionManager getInstance() { + if (instance == null) { + synchronized (CassandraConnectionMngrFactory.class) { + if (instance == null) { + instance = new CassandraConnectionManagerImpl(); + } + } + } + return instance; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/ServiceFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/ServiceFactory.java new file mode 100644 index 0000000000..e2a74b9e6e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/main/java/org/sunbird/helper/ServiceFactory.java @@ -0,0 +1,31 @@ +package org.sunbird.helper; + +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraDACImpl; + +/** + * This class will provide cassandraOperationImpl instance. + * + * @author Manzarul + */ +public class ServiceFactory { + private static CassandraOperation operation = null; + + private ServiceFactory() {} + + /** + * On call of this method , it will provide a new CassandraOperationImpl instance on each call. + * + * @return + */ + public static CassandraOperation getInstance() { + if (null == operation) { + synchronized (ServiceFactory.class) { + if (null == operation) { + operation = new CassandraDACImpl(); + } + } + } + return operation; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/CassandraStandaloneTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/CassandraStandaloneTest.java new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/CassandraTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/CassandraTest.java new file mode 100644 index 0000000000..cdc1d17be6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/CassandraTest.java @@ -0,0 +1,43 @@ +/* +package org.sunbird.cassandra; + +import static org.junit.Assert.assertEquals; + +import org.junit.AfterClass; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.helper.CassandraConnectionManagerImpl; +import org.sunbird.helper.CassandraConnectionMngrFactory; + +@Ignore +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class CassandraTest { + + private static PropertiesCache cach = PropertiesCache.getInstance(); + private static String host = cach.getProperty("contactPoint"); + private static String port = cach.getProperty("port"); + private static CassandraConnectionManagerImpl connectionManager = + (CassandraConnectionManagerImpl) CassandraConnectionMngrFactory.getObject(JsonKey.EMBEDDED); + + @Test + public void testConnection() { + boolean bool = connectionManager.createConnection(host, port, "", "", "sunbird1"); + assertEquals(true, bool); + } + + @Test + public void testConnectionB() { + boolean bool = connectionManager.createConnection(host, port, "", "", "sunbird12"); + assertEquals(true, bool); + } + + @AfterClass + public static void shutdownhook() { + connectionManager.registerShutDownHook(); + } +} +*/ diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/ConnectionManagerTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/ConnectionManagerTest.java new file mode 100644 index 0000000000..4a6db628fc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandra/ConnectionManagerTest.java @@ -0,0 +1,111 @@ +/* +package org.sunbird.cassandra; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.reset; +import static org.powermock.api.mockito.PowerMockito.when; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Metadata; +import com.datastax.driver.core.Session; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.CassandraConnectionManagerImpl; +import org.sunbird.helper.CassandraConnectionMngrFactory; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +*/ +/** @author kirti. Junit test cases *//* + + @RunWith(PowerMockRunner.class) + @PrepareForTest({ + Cluster.class, + Metadata.class, + Cluster.Builder.class, + CassandraUtil.class, + CassandraConnectionMngrFactory.class, + }) + @PowerMockIgnore("javax.management.*") + public class ConnectionManagerTest { + + private static PropertiesCache cach = PropertiesCache.getInstance(); + private static String host = cach.getProperty("contactPoint"); + private static String port = cach.getProperty("port"); + private static String cassandraKeySpace = cach.getProperty("keyspace"); + private static final Cluster.Builder builder = PowerMockito.mock(Cluster.Builder.class); + private static Cluster cluster; + private static Metadata metadata; + private static Session session = PowerMockito.mock(Session.class); + + private static CassandraConnectionManagerImpl connectionManager = + (CassandraConnectionManagerImpl) + CassandraConnectionMngrFactory.getObject( + cach.getProperty(JsonKey.SUNBIRD_CASSANDRA_MODE)); + + @BeforeClass + public static void init() { + + PowerMockito.mockStatic(Cluster.class); + cluster = PowerMockito.mock(Cluster.class); + when(cluster.connect(Mockito.anyString())).thenReturn(session); + metadata = PowerMockito.mock(Metadata.class); + when(cluster.getMetadata()).thenReturn(metadata); + when(Cluster.builder()).thenReturn(builder); + when(builder.addContactPoint(Mockito.anyString())).thenReturn(builder); + when(builder.withPort(Mockito.anyInt())).thenReturn(builder); + when(builder.withProtocolVersion(Mockito.any())).thenReturn(builder); + when(builder.withRetryPolicy(Mockito.any())).thenReturn(builder); + when(builder.withTimestampGenerator(Mockito.any())).thenReturn(builder); + when(builder.withPoolingOptions(Mockito.any())).thenReturn(builder); + when(builder.build()).thenReturn(cluster); + connectionManager.createConnection(host, port, "cassandra", "password", cassandraKeySpace); + } + + @Before + public void setUp() { + + reset(session); + when(cluster.connect(Mockito.anyString())).thenReturn(session); + } + + @Test + public void testCreateConnectionSuccessWithoutUsernameAndPassword() throws Exception { + + boolean bool = connectionManager.createConnection(host, port, null, null, cassandraKeySpace); + assertEquals(true, bool); + } + + @Test + public void testCreateConnectionSuccessWithUserNameAndPassword() throws Exception { + + Boolean bool = + connectionManager.createConnection(host, port, "cassandra", "password", cassandraKeySpace); + assertEquals(true, bool); + } + + @Test + public void testCreateConnectionFailure() { + + try { + connectionManager.createConnection("127.0.0.1", "9042", "cassandra", "pass", "eySpace"); + } catch (Exception ex) { + } + assertTrue(500 == ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + */ diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandraimpl/CassandraOperationImplTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandraimpl/CassandraOperationImplTest.java new file mode 100644 index 0000000000..fb8051b632 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/java/org/sunbird/cassandraimpl/CassandraOperationImplTest.java @@ -0,0 +1,686 @@ +/* +package org.sunbird.cassandraimpl; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.reset; +import static org.powermock.api.mockito.PowerMockito.when; + +import com.datastax.driver.core.*; +import com.datastax.driver.core.querybuilder.*; +import com.google.common.util.concurrent.Uninterruptibles; +import java.text.MessageFormat; +import java.util.*; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.Constants; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.CassandraConnectionManagerImpl; +import org.sunbird.helper.CassandraConnectionMngrFactory; +import org.sunbird.helper.ServiceFactory; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +*/ +/** @author kirti. Junit test cases *//* + + @RunWith(PowerMockRunner.class) + @PrepareForTest({ + Cluster.class, + Uninterruptibles.class, + PreparedStatement.class, + BoundStatement.class, + Session.class, + Metadata.class, + CassandraConnectionMngrFactory.class, + ResultSet.class, + CassandraUtil.class, + Cluster.Builder.class, + Select.class, + Row.class, + ColumnDefinitions.class, + String.class, + Select.Where.class, + Select.Builder.class, + QueryBuilder.class, + Select.Selection.class, + Delete.Where.class, + Delete.Selection.class, + Update.class, + Update.Assignments.class, + Update.Where.class, + Using.class, + Iterator.class, + Row.class, + Select.SelectionOrAlias.class + }) + @PowerMockIgnore("javax.management.*") + public class CassandraOperationImplTest { + + private static Iterator iterator; + private static Row row; + private static Cluster cluster; + private static Update update; + private static Session session = PowerMockito.mock(Session.class); + private static PreparedStatement statement; + private static ResultSet resultSet; + private static Select selectQuery; + private static Select.Where where; + private static Delete.Where deleteWhere; + private static Select.Builder selectBuilder; + private static Metadata metadata; + private static CassandraOperation operation; + private static Map address = null; + private static Map dummyAddress = null; + private static PropertiesCache cach = PropertiesCache.getInstance(); + private static String host = cach.getProperty("contactPoint"); + private static String port = cach.getProperty("port"); + private static String cassandraKeySpace = cach.getProperty("keyspace"); + private static final Cluster.Builder builder = PowerMockito.mock(Cluster.Builder.class); + private static BoundStatement boundStatement; + private static Select.Selection selectSelection; + private static Delete.Selection deleteSelection; + private static Delete delete; + + private static KeyspaceMetadata keyspaceMetadata; + private static Map otp = null; + private static CassandraConnectionManagerImpl connectionManager = + (CassandraConnectionManagerImpl) + CassandraConnectionMngrFactory.getObject( + cach.getProperty(JsonKey.SUNBIRD_CASSANDRA_MODE)); + + @BeforeClass + public static void init() { + PowerMockito.mockStatic(Select.SelectionOrAlias.class); + PowerMockito.mockStatic(Using.class); + PowerMockito.mockStatic(Cluster.class); + PowerMockito.mockStatic(Update.Assignments.class); + PowerMockito.mockStatic(Update.Where.class); + iterator = PowerMockito.mock(Iterator.class); + cluster = PowerMockito.mock(Cluster.class); + update = PowerMockito.mock(Update.class); + when(cluster.connect(Mockito.anyString())).thenReturn(session); + metadata = PowerMockito.mock(Metadata.class); + when(cluster.getMetadata()).thenReturn(metadata); + when(Cluster.builder()).thenReturn(builder); + when(builder.addContactPoint(Mockito.anyString())).thenReturn(builder); + when(builder.withPort(Mockito.anyInt())).thenReturn(builder); + when(builder.withProtocolVersion(Mockito.any())).thenReturn(builder); + when(builder.withRetryPolicy(Mockito.any())).thenReturn(builder); + when(builder.withTimestampGenerator(Mockito.any())).thenReturn(builder); + when(builder.withPoolingOptions(Mockito.any())).thenReturn(builder); + when(builder.build()).thenReturn(cluster); + connectionManager.createConnection(host, port, "cassandra", "password", cassandraKeySpace); + } + + @Before + public void setUp() throws Exception { + + reset(session); + address = new HashMap<>(); + address.put(JsonKey.ID, "123"); + address.put(JsonKey.ADDRESS_LINE1, "Line 1"); + address.put(JsonKey.USER_ID, "USR1"); + + otp = new HashMap<>(); + otp.put(JsonKey.TYPE, "email"); + otp.put(JsonKey.KEY, "amit@example.com"); + otp.put(JsonKey.OTP, "987456"); + otp.put(JsonKey.CREATED_ON, System.currentTimeMillis()); + + dummyAddress = new HashMap<>(); + dummyAddress.put(JsonKey.ID, "12345"); + dummyAddress.put(JsonKey.ADDRESS_LINE1, "Line 111"); + dummyAddress.put(JsonKey.USER_ID, "USR111"); + dummyAddress.put("DummyColumn", "USR111"); + + statement = PowerMockito.mock(PreparedStatement.class); + selectQuery = PowerMockito.mock(Select.class); + where = PowerMockito.mock(Select.Where.class); + selectBuilder = PowerMockito.mock(Select.Builder.class); + PowerMockito.mockStatic(QueryBuilder.class); + selectSelection = PowerMockito.mock(Select.Selection.class); + deleteSelection = PowerMockito.mock(Delete.Selection.class); + deleteWhere = PowerMockito.mock(Delete.Where.class); + delete = PowerMockito.mock(Delete.class); + operation = ServiceFactory.getInstance(); + resultSet = PowerMockito.mock(ResultSet.class); + keyspaceMetadata = PowerMockito.mock(KeyspaceMetadata.class); + Update.Assignments assignments = PowerMockito.mock(Update.Assignments.class); + when(QueryBuilder.select()).thenReturn(selectSelection); + Update.Where where2 = PowerMockito.mock(Update.Where.class); + when(update.where()).thenReturn(where2); + when(QueryBuilder.update(cassandraKeySpace, "otp")).thenReturn(update); + when(update.with()).thenReturn(assignments); + when(deleteSelection.from(Mockito.anyString(), Mockito.anyString())).thenReturn(delete); + when(delete.where(QueryBuilder.eq(Constants.IDENTIFIER, "123"))).thenReturn(deleteWhere); + when(selectQuery.where()).thenReturn(where); + when(metadata.getKeyspace("sunbird")).thenReturn(keyspaceMetadata); + when(cluster.connect(Mockito.anyString())).thenReturn(session); + boundStatement = PowerMockito.mock(BoundStatement.class); + PowerMockito.whenNew(BoundStatement.class) + .withArguments(Mockito.any(PreparedStatement.class)) + .thenReturn(boundStatement); + when(session.prepare(Mockito.anyString())).thenReturn(statement); + when(selectSelection.all()).thenReturn(selectBuilder); + when(selectBuilder.from(Mockito.anyString(), Mockito.anyString())).thenReturn(selectQuery); + when(session.execute(selectQuery)).thenReturn(resultSet); + + ColumnDefinitions cd = PowerMockito.mock(ColumnDefinitions.class); + String str = "qwertypower(king"; + when(resultSet.getColumnDefinitions()).thenReturn(cd); + when(cd.toString()).thenReturn(str); + when(str.substring(8, resultSet.getColumnDefinitions().toString().length() - 1)) + .thenReturn(str); + } + + // @Test + public void testInsertRecordSuccess() throws Exception { + statement = PowerMockito.mock(PreparedStatement.class); + boundStatement = PowerMockito.mock(BoundStatement.class); + PowerMockito.whenNew(BoundStatement.class).withArguments(statement).thenReturn(boundStatement); + // when(session.execute(boundStatement.bind("123"))).thenReturn(resultSet); + Response response = operation.insertRecord(cassandraKeySpace, "address1", address); + assertEquals(ResponseCode.success.getErrorCode(), response.get("response")); + } + + // @Test + public void testInsertRecordFailure() throws Exception { + Object[] array = new Object[2]; + when(session.execute(boundStatement.bind(array))) + .thenThrow( + new ProjectCommonException( + ResponseCode.dbInsertionError.getErrorCode(), + ResponseCode.dbInsertionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.insertRecord(cassandraKeySpace, "address", address); + } catch (Exception ex) { + exception = ex; + } + assertEquals(ResponseCode.dbInsertionError.getErrorMessage(), exception.getMessage()); + } + + // @Test + public void testInsertRecordFailureWithInvalidProperty() throws Exception { + + when(session.execute(boundStatement.bind("123"))) + .thenThrow( + new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + JsonKey.UNKNOWN_IDENTIFIER, + ResponseCode.CLIENT_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.insertRecord(cassandraKeySpace, "address", address); + } catch (Exception exp) { + exception = exp; + } + Object[] args = {""}; + assertEquals( + new MessageFormat(ResponseCode.invalidPropertyError.getErrorMessage()).format(args), + exception.getMessage()); + } + + @Test + public void testUpdateRecordSuccess() { + + address.put(JsonKey.CITY, "city"); + address.put(JsonKey.ADD_TYPE, "addrType"); + + when(session.execute(boundStatement)).thenReturn(resultSet); + Response response = operation.updateRecord(cassandraKeySpace, "address", address); + assertEquals(ResponseCode.success.getErrorCode(), response.get("response")); + } + + @Test + public void testUpdateRecordWithTTLSuccess() { + when(resultSet.iterator()).thenReturn(iterator); + Map compositeKey = new HashMap<>(); + compositeKey.put(JsonKey.TYPE, JsonKey.EMAIL); + compositeKey.put(JsonKey.KEY, "amit@example.com"); + when(session.execute(update)).thenReturn(resultSet); + Response response = + operation.updateRecordWithTTL(cassandraKeySpace, "otp", otp, compositeKey, 120); + assertNotNull(response.get("response")); + } + + @Test + public void testUpdateRecordFailure() throws Exception { + + dummyAddress.put(JsonKey.CITY, "city"); + dummyAddress.put(JsonKey.ADD_TYPE, "addrType"); + + when(session.prepare(Mockito.anyString())) + .thenThrow( + new ProjectCommonException( + ResponseCode.dbUpdateError.getErrorCode(), + ResponseCode.dbUpdateError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.updateRecord(cassandraKeySpace, "address", dummyAddress); + + } catch (Exception ex) { + exception = ex; + } + assertEquals(ResponseCode.dbUpdateError.getErrorMessage(), exception.getMessage()); + } + + @Test + public void testUpdateRecordFailureWithInvalidProperty() throws Exception { + + dummyAddress.put(JsonKey.CITY, "city"); + dummyAddress.put(JsonKey.ADD_TYPE, "addrType"); + + when(session.prepare(Mockito.anyString())) + .thenThrow( + new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + JsonKey.UNKNOWN_IDENTIFIER, + ResponseCode.CLIENT_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.updateRecord(cassandraKeySpace, "address", dummyAddress); + } catch (Exception exp) { + exception = exp; + } + Object[] args = {""}; + assertEquals( + new MessageFormat(ResponseCode.invalidPropertyError.getErrorMessage()).format(args), + exception.getMessage()); + } + + @Test + public void testGetAllRecordsSuccess() throws Exception { + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + PowerMockito.whenNew(BoundStatement.class) + .withArguments(Mockito.any(PreparedStatement.class)) + .thenReturn(boundStatement); + + Response response = operation.getAllRecords(cassandraKeySpace, "address"); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetAllRecordsFailure() throws Exception { + + when(session.execute(selectQuery)) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + List rows = new ArrayList<>(); + Row row = Mockito.mock(Row.class); + rows.add(row); + when(resultSet.all()).thenReturn(rows); + + PowerMockito.whenNew(BoundStatement.class) + .withArguments(Mockito.any(PreparedStatement.class)) + .thenReturn(boundStatement); + + Throwable exception = null; + try { + operation.getAllRecords(cassandraKeySpace, "address"); + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + // @Test + public void testGetPropertiesValueSuccessById() throws Exception { + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + when(session.execute(boundStatement.bind("123"))).thenReturn(resultSet); + PowerMockito.whenNew(BoundStatement.class) + .withArguments(Mockito.any(PreparedStatement.class)) + .thenReturn(boundStatement); + Response response = + operation.getPropertiesValueById( + cassandraKeySpace, "address", "123", JsonKey.ID, JsonKey.CITY, JsonKey.ADD_TYPE); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetPropertiesValueFailureById() throws Exception { + + Throwable exception = null; + PowerMockito.whenNew(BoundStatement.class) + .withArguments(Mockito.any(PreparedStatement.class)) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + try { + operation.getPropertiesValueById( + cassandraKeySpace, "address", "123", JsonKey.ID, JsonKey.CITY, JsonKey.ADD_TYPE); + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + @Test + public void testGetRecordSuccessById() { + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + when(session.execute(boundStatement.bind("123"))).thenReturn(resultSet); + when(session.execute(where)).thenReturn(resultSet); + when(selectBuilder.from(Mockito.anyString(), Mockito.anyString())).thenReturn(selectQuery); + when(selectSelection.all()).thenReturn(selectBuilder); + + Response response = operation.getRecordById(cassandraKeySpace, "address", "123"); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetRecordWithTTLById() { + Select.SelectionOrAlias alias = PowerMockito.mock(Select.SelectionOrAlias.class); + Select select = PowerMockito.mock(Select.class); + when(selectSelection.from("sunbird", "otp")).thenReturn(select); + when(select.where()).thenReturn(where); + when(selectSelection.ttl("otp")).thenReturn(alias); + when(alias.as("otp_ttl")).thenReturn(selectSelection); + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + when(session.execute(where)).thenReturn(resultSet); + when(selectBuilder.from(Mockito.anyString(), Mockito.anyString())).thenReturn(selectQuery); + when(selectSelection.all()).thenReturn(selectBuilder); + Map key = new HashMap<>(); + key.put(JsonKey.TYPE, JsonKey.EMAIL); + key.put(JsonKey.KEY, "amit@example.com"); + List ttlFields = new ArrayList<>(); + ttlFields.add(JsonKey.OTP); + List fields = new ArrayList<>(); + fields.add(JsonKey.CREATED_ON); + fields.add(JsonKey.TYPE); + fields.add(JsonKey.OTP); + fields.add(JsonKey.KEY); + Response response = + operation.getRecordWithTTLById(cassandraKeySpace, "otp", key, ttlFields, fields); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetRecordFailureById() throws Exception { + + Throwable exception = null; + PowerMockito.whenNew(BoundStatement.class) + .withArguments(Mockito.any(PreparedStatement.class)) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + try { + operation.getRecordById(cassandraKeySpace, "address", "123"); + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + @Test + public void testGetRecordSuccessByProperties() throws Exception { + + Map map = new HashMap<>(); + map.put(JsonKey.USER_ID, "USR1"); + map.put(JsonKey.ADD_TYPE, "addrType"); + + when(session.execute(boundStatement.bind("123"))).thenReturn(resultSet); + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + + Response response = operation.getRecordsByProperties(cassandraKeySpace, "address", map); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetRecordFailureByProperties() throws Exception { + + Map map = new HashMap<>(); + map.put(JsonKey.USER_ID, "USR1"); + map.put(JsonKey.ADD_TYPE, "addrType"); + + List rows = new ArrayList<>(); + Row row = Mockito.mock(Row.class); + rows.add(row); + when(resultSet.all()).thenReturn(rows); + + when(selectSelection.all()) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.getRecordsByProperties(cassandraKeySpace, "address", map); + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + @Test + public void testGetRecordForListSuccessByProperties() throws Exception { + + List list = new ArrayList<>(); + list.add("123"); + list.add("321"); + + when(session.execute(boundStatement.bind("123"))).thenReturn(resultSet); + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + Response response = + operation.getRecordsByProperty(cassandraKeySpace, "address", JsonKey.ID, list); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetRecordForListFailreByProperties() throws Exception { + + List list = new ArrayList<>(); + list.add("123"); + list.add("321"); + + List rows = new ArrayList<>(); + Row row = Mockito.mock(Row.class); + rows.add(row); + when(resultSet.all()).thenReturn(rows); + + when(selectSelection.all()) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.getRecordsByProperty(cassandraKeySpace, "address", JsonKey.ID, list); + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + @Test + public void testGetRecordsSuccessByProperty() throws Exception { + + List rows = new ArrayList<>(); + Row row = Mockito.mock(Row.class); + rows.add(row); + when(resultSet.all()).thenReturn(rows); + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + when(session.execute(boundStatement.bind("123"))).thenReturn(resultSet); + Response response = + operation.getRecordsByProperty(cassandraKeySpace, "address", JsonKey.ADD_TYPE, "addrType"); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetRecordsFailureByProperty() throws Exception { + + List rows = new ArrayList<>(); + Row row = Mockito.mock(Row.class); + rows.add(row); + when(resultSet.all()).thenReturn(rows); + + when(selectSelection.all()) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.getRecordsByProperty(cassandraKeySpace, "address", JsonKey.ADD_TYPE, "addrType"); + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + @Test + public void testGetRecordsSuccessById() { + Iterator rowItr = Mockito.mock(Iterator.class); + Mockito.when(resultSet.iterator()).thenReturn(rowItr); + when(session.execute(where)).thenReturn(resultSet); + when(selectSelection.all()).thenReturn(selectBuilder); + + Response response = operation.getRecordById(cassandraKeySpace, "address", "123"); + assertTrue(response.getResult().size() > 0); + } + + @Test + public void testGetRecordsFailureById() throws Exception { + + List rows = new ArrayList<>(); + Row row = Mockito.mock(Row.class); + rows.add(row); + when(resultSet.all()).thenReturn(rows); + + when(selectSelection.all()) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.getRecordById(cassandraKeySpace, "address1", "123"); + + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + @Test + public void testDeleteRecordSuccess() throws Exception { + + when(QueryBuilder.delete()).thenReturn(deleteSelection); + Response response = new Response(); + response.put(JsonKey.RESPONSE, Constants.SUCCESS); + operation.deleteRecord(cassandraKeySpace, "address", "123"); + assertEquals("SUCCESS", response.get("response")); + } + + @Test + public void testDeleteRecordFailure() { + + when(QueryBuilder.delete()) + .thenThrow( + new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode())); + + Throwable exception = null; + try { + operation.deleteRecord(cassandraKeySpace, "address", "123"); + + } catch (Exception ex) { + exception = ex; + } + assertTrue( + (((ProjectCommonException) exception).getResponseCode()) + == ResponseCode.SERVER_ERROR.getResponseCode()); + } + + @Test + public void testGetTableListSuccess() throws Exception { + + Collection tables = new ArrayList<>(); + TableMetadata table = Mockito.mock(TableMetadata.class); + tables.add(table); + when(keyspaceMetadata.getTables()).thenReturn(tables); + + List tableList = connectionManager.getTableList(cassandraKeySpace); + assertTrue(tableList.size() > 0); + } + + @Test + public void testGetClusterSuccess() throws Exception { + + Cluster cluster = connectionManager.getCluster("sunbird"); + assertTrue(cluster != null); + } + + @Test + public void testGetClusterFailureWithInvalidKeySpace() { + + Throwable exception = null; + try { + connectionManager.getCluster("sun"); + } catch (Exception ex) { + exception = ex; + } + assertTrue("cassandra cluster value is null for this sun".equals(exception.getMessage())); + } + } + */ diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/resources/cassandra.config.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/resources/cassandra.config.properties new file mode 100644 index 0000000000..e2fdff8787 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/resources/cassandra.config.properties @@ -0,0 +1,13 @@ +coreConnectionsPerHostForLocal=4 +coreConnectionsPerHostForRemote=2 +maxConnectionsPerHostForLocal=10 +maxConnectionsPerHostForRemote=4 +maxRequestsPerConnection=32768 +heartbeatIntervalSeconds=60 +poolTimeoutMillis=0 +contactPoint=127.0.0.1 +port=9042 +userName=cassandra +password=password +queryLoggerConstantThreshold=300 +keyspace=sunbird \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/resources/cassandra.cql b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/resources/cassandra.cql new file mode 100644 index 0000000000..e780c1abf9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-cassandra-utils/src/test/resources/cassandra.cql @@ -0,0 +1,16 @@ +CREATE KEYSPACE IF NOT EXISTS sunbird1 WITH replication = {'class':'SimpleStrategy','replication_factor':1}; + +//to change cluster name +//UPDATE system.local SET cluster_name = 'sunbird' where key='local'; +//ALTER USER cassandra WITH PASSWORD 'password'; +USE sunbird1; + +//Address Type values(permanent, current, office, home) +CREATE TABLE IF NOT EXISTS sunbird1.address1(id text, userId text, country text,state text,city text,zipCode text,addType text,createdDate text,createdBy text,updatedDate text,updatedBy text, PRIMARY KEY (id)); +//CREATE INDEX inx_add_userid ON sunbird1.address1 (userId); +//CREATE INDEX inx_add_addType ON sunbird1.address1 (addType); + +//ALTER TABLE sunbird1.address1 ADD addressLine1 text; +//ALTER TABLE sunbird1.address1 ADD addressLine2 text; + +//ALTER TABLE sunbird1.address1 ADD isDeleted boolean; \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/.gitignore new file mode 100644 index 0000000000..55977f8f94 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/.gitignore @@ -0,0 +1,7 @@ +/target/ +.classpath +.project +.settings +/bin/ + +*.iml diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/pom.xml new file mode 100644 index 0000000000..14b2371dd6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/pom.xml @@ -0,0 +1,109 @@ + + 4.0.0 + org.sunbird + sunbird-es-utils + 1.0-SNAPSHOT + Sunbird ElasticSearch Utils + + + 2.3.1 + 1.8 + 1.8 + UTF-8 + UTF-8 + 1.1.1 + + + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + 6.3.2 + + + + org.elasticsearch.client + transport + 6.3.0 + + + org.apache.logging.log4j + log4j-api + 2.8.2 + + + org.apache.logging.log4j + log4j-core + 2.8.2 + + + org.sunbird + common-util + 0.0.1-SNAPSHOT + + + junit + junit + 4.12 + test + + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + **/*Spec.java + **/*Test.java + + + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/ElasticSearchHelper.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/ElasticSearchHelper.java new file mode 100644 index 0000000000..166f9bcc96 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/ElasticSearchHelper.java @@ -0,0 +1,790 @@ +package org.sunbird.common; + +import static org.sunbird.common.models.util.ProjectUtil.isNotNull; + +import akka.util.Timeout; +import com.typesafe.config.Config; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.lucene.search.join.ScoreMode; +import org.elasticsearch.action.search.SearchRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.ExistsQueryBuilder; +import org.elasticsearch.index.query.MatchQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.RangeQueryBuilder; +import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.index.query.TermsQueryBuilder; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; +import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket; +import org.elasticsearch.search.sort.SortOrder; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.util.ConfigUtil; +import org.sunbird.dto.SearchDTO; +import scala.concurrent.Await; +import scala.concurrent.Future; + +/** + * This class will provide all required operation for elastic search. + * + * @author arvind + * @author Manzarul + * @author mayank:github.com/iostream04 + */ +public class ElasticSearchHelper { + + public static final String LTE = "<="; + public static final String LT = "<"; + public static final String GTE = ">="; + public static final String GT = ">"; + public static final String ASC_ORDER = "ASC"; + public static final String STARTS_WITH = "startsWith"; + public static final String ENDS_WITH = "endsWith"; + public static final String SOFT_MODE = "soft"; + public static final String RAW_APPEND = ".raw"; + protected static Map indexMap = new HashMap<>(); + protected static Map typeMap = new HashMap<>(); + protected static final String ES_CONFIG_FILE = "elasticsearch.conf"; + private static Config config = ConfigUtil.getConfig(ES_CONFIG_FILE); + public static final int WAIT_TIME = 5; + public static Timeout timeout = new Timeout(WAIT_TIME, TimeUnit.SECONDS); + public static final List upsertResults = + new ArrayList<>(Arrays.asList("CREATED", "UPDATED", "NOOP")); + private static final String _DOC = "_doc"; + + private ElasticSearchHelper() {} + + /** + * This method will return the object after getting complete future. + * + * @param future + * @return Object which future inherits + */ + @SuppressWarnings("unchecked") + public static Object getResponseFromFuture(Future future) { + try { + Object result = Await.result(future, timeout.duration()); + return result; + } catch (Exception e) { + ProjectLogger.log( + "ElasticSearchHelper:getResponseFromFuture: error occured " + e, LoggerEnum.ERROR.name()); + } + return null; + } + + /** + * This method adds aggregations to the incoming SearchRequestBuilder object + * + * @param searchRequestBuilder which will be updated with facets if any present + * @param facets Facets provide aggregated data based on a search query + * @return SearchRequestBuilder + */ + public static SearchRequestBuilder addAggregations( + SearchRequestBuilder searchRequestBuilder, List> facets) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "ElasticSearchHelper:addAggregations: method started at ==" + startTime, + LoggerEnum.PERF_LOG.name()); + if (facets != null && !facets.isEmpty()) { + Map map = facets.get(0); + if (!MapUtils.isEmpty(map)) { + for (Map.Entry entry : map.entrySet()) { + + String key = entry.getKey(); + String value = entry.getValue(); + if (JsonKey.DATE_HISTOGRAM.equalsIgnoreCase(value)) { + searchRequestBuilder.addAggregation( + AggregationBuilders.dateHistogram(key) + .field(key + RAW_APPEND) + .dateHistogramInterval(DateHistogramInterval.days(1))); + + } else if (null == value) { + searchRequestBuilder.addAggregation( + AggregationBuilders.terms(key).field(key + RAW_APPEND)); + } + } + } + long elapsedTime = calculateEndTime(startTime); + ProjectLogger.log( + "ElasticSearchHelper:addAggregations method end ==" + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG.name()); + } + + return searchRequestBuilder; + } + + /** + * This method returns any constraints defined in searchDto object + * + * @param searchDTO with constraints + * @return Map for constraints present in serachDTO + */ + public static Map getConstraints(SearchDTO searchDTO) { + if (null != searchDTO.getSoftConstraints() && !searchDTO.getSoftConstraints().isEmpty()) { + return searchDTO + .getSoftConstraints() + .entrySet() + .stream() + .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().floatValue())); + } + return Collections.emptyMap(); + } + + /** + * This method return SearchRequestBuilder for transport client + * + * @param client transport client instance + * @param index to be checkout + * @return SearchRequestBuilder for a provided request + */ + public static SearchRequestBuilder getTransportSearchBuilder( + TransportClient client, String[] index) { + return client.prepareSearch().setIndices(index).setTypes(_DOC); + } + + /** + * Method to add the additional search query like range query , exists - not exist filter etc. + * + * @param query query which will be updated + * @param entry which will have key to be search and respective values + * @param constraintsMap constraints on key and values + */ + @SuppressWarnings("unchecked") + public static void addAdditionalProperties( + BoolQueryBuilder query, Entry entry, Map constraintsMap) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "ElasticSearchHelper:addAdditionalProperties: method started at ==" + startTime, + LoggerEnum.PERF_LOG.name()); + String key = entry.getKey(); + if (JsonKey.FILTERS.equalsIgnoreCase(key)) { + + Map filters = (Map) entry.getValue(); + for (Map.Entry en : filters.entrySet()) { + query = createFilterESOpperation(en, query, constraintsMap); + } + } else if (JsonKey.EXISTS.equalsIgnoreCase(key) || JsonKey.NOT_EXISTS.equalsIgnoreCase(key)) { + query = createESOpperation(entry, query, constraintsMap); + } else if (JsonKey.NESTED_EXISTS.equalsIgnoreCase(key) + || JsonKey.NESTED_NOT_EXISTS.equalsIgnoreCase(key)) { + query = createNestedESOpperation(entry, query, constraintsMap); + } else if (JsonKey.NESTED_KEY_FILTER.equalsIgnoreCase(key)) { + Map nestedFilters = (Map) entry.getValue(); + for (Map.Entry en : nestedFilters.entrySet()) { + query = createNestedFilterESOpperation(en, query, constraintsMap); + } + } + long elapsedTime = calculateEndTime(startTime); + ProjectLogger.log( + "ElasticSearchHelper:addAdditionalProperties: method end ==" + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG.name()); + } + + /** + * Method to create CommonTermQuery , multimatch and Range Query. + * + * @param entry which contains key for search and respective values + * @param query Object which will be updated + * @param constraintsMap constraints for key and values + * @return BoolQueryBuilder + */ + @SuppressWarnings("unchecked") + private static BoolQueryBuilder createFilterESOpperation( + Entry entry, BoolQueryBuilder query, Map constraintsMap) { + String key = entry.getKey(); + Object val = entry.getValue(); + if (val instanceof List && val != null) { + query = getTermQueryFromList(val, key, query, constraintsMap); + } else if (val instanceof Map) { + if (key.equalsIgnoreCase(JsonKey.ES_OR_OPERATION)) { + query.must(createEsORFilterQuery((Map) val)); + } else { + query = getTermQueryFromMap(val, key, query, constraintsMap); + } + } else if (val instanceof String) { + query.must( + createTermQuery(key + RAW_APPEND, ((String) val).toLowerCase(), constraintsMap.get(key))); + } else { + query.must(createTermQuery(key + RAW_APPEND, val, constraintsMap.get(key))); + } + return query; + } + + /** + * Method to create CommonTermQuery , multimatch and Range Query. + * + * @param entry which contains key for search and respective values + * @param query Object which will be updated + * @param constraintsMap constraints for key and values + * @return BoolQueryBuilder + */ + @SuppressWarnings("unchecked") + private static BoolQueryBuilder createNestedFilterESOpperation( + Entry entry, BoolQueryBuilder query, Map constraintsMap) { + String key = entry.getKey(); + Object val = entry.getValue(); + String path = key.split("\\.")[0]; + if (val instanceof List && CollectionUtils.isNotEmpty((List) val)) { + if (((List) val).get(0) instanceof String) { + ((List) val).replaceAll(String::toLowerCase); + query.must( + QueryBuilders.nestedQuery( + path, + createTermsQuery(key + RAW_APPEND, (List) val, constraintsMap.get(key)), + ScoreMode.None)); + } else { + query.must( + QueryBuilders.nestedQuery( + path, createTermsQuery(key, (List) val, constraintsMap.get(key)), ScoreMode.None)); + } + } else if (val instanceof Map) { + query = getNestedTermQueryFromMap(val, key, path, query, constraintsMap); + } else if (val instanceof String) { + query.must( + QueryBuilders.nestedQuery( + path, + createTermQuery( + key + RAW_APPEND, ((String) val).toLowerCase(), constraintsMap.get(key)), + ScoreMode.None)); + } else { + query.must( + QueryBuilders.nestedQuery( + path, + createTermQuery(key + RAW_APPEND, val, constraintsMap.get(key)), + ScoreMode.None)); + } + return query; + } + + /** + * This method returns termQuery if any present in map provided + * + * @param key for search in termquery + * @param val value of the key to be searched + * @param query which will be updated according to key , value and constraints + * @param constraintsMap for setting any constraints on values for the specified key + * @return BoolQueryBuilder + */ + private static BoolQueryBuilder getTermQueryFromMap( + Object val, String key, BoolQueryBuilder query, Map constraintsMap) { + Map value = (Map) val; + Map rangeOperation = new HashMap<>(); + Map lexicalOperation = new HashMap<>(); + for (Map.Entry it : value.entrySet()) { + String operation = it.getKey(); + if (operation.startsWith(LT) || operation.startsWith(GT)) { + rangeOperation.put(operation, it.getValue()); + } else if (operation.startsWith(STARTS_WITH) || operation.startsWith(ENDS_WITH)) { + lexicalOperation.put(operation, it.getValue()); + } + } + if (!(rangeOperation.isEmpty())) { + query.must(createRangeQuery(key, rangeOperation, constraintsMap.get(key))); + } + if (!(lexicalOperation.isEmpty())) { + query.must(createLexicalQuery(key, lexicalOperation, constraintsMap.get(key))); + } + + return query; + } + + private static BoolQueryBuilder createEsORFilterQuery(Map orFilters) { + BoolQueryBuilder query = new BoolQueryBuilder(); + for (Map.Entry mp : orFilters.entrySet()) { + query.should( + QueryBuilders.termQuery( + mp.getKey() + RAW_APPEND, ((String) mp.getValue()).toLowerCase())); + } + return query; + } + + /** + * This method returns termQuery if any present in map provided + * + * @param key for search in termquery + * @param val value of the key to be searched + * @param query which will be updated according to key , value and constraints + * @param constraintsMap for setting any constraints on values for the specified key + * @return BoolQueryBuilder + */ + private static BoolQueryBuilder getNestedTermQueryFromMap( + Object val, + String key, + String path, + BoolQueryBuilder query, + Map constraintsMap) { + Map value = (Map) val; + Map rangeOperation = new HashMap<>(); + Map lexicalOperation = new HashMap<>(); + for (Map.Entry it : value.entrySet()) { + String operation = it.getKey(); + if (operation.startsWith(LT) || operation.startsWith(GT)) { + rangeOperation.put(operation, it.getValue()); + } else if (operation.startsWith(STARTS_WITH) || operation.startsWith(ENDS_WITH)) { + lexicalOperation.put(operation, it.getValue()); + } + } + if (!(rangeOperation.isEmpty())) { + query.must( + QueryBuilders.nestedQuery( + path, + createRangeQuery(key, rangeOperation, constraintsMap.get(key)), + ScoreMode.None)); + } + if (!(lexicalOperation.isEmpty())) { + query.must( + QueryBuilders.nestedQuery( + path, + createLexicalQuery(key, lexicalOperation, constraintsMap.get(key)), + ScoreMode.None)); + } + return query; + } + + /** + * This method returns termQuery if any present in List provided + * + * @param key for search in termquery + * @param val value of the key to be searched + * @param query which will be updated according to key , value and constraints + * @param constraintsMap for setting any constraints on values for the specified key + * @return BoolQueryBuilder + */ + private static BoolQueryBuilder getTermQueryFromList( + Object val, String key, BoolQueryBuilder query, Map constraintsMap) { + if (!((List) val).isEmpty()) { + if (((List) val).get(0) instanceof String) { + ((List) val).replaceAll(String::toLowerCase); + query.must(createTermsQuery(key + RAW_APPEND, (List) val, constraintsMap.get(key))); + } else { + query.must(createTermsQuery(key, (List) val, constraintsMap.get(key))); + } + } + return query; + } + + /** Method to create EXISTS and NOT EXIST FILTER QUERY . */ + /** + * @param entry contains operations and keys for filter + * @param query do get updated with provided operations + * @param constraintsMap to set ant constraints on keys for filter + * @return + */ + @SuppressWarnings("unchecked") + private static BoolQueryBuilder createESOpperation( + Entry entry, BoolQueryBuilder query, Map constraintsMap) { + + String operation = entry.getKey(); + if (entry.getValue() != null && entry.getValue() instanceof List) { + List existsList = (List) entry.getValue(); + + if (JsonKey.EXISTS.equalsIgnoreCase(operation)) { + for (String name : existsList) { + query.must(createExistQuery(name, constraintsMap.get(name))); + } + } else if (JsonKey.NOT_EXISTS.equalsIgnoreCase(operation)) { + for (String name : existsList) { + query.mustNot(createExistQuery(name, constraintsMap.get(name))); + } + } + } + return query; + } + + /** Method to create EXISTS and NOT EXIST FILTER QUERY . */ + /** + * @param entry contains operations and keys for filter + * @param query do get updated with provided operations + * @param constraintsMap to set ant constraints on keys for filter + * @return + */ + @SuppressWarnings("unchecked") + private static BoolQueryBuilder createNestedESOpperation( + Entry entry, BoolQueryBuilder query, Map constraintsMap) { + + String operation = entry.getKey(); + if (entry.getValue() != null && entry.getValue() instanceof Map) { + Map existsMap = (Map) entry.getValue(); + + if (JsonKey.NESTED_EXISTS.equalsIgnoreCase(operation)) { + for (Map.Entry nameByPath : existsMap.entrySet()) { + query.must( + QueryBuilders.nestedQuery( + nameByPath.getValue(), + createExistQuery(nameByPath.getKey(), constraintsMap.get(nameByPath.getKey())), + ScoreMode.None)); + } + } else if (JsonKey.NESTED_NOT_EXISTS.equalsIgnoreCase(operation)) { + for (Map.Entry nameByPath : existsMap.entrySet()) { + query.mustNot( + QueryBuilders.nestedQuery( + nameByPath.getValue(), + createExistQuery(nameByPath.getKey(), constraintsMap.get(nameByPath.getKey())), + ScoreMode.None)); + } + } + } + return query; + } + + /** Method to return the sorting order on basis of string param . */ + public static SortOrder getSortOrder(String value) { + return ASC_ORDER.equalsIgnoreCase(value) ? SortOrder.ASC : SortOrder.DESC; + } + + /** + * This method return MatchQueryBuilder Object with boosts if any provided + * + * @param name of the attribute + * @param value of the attribute + * @param boost for increasing the search parameters priority + * @return MatchQueryBuilder + */ + public static MatchQueryBuilder createMatchQuery(String name, Object value, Float boost) { + if (isNotNull(boost)) { + return QueryBuilders.matchQuery(name, value).boost(boost); + } else { + return QueryBuilders.matchQuery(name, value); + } + } + + /** + * This method returns TermsQueryBuilder with boosts if any provided + * + * @param key : field name + * @param values : values for the field value + * @param boost for increasing the search parameters priority + * @return TermsQueryBuilder + */ + private static TermsQueryBuilder createTermsQuery(String key, List values, Float boost) { + if (isNotNull(boost)) { + return QueryBuilders.termsQuery(key, (values).stream().toArray(Object[]::new)).boost(boost); + } else { + return QueryBuilders.termsQuery(key, (values).stream().toArray(Object[]::new)); + } + } + + /** + * This method returns RangeQueryBuilder with boosts if any provided + * + * @param name for the field + * @param rangeOperation: keys and value related to range + * @param boost for increasing the search parameters priority + * @return RangeQueryBuilder + */ + private static RangeQueryBuilder createRangeQuery( + String name, Map rangeOperation, Float boost) { + + RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(name + RAW_APPEND); + for (Map.Entry it : rangeOperation.entrySet()) { + switch (it.getKey()) { + case LTE: + rangeQueryBuilder.lte(it.getValue()); + break; + case LT: + rangeQueryBuilder.lt(it.getValue()); + break; + case GTE: + rangeQueryBuilder.gte(it.getValue()); + break; + case GT: + rangeQueryBuilder.gt(it.getValue()); + break; + } + } + if (isNotNull(boost)) { + return rangeQueryBuilder.boost(boost); + } + return rangeQueryBuilder; + } + + /** + * This method returns TermQueryBuilder with boosts if any provided + * + * @param name of the field for termquery + * @param value of the field for termquery + * @param boost for increasing the search parameters priority + * @return TermQueryBuilder + */ + private static TermQueryBuilder createTermQuery(String name, Object value, Float boost) { + if (isNotNull(boost)) { + return QueryBuilders.termQuery(name, value).boost(boost); + } else { + return QueryBuilders.termQuery(name, value); + } + } + + /** + * this method return ExistsQueryBuilder with boosts if any provided + * + * @param name of the field which required for exists operation + * @param boost for increasing the search parameters priority + * @return ExistsQueryBuilder + */ + private static ExistsQueryBuilder createExistQuery(String name, Float boost) { + if (isNotNull(boost)) { + return QueryBuilders.existsQuery(name).boost(boost); + } else { + return QueryBuilders.existsQuery(name); + } + } + + /** + * This method create lexical query with boosts if any provided + * + * @param key for search + * @param rangeOperation to search or match in a particular way + * @param boost for increasing the search parameters priority + * @return QueryBuilder + */ + public static QueryBuilder createLexicalQuery( + String key, Map rangeOperation, Float boost) { + QueryBuilder queryBuilder = null; + for (Map.Entry it : rangeOperation.entrySet()) { + switch (it.getKey()) { + case STARTS_WITH: + { + String startsWithVal = (String) it.getValue(); + if (StringUtils.isNotBlank(startsWithVal)) { + startsWithVal = startsWithVal.toLowerCase(); + } + if (isNotNull(boost)) { + queryBuilder = + QueryBuilders.prefixQuery(key + RAW_APPEND, startsWithVal).boost(boost); + } + queryBuilder = QueryBuilders.prefixQuery(key + RAW_APPEND, startsWithVal); + break; + } + case ENDS_WITH: + { + String endsWithRegex = "~" + it.getValue(); + if (isNotNull(boost)) { + queryBuilder = + QueryBuilders.regexpQuery(key + RAW_APPEND, endsWithRegex).boost(boost); + } + queryBuilder = QueryBuilders.regexpQuery(key + RAW_APPEND, endsWithRegex); + break; + } + } + } + return queryBuilder; + } + + /** + * this method will take start time and subtract with current time to get the time spent in + * millis. + * + * @param startTime long + * @return long + */ + public static long calculateEndTime(long startTime) { + return System.currentTimeMillis() - startTime; + } + + /** + * This method will create searchdto on this of searchquery provided + * + * @param searchQueryMap Map contains query + * @return SearchDto for search data in elastic search + */ + public static SearchDTO createSearchDTO(Map searchQueryMap) { + SearchDTO search = new SearchDTO(); + search = getBasicBuiders(search, searchQueryMap); + search = setOffset(search, searchQueryMap); + search = getLimits(search, searchQueryMap); + if (searchQueryMap.containsKey(JsonKey.GROUP_QUERY)) { + search + .getGroupQuery() + .addAll( + (Collection>) searchQueryMap.get(JsonKey.GROUP_QUERY)); + } + search = getSoftConstraints(search, searchQueryMap); + return search; + } + + /** + * This method add any softconstraints present in seach query to search DTo + * + * @param SearchDTO search which contains the search parameters for elastic search. + * @param Map searchQueryMap which contains soft_constraints + * @return SearchDTO updated searchDTO which contains soft_constraits + */ + private static SearchDTO getSoftConstraints( + SearchDTO search, Map searchQueryMap) { + if (searchQueryMap.containsKey(JsonKey.SOFT_CONSTRAINTS)) { + search.setSoftConstraints( + (Map) searchQueryMap.get(JsonKey.SOFT_CONSTRAINTS)); + } + return search; + } + + /** + * This method adds any limits present in the search query + * + * @param SearchDTO search which contains the search parameters for elastic search. + * @param Map searchQueryMap which contain limit + * @return SearchDTO updated searchDTO which contains limit + */ + private static SearchDTO getLimits(SearchDTO search, Map searchQueryMap) { + if (searchQueryMap.containsKey(JsonKey.LIMIT)) { + if ((searchQueryMap.get(JsonKey.LIMIT)) instanceof Integer) { + search.setLimit((int) searchQueryMap.get(JsonKey.LIMIT)); + } else { + search.setLimit(((BigInteger) searchQueryMap.get(JsonKey.LIMIT)).intValue()); + } + } + return search; + } + + /** + * This method adds offset if any present in the searchQuery + * + * @param SearchDTO search which contains the search parameters for elastic search. + * @param map searchQueryMap which contains offset + * @return SearchDTO updated searchDTO which contain offset + */ + private static SearchDTO setOffset(SearchDTO search, Map searchQueryMap) { + if (searchQueryMap.containsKey(JsonKey.OFFSET)) { + if ((searchQueryMap.get(JsonKey.OFFSET)) instanceof Integer) { + search.setOffset((int) searchQueryMap.get(JsonKey.OFFSET)); + } else { + search.setOffset(((BigInteger) searchQueryMap.get(JsonKey.OFFSET)).intValue()); + } + } + return search; + } + + /** + * This method adds basic query parameter to SearchDTO if any provided + * + * @param SearchDTO search + * @param Map searchQueryMap + * @return SearchDTO + */ + private static SearchDTO getBasicBuiders(SearchDTO search, Map searchQueryMap) { + if (searchQueryMap.containsKey(JsonKey.QUERY)) { + search.setQuery((String) searchQueryMap.get(JsonKey.QUERY)); + } + if (searchQueryMap.containsKey(JsonKey.QUERY_FIELDS)) { + search.setQueryFields((List) searchQueryMap.get(JsonKey.QUERY_FIELDS)); + } + if (searchQueryMap.containsKey(JsonKey.FACETS)) { + search.setFacets((List>) searchQueryMap.get(JsonKey.FACETS)); + } + if (searchQueryMap.containsKey(JsonKey.FIELDS)) { + search.setFields((List) searchQueryMap.get(JsonKey.FIELDS)); + } + if (searchQueryMap.containsKey(JsonKey.FILTERS)) { + search.getAdditionalProperties().put(JsonKey.FILTERS, searchQueryMap.get(JsonKey.FILTERS)); + } + if (searchQueryMap.containsKey(JsonKey.EXISTS)) { + search.getAdditionalProperties().put(JsonKey.EXISTS, searchQueryMap.get(JsonKey.EXISTS)); + } + if (searchQueryMap.containsKey(JsonKey.NOT_EXISTS)) { + search + .getAdditionalProperties() + .put(JsonKey.NOT_EXISTS, searchQueryMap.get(JsonKey.NOT_EXISTS)); + } + if (searchQueryMap.containsKey(JsonKey.SORT_BY)) { + search + .getSortBy() + .putAll((Map) searchQueryMap.get(JsonKey.SORT_BY)); + } + return search; + } + + /** + * Method returns map which contains all the request data from elasticsearch + * + * @param SearchResponse response from elastic search + * @param searchDTO searchDTO which was used to search data + * @param finalFacetList Facets provide aggregated data based on a search query + * @return Map which will have all the requested data + */ + public static Map getSearchResponseMap( + SearchResponse response, SearchDTO searchDTO, List finalFacetList) { + Map responseMap = new HashMap<>(); + List> esSource = new ArrayList<>(); + long count = 0; + if (response != null) { + SearchHits hits = response.getHits(); + count = hits.getTotalHits(); + + for (SearchHit hit : hits) { + esSource.add(hit.getSourceAsMap()); + } + + // fetch aggregations aggregations + finalFacetList = getFinalFacetList(response, searchDTO, finalFacetList); + } + responseMap.put(JsonKey.CONTENT, esSource); + if (!(finalFacetList.isEmpty())) { + responseMap.put(JsonKey.FACETS, finalFacetList); + } + responseMap.put(JsonKey.COUNT, count); + return responseMap; + } + + private static List getFinalFacetList( + SearchResponse response, SearchDTO searchDTO, List finalFacetList) { + if (null != searchDTO.getFacets() && !searchDTO.getFacets().isEmpty()) { + Map m1 = searchDTO.getFacets().get(0); + for (Map.Entry entry : m1.entrySet()) { + String field = entry.getKey(); + String aggsType = entry.getValue(); + List aggsList = new ArrayList<>(); + Map facetMap = new HashMap(); + if (JsonKey.DATE_HISTOGRAM.equalsIgnoreCase(aggsType)) { + Histogram agg = response.getAggregations().get(field); + for (Histogram.Bucket ent : agg.getBuckets()) { + // DateTime key = (DateTime) ent.getKey(); // Key + String keyAsString = ent.getKeyAsString(); // Key as String + long docCount = ent.getDocCount(); // Doc count + Map internalMap = new HashMap(); + internalMap.put(JsonKey.NAME, keyAsString); + internalMap.put(JsonKey.COUNT, docCount); + aggsList.add(internalMap); + } + } else { + Terms aggs = response.getAggregations().get(field); + for (Bucket bucket : aggs.getBuckets()) { + Map internalMap = new HashMap(); + internalMap.put(JsonKey.NAME, bucket.getKey()); + internalMap.put(JsonKey.COUNT, bucket.getDocCount()); + aggsList.add(internalMap); + } + } + facetMap.put("values", aggsList); + facetMap.put(JsonKey.NAME, field); + finalFacetList.add(facetMap); + } + } + return finalFacetList; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/ElasticSearchRestHighImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/ElasticSearchRestHighImpl.java new file mode 100644 index 0000000000..60f61dc68e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/ElasticSearchRestHighImpl.java @@ -0,0 +1,737 @@ +package org.sunbird.common; + +import akka.dispatch.Futures; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest; +import org.elasticsearch.action.bulk.BulkItemResponse; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.delete.DeleteRequest; +import org.elasticsearch.action.delete.DeleteResponse; +import org.elasticsearch.action.get.GetRequest; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.update.UpdateRequest; +import org.elasticsearch.action.update.UpdateResponse; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.SimpleQueryStringBuilder; +import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.sort.FieldSortBuilder; +import org.elasticsearch.search.sort.SortMode; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ConnectionManager; +import scala.concurrent.Future; +import scala.concurrent.Promise; + +/** + * This class will provide all required operation for elastic search. + * + * @author github.com/iostream04 + */ +public class ElasticSearchRestHighImpl implements ElasticSearchService { + private static final String ERROR = "ERROR"; + + /** + * This method will put a new data entry inside Elastic search. identifier value becomes _id + * inside ES, so every time provide a unique value while saving it. + * + * @param index String ES index name + * @param identifier ES column identifier as an String + * @param data Map + * @return Future which contains identifier for created data + */ + @Override + public Future save(String index, String identifier, Map data) { + long startTime = System.currentTimeMillis(); + Promise promise = Futures.promise(); + ProjectLogger.log( + "ElasticSearchUtilRest:save: method started at ==" + startTime + " for Index " + index, + LoggerEnum.PERF_LOG.name()); + if (StringUtils.isBlank(identifier) || StringUtils.isBlank(index)) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:save: " + + "Identifier or Index value is null or empty, identifier : " + + "" + + identifier + + ",index: " + + index + + ",not able to save data.", + LoggerEnum.INFO.name()); + promise.success(ERROR); + return promise.future(); + } + data.put("identifier", identifier); + + IndexRequest indexRequest = new IndexRequest(index, _DOC, identifier).source(data); + + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(IndexResponse indexResponse) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:save: Success for index : " + + index + + ", identifier :" + + identifier, + LoggerEnum.INFO.name()); + + promise.success(indexResponse.getId()); + ProjectLogger.log( + "ElasticSearchRestHighImpl:save: method end at ==" + + System.currentTimeMillis() + + " for Index " + + index + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + } + + @Override + public void onFailure(Exception e) { + promise.failure(e); + ProjectLogger.log( + "ElasticSearchRestHighImpl:save: " + + "Error while saving " + + index + + " id : " + + identifier + + " with error :" + + e, + LoggerEnum.ERROR.name()); + ProjectLogger.log( + "ElasticSearchRestHighImpl:save: method end at ==" + + System.currentTimeMillis() + + " for INdex " + + index + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + } + }; + + ConnectionManager.getRestClient().indexAsync(indexRequest, listener); + + return promise.future(); + } + + /** + * This method will update data entry inside Elastic search, using identifier and provided data . + * + * @param index String ES index name + * @param identifier ES column identifier as an String + * @param data Map + * @return true or false + */ + @Override + public Future update(String index, String identifier, Map data) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "ElasticSearchRestHighImpl:update: method started at ==" + + startTime + + " for Index " + + index, + LoggerEnum.PERF_LOG.name()); + Promise promise = Futures.promise(); + ; + + if (!StringUtils.isBlank(index) && !StringUtils.isBlank(identifier) && data != null) { + UpdateRequest updateRequest = new UpdateRequest(index, _DOC, identifier).doc(data); + + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(UpdateResponse updateResponse) { + promise.success(true); + ProjectLogger.log( + "ElasticSearchRestHighImpl:update: Success with " + + updateResponse.getResult() + + " response from elastic search for index" + + index + + ",identifier : " + + identifier, + LoggerEnum.INFO.name()); + ProjectLogger.log( + "ElasticSearchRestHighImpl:update: method end ==" + + " for INdex " + + index + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + } + + @Override + public void onFailure(Exception e) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:update: exception occured:" + e.getMessage(), + LoggerEnum.ERROR.name()); + promise.failure(e); + } + }; + ConnectionManager.getRestClient().updateAsync(updateRequest, listener); + + } else { + ProjectLogger.log( + "ElasticSearchRestHighImpl:update: Requested data is invalid.", LoggerEnum.INFO.name()); + promise.failure(ProjectUtil.createClientException(ResponseCode.invalidData)); + } + return promise.future(); + } + + /** + * This method will provide data form ES based on incoming identifier. we can get data by passing + * index and identifier values , or all the three + * + * @param type String + * @param identifier String + * @return Map or empty map + */ + @Override + public Future> getDataByIdentifier(String index, String identifier) { + long startTime = System.currentTimeMillis(); + Promise> promise = Futures.promise(); + if (StringUtils.isNotEmpty(identifier) && StringUtils.isNotEmpty(index)) { + + ProjectLogger.log( + "ElasticSearchRestHighImpl:getDataByIdentifier: method started at ==" + + startTime + + " for Index " + + index, + LoggerEnum.PERF_LOG.name()); + + GetRequest getRequest = new GetRequest(index, _DOC, identifier); + + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(GetResponse getResponse) { + if (getResponse.isExists()) { + Map sourceAsMap = getResponse.getSourceAsMap(); + if (MapUtils.isNotEmpty(sourceAsMap)) { + promise.success(sourceAsMap); + ProjectLogger.log( + "ElasticSearchRestHighImpl:getDataByIdentifier: method end ==" + + " for Index " + + index + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + } else { + promise.success(new HashMap<>()); + } + } else { + promise.success(new HashMap<>()); + } + } + + @Override + public void onFailure(Exception e) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:getDataByIdentifier: method Failed with error == " + e, + LoggerEnum.INFO.name()); + promise.failure(e); + } + }; + + ConnectionManager.getRestClient().getAsync(getRequest, listener); + } else { + ProjectLogger.log( + "ElasticSearchRestHighImpl:getDataByIdentifier: " + + "provided index or identifier is null, index = " + + index + + "," + + " identifier = " + + identifier, + LoggerEnum.INFO.name()); + promise.failure(ProjectUtil.createClientException(ResponseCode.invalidData)); + } + + return promise.future(); + } + + /** + * This method will remove data from ES based on identifier. + * + * @param index String + * @param type String + * @param identifier String + */ + @Override + public Future delete(String index, String identifier) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "ElasticSearchRestHighImpl:delete: method started at ==" + startTime, + LoggerEnum.PERF_LOG.name()); + Promise promise = Futures.promise(); + if (StringUtils.isNotEmpty(identifier) && StringUtils.isNotEmpty(index)) { + DeleteRequest delRequest = new DeleteRequest(index, _DOC, identifier); + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(DeleteResponse deleteResponse) { + if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:delete:OnResponse: Document not found for index : " + + index + + " , identifier : " + + identifier, + LoggerEnum.INFO.name()); + promise.success(false); + } else { + promise.success(true); + } + } + + @Override + public void onFailure(Exception e) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:delete: Async Failed due to error :" + e, + LoggerEnum.INFO.name()); + promise.failure(e); + } + }; + + ConnectionManager.getRestClient().deleteAsync(delRequest, listener); + } else { + ProjectLogger.log( + "ElasticSearchRestHighImpl:delete: " + + "provided index or identifier is null, index = " + + index + + "," + + " identifier = " + + identifier, + LoggerEnum.INFO.name()); + promise.failure(ProjectUtil.createClientException(ResponseCode.invalidData)); + } + + ProjectLogger.log( + "ElasticSearchRestHighImpl:delete: method end ==" + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + return promise.future(); + } + + /** + * Method to perform the elastic search on the basis of SearchDTO . SearchDTO contains the search + * criteria like fields, facets, sort by , filters etc. here user can pass single type to search + * or multiple type or null + * + * @param type var arg of String + * @return search result as Map. + */ + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public Future> search(SearchDTO searchDTO, String index) { + long startTime = System.currentTimeMillis(); + + ProjectLogger.log( + "ElasticSearchRestHighImpl:search: method started at ==" + startTime, + LoggerEnum.PERF_LOG.name()); + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + SearchRequest searchRequest = new SearchRequest(index); + searchRequest.types(_DOC); + + // check mode and set constraints + Map constraintsMap = ElasticSearchHelper.getConstraints(searchDTO); + + BoolQueryBuilder query = new BoolQueryBuilder(); + + // add channel field as mandatory + String channel = PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_ES_CHANNEL); + if (!(StringUtils.isBlank(channel) || JsonKey.SUNBIRD_ES_CHANNEL.equals(channel))) { + query.must( + ElasticSearchHelper.createMatchQuery( + JsonKey.CHANNEL, channel, constraintsMap.get(JsonKey.CHANNEL))); + } + + // apply simple query string + if (!StringUtils.isBlank(searchDTO.getQuery())) { + SimpleQueryStringBuilder sqsb = QueryBuilders.simpleQueryStringQuery(searchDTO.getQuery()); + if (CollectionUtils.isEmpty(searchDTO.getQueryFields())) { + query.must(sqsb.field("all_fields")); + } else { + Map searchFields = + searchDTO + .getQueryFields() + .stream() + .collect(Collectors.toMap(s -> s, v -> 1.0f)); + query.must(sqsb.fields(searchFields)); + } + } + // apply the sorting + if (searchDTO.getSortBy() != null && searchDTO.getSortBy().size() > 0) { + for (Map.Entry entry : searchDTO.getSortBy().entrySet()) { + if (!entry.getKey().contains(".")) { + searchSourceBuilder.sort( + entry.getKey() + ElasticSearchHelper.RAW_APPEND, + ElasticSearchHelper.getSortOrder((String) entry.getValue())); + } else { + Map map = (Map) entry.getValue(); + Map dataMap = (Map) map.get(JsonKey.TERM); + for (Map.Entry dateMapEntry : dataMap.entrySet()) { + FieldSortBuilder mySort = + new FieldSortBuilder(entry.getKey() + ElasticSearchHelper.RAW_APPEND) + .setNestedFilter( + new TermQueryBuilder(dateMapEntry.getKey(), dateMapEntry.getValue())) + .sortMode(SortMode.MIN) + .order(ElasticSearchHelper.getSortOrder((String) map.get(JsonKey.ORDER))); + searchSourceBuilder.sort(mySort); + } + } + } + } + + // apply the fields filter + searchSourceBuilder.fetchSource( + searchDTO.getFields() != null + ? searchDTO.getFields().stream().toArray(String[]::new) + : null, + searchDTO.getExcludedFields() != null + ? searchDTO.getExcludedFields().stream().toArray(String[]::new) + : null); + + // setting the offset + if (searchDTO.getOffset() != null) { + searchSourceBuilder.from(searchDTO.getOffset()); + } + + // setting the limit + if (searchDTO.getLimit() != null) { + searchSourceBuilder.size(searchDTO.getLimit()); + } + // apply additional properties + if (searchDTO.getAdditionalProperties() != null + && searchDTO.getAdditionalProperties().size() > 0) { + for (Map.Entry entry : searchDTO.getAdditionalProperties().entrySet()) { + ElasticSearchHelper.addAdditionalProperties(query, entry, constraintsMap); + } + } + + // set final query to search request builder + searchSourceBuilder.query(query); + List finalFacetList = new ArrayList(); + + if (null != searchDTO.getFacets() && !searchDTO.getFacets().isEmpty()) { + searchSourceBuilder = addAggregations(searchSourceBuilder, searchDTO.getFacets()); + } + ProjectLogger.log( + "ElasticSearchRestHighImpl:search: calling search builder======" + + searchSourceBuilder.toString(), + LoggerEnum.INFO.name()); + + searchRequest.source(searchSourceBuilder); + Promise> promise = Futures.promise(); + + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(SearchResponse response) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:search:onResponse response1 = " + response, + LoggerEnum.DEBUG.name()); + if (response.getHits() == null || response.getHits().getTotalHits() == 0) { + + Map responseMap = new HashMap<>(); + List> esSource = new ArrayList<>(); + responseMap.put(JsonKey.CONTENT, esSource); + responseMap.put(JsonKey.COUNT, 0); + promise.success(responseMap); + } else { + Map responseMap = + ElasticSearchHelper.getSearchResponseMap(response, searchDTO, finalFacetList); + ProjectLogger.log( + "ElasticSearchRestHighImpl:search: method end " + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + promise.success(responseMap); + } + } + + @Override + public void onFailure(Exception e) { + promise.failure(e); + + ProjectLogger.log( + "ElasticSearchRestHighImpl:search: method end for Index " + + index + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + ProjectLogger.log( + "ElasticSearchRestHighImpl:search: method Failed with error :" + e, + LoggerEnum.ERROR.name()); + } + }; + + ConnectionManager.getRestClient().searchAsync(searchRequest, listener); + return promise.future(); + } + + /** + * This method will do the health check of elastic search. + * + * @return boolean + */ + @Override + public Future healthCheck() { + + GetIndexRequest indexRequest = + new GetIndexRequest().indices(ProjectUtil.EsType.user.getTypeName()); + Promise promise = Futures.promise(); + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(Boolean getResponse) { + if (getResponse) { + promise.success(getResponse); + } else { + promise.success(false); + } + } + + @Override + public void onFailure(Exception e) { + promise.failure(e); + ProjectLogger.log( + "ElasticSearchRestHighImpl:healthCheck: error " + e.getMessage(), + LoggerEnum.INFO.name()); + } + }; + ConnectionManager.getRestClient().indices().existsAsync(indexRequest, listener); + + return promise.future(); + } + + /** + * This method will do the bulk data insertion. + * + * @param index String index name + * @param type String type name + * @param dataList List> + * @return boolean + */ + @Override + public Future bulkInsert(String index, List> dataList) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "ElasticSearchRestHighImpl:bulkInsert: method started at ==" + + startTime + + " for Index " + + index, + LoggerEnum.PERF_LOG.name()); + BulkRequest request = new BulkRequest(); + Promise promise = Futures.promise(); + for (Map data : dataList) { + request.add(new IndexRequest(index, _DOC, (String) data.get(JsonKey.ID)).source(data)); + } + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(BulkResponse bulkResponse) { + Iterator responseItr = bulkResponse.iterator(); + if (responseItr != null) { + promise.success(true); + while (responseItr.hasNext()) { + + BulkItemResponse bResponse = responseItr.next(); + + if (bResponse.isFailed()) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:bulkinsert: api response===" + + bResponse.getId() + + " " + + bResponse.getFailureMessage(), + LoggerEnum.INFO.name()); + } + } + } + } + + @Override + public void onFailure(Exception e) { + ProjectLogger.log("ElasticSearchRestHighImpl:bulkinsert: Bulk upload error block", e); + promise.success(false); + } + }; + ConnectionManager.getRestClient().bulkAsync(request, listener); + + ProjectLogger.log( + "ElasticSearchRestHighImpl:bulkInsert: method end ==" + + " for Index " + + index + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + return promise.future(); + } + + private static long calculateEndTime(long startTime) { + return System.currentTimeMillis() - startTime; + } + + private static SearchSourceBuilder addAggregations( + SearchSourceBuilder searchSourceBuilder, List> facets) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "ElasticSearchRestHighImpl:addAggregations: method started at ==" + startTime, + LoggerEnum.PERF_LOG.name()); + Map map = facets.get(0); + for (Map.Entry entry : map.entrySet()) { + + String key = entry.getKey(); + String value = entry.getValue(); + if (JsonKey.DATE_HISTOGRAM.equalsIgnoreCase(value)) { + searchSourceBuilder.aggregation( + AggregationBuilders.dateHistogram(key) + .field(key + ElasticSearchHelper.RAW_APPEND) + .dateHistogramInterval(DateHistogramInterval.days(1))); + + } else if (null == value) { + searchSourceBuilder.aggregation( + AggregationBuilders.terms(key).field(key + ElasticSearchHelper.RAW_APPEND)); + } + } + ProjectLogger.log( + "ElasticSearchRestHighImpl:addAggregations: method end ==" + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + return searchSourceBuilder; + } + + /** + * This method will update data based on identifier.take the data based on identifier and merge + * with incoming data then update it. + * + * @param index String + * @param type String + * @param identifier String + * @param data Map + * @return boolean + */ + @Override + public Future upsert(String index, String identifier, Map data) { + long startTime = System.currentTimeMillis(); + Promise promise = Futures.promise(); + ProjectLogger.log( + "ElasticSearchRestHighImpl:upsert: method started at ==" + + startTime + + " for INdex " + + index, + LoggerEnum.PERF_LOG.name()); + if (!StringUtils.isBlank(index) + && !StringUtils.isBlank(identifier) + && data != null + && data.size() > 0) { + + IndexRequest indexRequest = new IndexRequest(index, _DOC, identifier).source(data); + + UpdateRequest updateRequest = new UpdateRequest(index, _DOC, identifier).upsert(indexRequest); + updateRequest.doc(indexRequest); + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(UpdateResponse updateResponse) { + promise.success(true); + ProjectLogger.log( + "ElasticSearchRestHighImpl:upsert: Response for index : " + + updateResponse.getResult() + + "," + + index + + ",identifier : " + + identifier, + LoggerEnum.INFO.name()); + ProjectLogger.log( + "ElasticSearchRestHighImpl:upsert: method end ==" + + " for Index " + + index + + " ,Total time elapsed = " + + calculateEndTime(startTime), + LoggerEnum.PERF_LOG.name()); + } + + @Override + public void onFailure(Exception e) { + ProjectLogger.log( + "ElasticSearchRestHighImpl:upsert: exception occured:" + e.getMessage(), + LoggerEnum.ERROR.name()); + promise.failure(e); + } + }; + ConnectionManager.getRestClient().updateAsync(updateRequest, listener); + return promise.future(); + } else { + ProjectLogger.log( + "ElasticSearchRestHighImpl:upsert: Requested data is invalid.", LoggerEnum.ERROR.name()); + promise.failure(ProjectUtil.createClientException(ResponseCode.invalidData)); + return promise.future(); + } + } + + /** + * This method will return map of objects on the basis of ids provided. + * + * @param ids List of String + * @param fields List of String + * @param index index of elasticserach for query + * @param data Map + * @return future of requested data in the form of map + */ + @Override + public Future>> getEsResultByListOfIds( + List ids, List fields, String index) { + long startTime = System.currentTimeMillis(); + + Map filters = new HashMap<>(); + filters.put(JsonKey.ID, ids); + + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + searchDTO.setFields(fields); + + Future> resultF = search(searchDTO, index); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + List> esContent = (List>) result.get(JsonKey.CONTENT); + Promise>> promise = Futures.promise(); + promise.success( + esContent + .stream() + .collect( + Collectors.toMap( + obj -> { + return (String) obj.get("id"); + }, + val -> val))); + ProjectLogger.log( + "ElasticSearchRestHighImpl:getEsResultByListOfIds: method ended for index " + index, + LoggerEnum.INFO.name()); + + return promise.future(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/factory/EsClientFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/factory/EsClientFactory.java new file mode 100644 index 0000000000..942be89928 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/factory/EsClientFactory.java @@ -0,0 +1,39 @@ +package org.sunbird.common.factory; + +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; + +public class EsClientFactory { + + private static ElasticSearchService restClient = null; + + /** + * This method return REST/TCP client for elastic search + * + * @param type can be "tcp" or "rest" + * @return ElasticSearchService with the respected type impl + */ + public static ElasticSearchService getInstance(String type) { + if (JsonKey.REST.equals(type)) { + return getRestClient(); + } else { + ProjectLogger.log( + "EsClientFactory:getInstance: value for client type provided null ", LoggerEnum.ERROR); + } + return null; + } + + private static ElasticSearchService getRestClient() { + if (restClient == null) { + synchronized (EsClientFactory.class) { + if (restClient == null) { + restClient = new ElasticSearchRestHighImpl(); + } + } + } + return restClient; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/inf/ElasticSearchService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/inf/ElasticSearchService.java new file mode 100644 index 0000000000..8e854f81a4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/common/inf/ElasticSearchService.java @@ -0,0 +1,172 @@ +package org.sunbird.common.inf; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import scala.concurrent.Future; + +public interface ElasticSearchService { + public static final String _DOC = "_doc"; + + /** + * This method will put a new data entry inside Elastic search. identifier value becomes _id + * inside ES, so every time provide a unique value while saving it. + * + * @param index String ES index name + * @param identifier ES column identifier as an String + * @param data Map + * @return String identifier for created data + */ + public Future save(String index, String identifier, Map data); + + /** + * This method will update data based on identifier.take the data based on identifier and merge + * with incoming data then update it. + * + * @param index String + * @param identifier String + * @param data Map + * @return boolean + */ + public Future update(String index, String identifier, Map data); + + /** + * This method will provide data form ES based on incoming identifier. we can get data by passing + * index and identifier values , or all the three index, identifier and type + * + * @param index String + * @param identifier String + * @return Map or null + */ + public Future> getDataByIdentifier(String index, String identifier); + + /** + * This method will remove data from ES based on identifier. + * + * @param index String + * @param identifier String + */ + public Future delete(String index, String identifier); + + /** + * Method to perform the elastic search on the basis of SearchDTO . SearchDTO contains the search + * criteria like fields, facets, sort by , filters etc. here user can pass single type to search + * or multiple type or null + * + * @param type var arg of String + * @return search result as Map. + */ + public Future> search(SearchDTO searchDTO, String index); + + /** + * This method will do the health check of elastic search. + * + * @return boolean + */ + public Future healthCheck(); + + /** + * This method will do the bulk data insertion. + * + * @param index String index name + * @param dataList List> + * @return boolean + */ + public Future bulkInsert(String index, List> dataList); + + /** + * This method will upsert data based on identifier.take the data based on identifier and merge + * with incoming data then update it or if not present already will create it. + * + * @param index String + * @param identifier String + * @param data Map + * @return boolean + */ + public Future upsert(String index, String identifier, Map data); + + /** + * @param ids List of ids of document + * @param fields List of fields which needs to captured + * @param index elastic search index in which search should be done + * @return Map> It will return a map with id as key and the data from ES + * as value + */ + public Future>> getEsResultByListOfIds( + List organisationIds, List fields, String index); + + /** + * Method to execute ES raw query with the limitation of size set to 0 Currently, This is a not a + * tcp call. + * + * @param index ES indexName + * @param rawQuery actual query to be executed + * @return Response Object from elastic Search + */ + default Response searchMetricsData(String index, String rawQuery) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "ElasticSearchService:searchMetricsData: " + + "Metrics search method started at ==" + + startTime, + LoggerEnum.PERF_LOG); + String baseUrl = null; + if (!StringUtils.isBlank(System.getenv(JsonKey.SUNBIRD_ES_IP))) { + String envHost = System.getenv(JsonKey.SUNBIRD_ES_IP); + String[] host = envHost.split(","); + baseUrl = + "http://" + + host[0] + + ":" + + PropertiesCache.getInstance().getProperty(JsonKey.ES_METRICS_PORT); + } else { + ProjectLogger.log("ElasticSearchTcpImpl:searchMetricsData:" + " ES URL from Properties file"); + baseUrl = PropertiesCache.getInstance().getProperty(JsonKey.ES_URL); + } + String requestURL = baseUrl + "/" + index + "/" + "_doc" + "/" + "_search"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + Map responseData = new HashMap<>(); + try { + // TODO:Currently this is making a rest call but needs to be modified to make + // the call using + // ElasticSearch client + String responseStr = HttpUtil.sendPostRequest(requestURL, rawQuery, headers); + ObjectMapper mapper = new ObjectMapper(); + responseData = mapper.readValue(responseStr, Map.class); + } catch (IOException e) { + throw new ProjectCommonException( + ResponseCode.unableToConnectToES.getErrorCode(), + ResponseCode.unableToConnectToES.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.unableToParseData.getErrorCode(), + ResponseCode.unableToParseData.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + Response response = new Response(); + response.put(JsonKey.RESPONSE, responseData); + ProjectLogger.log( + "ElasticSearchService:searchMetricsData: " + + "ElasticSearchService metrics search method end at == " + + System.currentTimeMillis() + + " ,Total time elapsed = " + + ElasticSearchHelper.calculateEndTime(startTime), + LoggerEnum.PERF_LOG); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/dto/SearchDTO.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/dto/SearchDTO.java new file mode 100644 index 0000000000..a442535a34 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/dto/SearchDTO.java @@ -0,0 +1,177 @@ +/** */ +package org.sunbird.dto; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class will take input for elastic search query + * + * @author Manzarul + */ +public class SearchDTO { + + @SuppressWarnings("rawtypes") + private List properties; + + private List> facets = new ArrayList<>(); + private List fields; + private List excludedFields; + private Map sortBy = new HashMap<>(); + private String operation; + private String query; + private List queryFields; + + private Integer limit = 250; + private Integer offset = 0; + private boolean fuzzySearch = false; + // additional properties will hold , filters, exist , not exist + private Map additionalProperties = new HashMap<>(); + private Map softConstraints = new HashMap<>(); + private List> groupQuery = new ArrayList<>(); + private List mode = new ArrayList<>(); + + public List> getGroupQuery() { + return groupQuery; + } + + public void setGroupQuery(List> groupQuery) { + this.groupQuery = groupQuery; + } + + public SearchDTO() { + super(); + } + + @SuppressWarnings("rawtypes") + public SearchDTO(List properties, String operation, int limit) { + super(); + this.properties = properties; + this.operation = operation; + this.limit = limit; + } + + @SuppressWarnings("rawtypes") + public List getProperties() { + return properties; + } + + @SuppressWarnings("rawtypes") + public void setProperties(List properties) { + this.properties = properties; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public Integer getLimit() { + return limit; + } + + public void setLimit(Integer limit) { + this.limit = limit; + } + + public List> getFacets() { + return facets; + } + + public void setFacets(List> facets) { + this.facets = facets; + } + + public Map getSortBy() { + return sortBy; + } + + public void setSortBy(Map sortBy) { + this.sortBy = sortBy; + } + + public boolean isFuzzySearch() { + return fuzzySearch; + } + + public void setFuzzySearch(boolean fuzzySearch) { + this.fuzzySearch = fuzzySearch; + } + + public Map getAdditionalProperties() { + return additionalProperties; + } + + public void setAdditionalProperties(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + public Object getAdditionalProperty(String key) { + return additionalProperties.get(key); + } + + public void addAdditionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + } + + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + public Integer getOffset() { + return offset; + } + + public void setOffset(Integer offset) { + this.offset = offset; + } + + public Map getSoftConstraints() { + return softConstraints; + } + + public void setSoftConstraints(Map softConstraints) { + this.softConstraints = softConstraints; + } + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public List getMode() { + return mode; + } + + public void setMode(List mode) { + this.mode = mode; + } + + public List getExcludedFields() { + return excludedFields; + } + + public void setExcludedFields(List excludedFields) { + this.excludedFields = excludedFields; + } + + public List getQueryFields() { + return queryFields; + } + + public void setQueryFields(List queryFields) { + this.queryFields = queryFields; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ConnectionManager.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ConnectionManager.java new file mode 100644 index 0000000000..f4077ac3da --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ConnectionManager.java @@ -0,0 +1,132 @@ +/** */ +package org.sunbird.helper; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; + +/** + * This class will manage connection. + * + * @author Manzarul + */ +public class ConnectionManager { + + private static RestHighLevelClient restClient = null; + private static List host = new ArrayList<>(); + private static List ports = new ArrayList<>(); + + static { + System.setProperty("es.set.netty.runtime.available.processors", "false"); + initialiseRestClientConnection(); + registerShutDownHook(); + } + + private ConnectionManager() {} + + private static boolean initialiseRestClientConnection() { + boolean response = false; + try { + String cluster = System.getenv(JsonKey.SUNBIRD_ES_CLUSTER); + String hostName = System.getenv(JsonKey.SUNBIRD_ES_IP); + String port = System.getenv(JsonKey.SUNBIRD_ES_PORT); + if (StringUtils.isBlank(hostName) || StringUtils.isBlank(port)) { + return false; + } + String[] splitedHost = hostName.split(","); + for (String val : splitedHost) { + host.add(val); + } + String[] splitedPort = port.split(","); + for (String val : splitedPort) { + ports.add(Integer.parseInt(val)); + } + response = createRestClient(cluster, host); + ProjectLogger.log( + "ELASTIC SEARCH CONNECTION ESTABLISHED for restClient from EVN with Following Details cluster " + + cluster + + " hostName" + + hostName + + " port " + + port + + response, + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log("Error while initialising connection for restClient from the Env", e); + return false; + } + return response; + } + + /** + * This method will provide ES transport client. + * + * @return TransportClient + */ + public static RestHighLevelClient getRestClient() { + if (restClient == null) { + ProjectLogger.log( + "ConnectionManager:getRestClient eLastic search rest clinet is null ", + LoggerEnum.INFO.name()); + initialiseRestClientConnection(); + ProjectLogger.log( + "ConnectionManager:getRestClient after calling initialiseRestClientConnection ES client value ", + LoggerEnum.INFO.name()); + } + return restClient; + } + + /** + * This method will create the client instance for elastic search. + * + * @param clusterName String + * @param host List + * @return boolean + * @throws UnknownHostException + */ + private static boolean createRestClient(String clusterName, List host) { + HttpHost[] httpHost = new HttpHost[host.size()]; + for (int i = 0; i < host.size(); i++) { + httpHost[i] = new HttpHost(host.get(i), 9200); + } + restClient = new RestHighLevelClient(RestClient.builder(httpHost)); + ProjectLogger.log( + "ConnectionManager:createRestClient client initialisation done. ", LoggerEnum.INFO.name()); + return true; + } + + /** + * This class will be called by registerShutDownHook to register the call inside jvm , when jvm + * terminate it will call the run method to clean up the resource. + * + * @author Manzarul + */ + public static class ResourceCleanUp extends Thread { + @Override + public void run() { + try { + restClient.close(); + } catch (IOException e) { + e.printStackTrace(); + ProjectLogger.log( + "ConnectionManager:ResourceCleanUp error occured during restclient resource cleanup " + + e, + LoggerEnum.ERROR.name()); + } + } + } + + /** Register the hook for resource clean up. this will be called when jvm shut down. */ + public static void registerShutDownHook() { + Runtime runtime = Runtime.getRuntime(); + runtime.addShutdownHook(new ResourceCleanUp()); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ElasticSearchMapping.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ElasticSearchMapping.java new file mode 100644 index 0000000000..c7c6c0d9af --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ElasticSearchMapping.java @@ -0,0 +1,21 @@ +/** */ +package org.sunbird.helper; + +/** + * This class will define Elastic search mapping. + * + * @author Manzarul + */ +public class ElasticSearchMapping { + + /** + * This method will define ES default mapping. + * + * @return + */ + public static String createMapping() { + String mapping = + " { \"dynamic_templates\": [ {\"longs\": {\"match_mapping_type\": \"long\", \"mapping\": {\"type\": \"long\", \"fields\": { \"raw\": {\"type\": \"long\" } }}}},{\"booleans\": {\"match_mapping_type\": \"boolean\", \"mapping\": {\"type\": \"boolean\", \"fields\": { \"raw\": { \"type\": \"boolean\" }} }}},{\"doubles\": {\"match_mapping_type\": \"double\",\"mapping\": {\"type\": \"double\",\"fields\":{\"raw\": { \"type\": \"double\" } }}}},{ \"dates\": {\"match_mapping_type\": \"date\", \"mapping\": { \"type\": \"date\",\"fields\": {\"raw\": { \"type\": \"date\" } } }}},{\"strings\": {\"match_mapping_type\": \"string\",\"mapping\": {\"type\": \"text\",\"fielddata\": true,\"copy_to\": \"all_fields\",\"analyzer\": \"cs_index_analyzer\",\"search_analyzer\": \"cs_search_analyzer\",\"fields\": {\"raw\": {\"type\": \"text\",\"fielddata\": true,\"analyzer\": \"keylower\"}}}}}],\"properties\": {\"all_fields\": {\"type\": \"text\",\"analyzer\": \"cs_index_analyzer\",\"search_analyzer\": \"cs_search_analyzer\",\"fields\": { \"raw\": { \"type\": \"text\",\"analyzer\": \"keylower\" } }} }}"; + return mapping; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ElasticSearchSettings.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ElasticSearchSettings.java new file mode 100644 index 0000000000..577e5d2b31 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/java/org/sunbird/helper/ElasticSearchSettings.java @@ -0,0 +1,21 @@ +/** */ +package org.sunbird.helper; + +/** + * This class will define Elastic search default settings. + * + * @author Manzarul + */ +public class ElasticSearchSettings { + + /** + * This method will do default settings for Elastic search index + * + * @return String + */ + public static String createSettingsForIndex() { + String settings = + "{\"analysis\": {\"analyzer\": {\"cs_index_analyzer\": {\"type\": \"custom\",\"tokenizer\": \"standard\",\"filter\": [\"lowercase\",\"mynGram\"]},\"cs_search_analyzer\": {\"type\": \"custom\",\"tokenizer\": \"standard\",\"filter\": [\"lowercase\",\"standard\"]},\"keylower\": {\"type\": \"custom\",\"tokenizer\": \"keyword\",\"filter\": \"lowercase\"}},\"filter\": {\"mynGram\": {\"type\": \"ngram\",\"min_gram\": 1,\"max_gram\": 20,\"token_chars\": [\"letter\", \"digit\",\"whitespace\",\"punctuation\",\"symbol\"]} }}}"; + return settings; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/elasticsearch.conf b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/elasticsearch.conf new file mode 100644 index 0000000000..4691424b95 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/elasticsearch.conf @@ -0,0 +1,76 @@ + { + mapping = { + searchindex = { + user = { + index = "user", + "type" = "_doc" + }, + org = { + index = "org", + "type" = "_doc" + }, + cbatch = { + index = "cbatch", + "type" = "_doc" + }, + badgeassociations = { + index = "badgeassociations", + "type" = "_doc" + }, + content = { + index = "content", + "type" = "_doc" + }, + usercourses = { + index = "usercourses", + "type" = "_doc" + }, + usernotes = { + index = "usernotes", + "type" = "_doc" + }, + userprofilevisibility = { + index = "userprofilevisibility", + "type" = "_doc" + }, + telemetry = { + index = "telemetry", + "type" = "_doc" + }, + location = { + index = "location", + "type" = "_doc" + }, + cbatchstats = { + index = "cbatchstats", + "type" = "_doc" + } + }, + sunbirdplugin = { + announcementtype = { + index = "announcementtype", + "type" = "_doc" + }, + announcement = { + index = "announcement", + "type" = "_doc" + }, + metrics = { + index = "metrics", + "type" = "_doc" + } + }, + sbtestindex = { + sbtesttype = { + index = "sbtestindex", + "type" = "sbtesttype" + } + }, + searchtest = { + usertest = { + index = "searchtest", + "type" = "usertest" + } + } + } + } diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/announcement.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/announcement.json new file mode 100644 index 0000000000..8f091e230e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/announcement.json @@ -0,0 +1,397 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic_templates": [ + { + "longs": { + "match_mapping_type": "long", + "mapping": { + "fields": { + "raw": { + "type": "long" + } + }, + "type": "long" + } + } + }, + { + "booleans": { + "match_mapping_type": "boolean", + "mapping": { + "fields": { + "raw": { + "type": "boolean" + } + }, + "type": "boolean" + } + } + }, + { + "doubles": { + "match_mapping_type": "double", + "mapping": { + "fields": { + "raw": { + "type": "double" + } + }, + "type": "double" + } + } + }, + { + "dates": { + "match_mapping_type": "date", + "mapping": { + "fields": { + "raw": { + "type": "date" + } + }, + "type": "date" + } + } + }, + { + "strings": { + "match_mapping_type": "string", + "mapping": { + "analyzer": "cs_index_analyzer", + "copy_to": "all_fields", + "fielddata": true, + "fields": { + "raw": { + "type": "text", + "fielddata": true, + "analyzer": "keylower" + } + }, + "search_analyzer": "cs_search_analyzer", + "type": "text" + } + } + } + ], + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "attachments": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createddate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "details": { + "properties": { + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "filename": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "from": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "title": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "links": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "sentcount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "sourceId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "sourceid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "target": { + "properties": { + "geo": { + "properties": { + "ids": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } + }, + "userid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/announcementtype.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/announcementtype.json new file mode 100644 index 0000000000..50ec50544c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/announcementtype.json @@ -0,0 +1,233 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic_templates": [ + { + "longs": { + "match_mapping_type": "long", + "mapping": { + "fields": { + "raw": { + "type": "long" + } + }, + "type": "long" + } + } + }, + { + "booleans": { + "match_mapping_type": "boolean", + "mapping": { + "fields": { + "raw": { + "type": "boolean" + } + }, + "type": "boolean" + } + } + }, + { + "doubles": { + "match_mapping_type": "double", + "mapping": { + "fields": { + "raw": { + "type": "double" + } + }, + "type": "double" + } + } + }, + { + "dates": { + "match_mapping_type": "date", + "mapping": { + "fields": { + "raw": { + "type": "date" + } + }, + "type": "date" + } + } + }, + { + "strings": { + "match_mapping_type": "string", + "mapping": { + "analyzer": "cs_index_analyzer", + "copy_to": "all_fields", + "fielddata": true, + "fields": { + "raw": { + "type": "text", + "fielddata": true, + "analyzer": "keylower" + } + }, + "search_analyzer": "cs_search_analyzer", + "type": "text" + } + } + } + ], + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "createddate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootorgid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/badgeassociations.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/badgeassociations.json new file mode 100644 index 0000000000..a2fe645964 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/badgeassociations.json @@ -0,0 +1,249 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "badgeClassImage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "contentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "issuerId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "updatedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/cbatch.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/cbatch.json new file mode 100644 index 0000000000..55ff6e2a0e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/cbatch.json @@ -0,0 +1,369 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "countDecrementDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "countDecrementStatus": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "countIncrementDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "countIncrementStatus": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "courseCreator": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdFor": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "endDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "enrollmentType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "mentors": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "startDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "reportUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/cbatchstats.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/cbatchstats.json new file mode 100644 index 0000000000..bbec753276 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/cbatchstats.json @@ -0,0 +1,257 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completedPercent": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "districtName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "enrolledOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "maskedEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskedPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subOrgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/course-batch.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/course-batch.json new file mode 100644 index 0000000000..adb3af3688 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/course-batch.json @@ -0,0 +1,47 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/location.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/location.json new file mode 100644 index 0000000000..57d5e52624 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/location.json @@ -0,0 +1,161 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "code": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "parentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "value": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/metrics.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/metrics.json new file mode 100644 index 0000000000..1785559cac --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/metrics.json @@ -0,0 +1,329 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic_templates": [ + { + "longs": { + "match_mapping_type": "long", + "mapping": { + "fields": { + "raw": { + "type": "long" + } + }, + "type": "long" + } + } + }, + { + "booleans": { + "match_mapping_type": "boolean", + "mapping": { + "fields": { + "raw": { + "type": "boolean" + } + }, + "type": "boolean" + } + } + }, + { + "doubles": { + "match_mapping_type": "double", + "mapping": { + "fields": { + "raw": { + "type": "double" + } + }, + "type": "double" + } + } + }, + { + "dates": { + "match_mapping_type": "date", + "mapping": { + "fields": { + "raw": { + "type": "date" + } + }, + "type": "date" + } + } + }, + { + "strings": { + "match_mapping_type": "string", + "mapping": { + "analyzer": "cs_index_analyzer", + "copy_to": "all_fields", + "fielddata": true, + "fields": { + "raw": { + "type": "text", + "fielddata": true, + "analyzer": "keylower" + } + }, + "search_analyzer": "cs_search_analyzer", + "type": "text" + } + } + } + ], + "properties": { + "activity": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "announcementId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "announcementid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "channel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createddate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootorgid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/org.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/org.json new file mode 100644 index 0000000000..61273d9dde --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/org.json @@ -0,0 +1,876 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "address": { + "properties": { + "addType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "country": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "channel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "contactDetail": { + "properties": { + "Email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "Phone ": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "Phone Number": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "Phonenumber": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "address": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "age": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "fax": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "contactdetails": { + "type": "object" + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "externalId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "homeUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "imgUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isDefault": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isRootOrg": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "locationId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "locationIds": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "noOfMembers": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "orgCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgTypeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "preferredLanguage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "provider": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "slug": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "theme": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/user-courses.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/user-courses.json new file mode 100644 index 0000000000..adb3af3688 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/user-courses.json @@ -0,0 +1,47 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/user.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/user.json new file mode 100644 index 0000000000..a08bef58fd --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/user.json @@ -0,0 +1,3605 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic":false, + "properties": { + "managedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "activeStatus": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "address": { + "properties": { + "addType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "country": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "appointmentType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "authenticationStatus": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "avatar": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeAssertions": { + "properties": { + "assertionId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "assertionid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassImage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeclassimage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeclassname": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdTS": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdTs": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "createdts": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "issuerId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "badges": { + "properties": { + "badgeTypeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "receiverId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "batches": { + "properties": { + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "enrolledOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastAccessedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "progress": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + } + } + }, + "channel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "classSubjectTaught": { + "properties": { + "classes": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subjects": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "countryCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "disabilityType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "education": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "boardOrUniversity": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "degree": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "percentage": { + "type": "double", + "fields": { + "raw": { + "type": "double" + } + } + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "yearOfPassing": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + } + } + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "emailVerified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "emailverified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "employmentState": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "firstName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "framework": { + "properties": { + "board": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gradeLevel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "medium": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "fullName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestAcademicQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestEnglishQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestMathQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestSSTQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestScienceQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestTeacherQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestVernacularLanguageQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isMasterTrainer": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "endDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isCurrentJob": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "jobName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "joiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "orgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "role": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "language": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "locationIds": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskedEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskedPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "masterTrainerSubjects": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "organisations": { + "properties": { + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addedByName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvalDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvaldate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isApproved": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isRejected": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "orgJoinDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgLeftDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "organisationId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgjoindate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "position": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phoneVerified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "phoneverified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileVisibility": { + "properties": { + "address": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "education": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "firstName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grades": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "language": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "socialMedia": { + "properties": { + "in": { + "properties": { + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "twitter": { + "properties": { + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subjects": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "test": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userSkills": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "webPages": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "provider": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "regOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "registryId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "schoolCode": { + "type": "double", + "fields": { + "raw": { + "type": "double" + } + } + }, + "schoolJoiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "serviceJoiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skills": { + "properties": { + "addedAt": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "endorsementCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsementcount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsers": { + "properties": { + "0283452c-a607-4184-9806-1fac2f16d5b9": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "39d460e8-80ef-4045-8fe0-de4a78e78bc4": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "3d45fbd8-b911-4cc5-b503-61215902d780": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "48a2fbc6-df85-4a41-8e68-7057986aee5a": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "62354c16-29c7-419c-8d30-a30491bef7c3": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "7526ab9d-e8a6-478b-83e2-6ff1296c302e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "9645e749-39f0-4b73-993d-09e633eeea1d": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a1355233-6b82-4660-86f5-73b95c03aec9": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a3d4151b-4d3e-4068-8950-d5b27b10487e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "b2fff05d-dfc9-497c-840e-5675a2b78e57": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "be7efb23-6af9-4d92-82b3-a4d78fcfa2f6": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "c9f23b5f-cd4c-42db-9a24-1f3ebc60dc9a": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "d5efd1ab-3cad-4034-8143-32c480f5cc9e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + } + } + }, + "endorsersList": { + "properties": { + "endorseDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skillName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skillNameToLowercase": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherInBRC": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherInCRC": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherSchoolBoardAffiliation": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherStatus": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "tncAcceptedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "tncAcceptedVersion": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "trainingsCompleted": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "vernacularLanguageStudied": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "webPages": { + "properties": { + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/usercourses.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/usercourses.json new file mode 100644 index 0000000000..1038ff76ba --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/usercourses.json @@ -0,0 +1,1181 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "active": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "contentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseLogoUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dateTime": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "delta": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "enrolledDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "firstName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "framework": { + "properties": { + "board": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gradeLevel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "medium": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastReadContentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastReadContentStatus": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "leafNodesCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "locationIds": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "organisations": { + "properties": { + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvaldate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isApproved": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isRejected": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "organisationId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgjoindate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "position": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileVisibility": { + "properties": { + "address": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "education": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "progress": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "properties": { + "endorsementCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsersList": { + "properties": { + "endorseDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skillName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skillNameToLowercase": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "tncAcceptedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "tncAcceptedVersion": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "tocUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/userfeed.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/userfeed.json new file mode 100644 index 0000000000..1ba018b740 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/userfeed.json @@ -0,0 +1,212 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic":false, + "properties": { + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "category": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "data": { + "type": "object" + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "priority": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "createdOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "expireOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "updatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/usernotes.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/usernotes.json new file mode 100644 index 0000000000..8cf7ff1455 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/usernotes.json @@ -0,0 +1,289 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "contentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "note": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "tags": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "title": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/userprofilevisibility.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/userprofilevisibility.json new file mode 100644 index 0000000000..c05c6579e9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/indices/userprofilevisibility.json @@ -0,0 +1,1641 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + }, + "mappings": { + "_doc": { + "dynamic": false, + "properties": { + "address": { + "properties": { + "addType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "country": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "avatar": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeAssertions": { + "properties": { + "assertionId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassImage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdts": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "issuerId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "countryCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "education": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "boardOrUniversity": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "degree": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "percentage": { + "type": "double", + "fields": { + "raw": { + "type": "double" + } + } + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "yearOfPassing": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + } + } + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "endDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isCurrentJob": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "jobName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "joiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "orgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "role": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "language": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "properties": { + "addedAt": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "endorsementCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsementcount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsers": { + "properties": { + "39d460e8-80ef-4045-8fe0-de4a78e78bc4": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "7526ab9d-e8a6-478b-83e2-6ff1296c302e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a1355233-6b82-4660-86f5-73b95c03aec9": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a3d4151b-4d3e-4068-8950-d5b27b10487e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "d5efd1ab-3cad-4034-8143-32c480f5cc9e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + } + } + }, + "endorsersList": { + "properties": { + "endorseDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skillName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skillNameToLowercase": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "webPages": { + "properties": { + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/announcement-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/announcement-mapping.json new file mode 100644 index 0000000000..08d45cadbb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/announcement-mapping.json @@ -0,0 +1,348 @@ +{ + "dynamic_templates": [ + { + "longs": { + "match_mapping_type": "long", + "mapping": { + "fields": { + "raw": { + "type": "long" + } + }, + "type": "long" + } + } + }, + { + "booleans": { + "match_mapping_type": "boolean", + "mapping": { + "fields": { + "raw": { + "type": "boolean" + } + }, + "type": "boolean" + } + } + }, + { + "doubles": { + "match_mapping_type": "double", + "mapping": { + "fields": { + "raw": { + "type": "double" + } + }, + "type": "double" + } + } + }, + { + "dates": { + "match_mapping_type": "date", + "mapping": { + "fields": { + "raw": { + "type": "date" + } + }, + "type": "date" + } + } + }, + { + "strings": { + "match_mapping_type": "string", + "mapping": { + "analyzer": "cs_index_analyzer", + "copy_to": "all_fields", + "fielddata": true, + "fields": { + "raw": { + "type": "text", + "fielddata": true, + "analyzer": "keylower" + } + }, + "search_analyzer": "cs_search_analyzer", + "type": "text" + } + } + } + ], + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "attachments": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createddate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "details": { + "properties": { + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "filename": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "from": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "title": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "links": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "sentcount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "sourceId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "sourceid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "target": { + "properties": { + "geo": { + "properties": { + "ids": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } + }, + "userid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/announcementtype-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/announcementtype-mapping.json new file mode 100644 index 0000000000..bc518e6319 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/announcementtype-mapping.json @@ -0,0 +1,184 @@ +{ + "dynamic_templates": [ + { + "longs": { + "match_mapping_type": "long", + "mapping": { + "fields": { + "raw": { + "type": "long" + } + }, + "type": "long" + } + } + }, + { + "booleans": { + "match_mapping_type": "boolean", + "mapping": { + "fields": { + "raw": { + "type": "boolean" + } + }, + "type": "boolean" + } + } + }, + { + "doubles": { + "match_mapping_type": "double", + "mapping": { + "fields": { + "raw": { + "type": "double" + } + }, + "type": "double" + } + } + }, + { + "dates": { + "match_mapping_type": "date", + "mapping": { + "fields": { + "raw": { + "type": "date" + } + }, + "type": "date" + } + } + }, + { + "strings": { + "match_mapping_type": "string", + "mapping": { + "analyzer": "cs_index_analyzer", + "copy_to": "all_fields", + "fielddata": true, + "fields": { + "raw": { + "type": "text", + "fielddata": true, + "analyzer": "keylower" + } + }, + "search_analyzer": "cs_search_analyzer", + "type": "text" + } + } + } + ], + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "createddate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootorgid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/badgeassociations-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/badgeassociations-mapping.json new file mode 100644 index 0000000000..dc2ada59d0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/badgeassociations-mapping.json @@ -0,0 +1,200 @@ +{ + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "badgeClassImage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "contentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "issuerId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "updatedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/cbatch-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/cbatch-mapping.json new file mode 100644 index 0000000000..558dad77cf --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/cbatch-mapping.json @@ -0,0 +1,344 @@ +{ + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "countDecrementDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "countDecrementStatus": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "countIncrementDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "countIncrementStatus": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "courseCreator": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdFor": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "endDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "enrollmentEndDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "enrollmentType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "mentors": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "startDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "participantCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "completedCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "reportUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/cbatchstats-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/cbatchstats-mapping.json new file mode 100644 index 0000000000..082136d3b0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/cbatchstats-mapping.json @@ -0,0 +1,208 @@ +{ + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completedPercent": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "districtName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "enrolledOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "maskedEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskedPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subOrgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/course-batch-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/course-batch-mapping.json new file mode 100644 index 0000000000..722516897d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/course-batch-mapping.json @@ -0,0 +1,264 @@ +{ + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdFor": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "endDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "enrollmentEndDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "enrollmentType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "mentors": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "startDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "participantCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "completedCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "reportUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/location-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/location-mapping.json new file mode 100644 index 0000000000..39c416274f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/location-mapping.json @@ -0,0 +1,112 @@ +{ + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "code": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "parentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "value": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/metrics-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/metrics-mapping.json new file mode 100644 index 0000000000..a68e93c225 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/metrics-mapping.json @@ -0,0 +1,280 @@ +{ + "dynamic_templates": [ + { + "longs": { + "match_mapping_type": "long", + "mapping": { + "fields": { + "raw": { + "type": "long" + } + }, + "type": "long" + } + } + }, + { + "booleans": { + "match_mapping_type": "boolean", + "mapping": { + "fields": { + "raw": { + "type": "boolean" + } + }, + "type": "boolean" + } + } + }, + { + "doubles": { + "match_mapping_type": "double", + "mapping": { + "fields": { + "raw": { + "type": "double" + } + }, + "type": "double" + } + } + }, + { + "dates": { + "match_mapping_type": "date", + "mapping": { + "fields": { + "raw": { + "type": "date" + } + }, + "type": "date" + } + } + }, + { + "strings": { + "match_mapping_type": "string", + "mapping": { + "analyzer": "cs_index_analyzer", + "copy_to": "all_fields", + "fielddata": true, + "fields": { + "raw": { + "type": "text", + "fielddata": true, + "analyzer": "keylower" + } + }, + "search_analyzer": "cs_search_analyzer", + "type": "text" + } + } + } + ], + "properties": { + "activity": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "announcementId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "announcementid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "channel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createddate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootorgid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/org-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/org-mapping.json new file mode 100644 index 0000000000..94d8edacdb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/org-mapping.json @@ -0,0 +1,827 @@ +{ + "dynamic": false, + "properties": { + "address": { + "properties": { + "addType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "country": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "channel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "contactDetail": { + "properties": { + "Email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "Phone ": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "Phone Number": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "Phonenumber": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "address": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "age": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "fax": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "contactdetails": { + "type": "object" + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "externalId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "homeUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "imgUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isDefault": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isRootOrg": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "locationId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "locationIds": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "noOfMembers": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "orgCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgTypeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "preferredLanguage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "provider": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "slug": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "theme": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/user-courses-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/user-courses-mapping.json new file mode 100644 index 0000000000..e67b5de92e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/user-courses-mapping.json @@ -0,0 +1,397 @@ +{ + "dynamic": false, + "properties": { + "active": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dateTime": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "delta": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "enrolledDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastReadContentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastReadContentStatus": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "progress": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "contentStatus": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completionPercentage": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "certificates": { + "type": "nested", + "properties": { + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "token": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastIssuedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastReIssuedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/user-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/user-mapping.json new file mode 100644 index 0000000000..c60b64ea1f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/user-mapping.json @@ -0,0 +1,3588 @@ +{ + "dynamic": false, + "properties": { + "managedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "activeStatus": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "address": { + "properties": { + "addType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "country": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "appointmentType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "authenticationStatus": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "avatar": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeAssertions": { + "properties": { + "assertionId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "assertionid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassImage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeclassimage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeclassname": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeid": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdTS": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdTs": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "createdts": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "issuerId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "badges": { + "properties": { + "badgeTypeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "receiverId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "batches": { + "properties": { + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "enrolledOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastAccessedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "progress": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + } + } + }, + "channel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "classSubjectTaught": { + "properties": { + "classes": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subjects": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "countryCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "disabilityType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "education": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "boardOrUniversity": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "degree": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "percentage": { + "type": "double", + "fields": { + "raw": { + "type": "double" + } + } + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "yearOfPassing": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + } + } + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "prevUsedEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "emailVerified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "emailverified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "employmentState": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "firstName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "framework": { + "properties": { + "board": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gradeLevel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "medium": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "fullName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestAcademicQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestEnglishQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestMathQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestSSTQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestScienceQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestTeacherQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "highestVernacularLanguageQualification": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isMasterTrainer": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "endDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isCurrentJob": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "jobName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "joiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "orgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "role": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "language": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "locationIds": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskedEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "maskedPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "masterTrainerSubjects": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "organisations": { + "properties": { + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addedByName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvalDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvaldate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isApproved": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isRejected": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "orgJoinDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgLeftDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "organisationId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgjoindate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "position": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "prevUsedPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phoneVerified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "phoneverified": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileVisibility": { + "properties": { + "address": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "education": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "firstName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grades": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "language": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "socialMedia": { + "properties": { + "in": { + "properties": { + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "twitter": { + "properties": { + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subjects": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "test": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userSkills": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "webPages": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "provider": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "regOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "registryId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "schoolCode": { + "type": "double", + "fields": { + "raw": { + "type": "double" + } + } + }, + "schoolJoiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "serviceJoiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skills": { + "properties": { + "addedAt": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "endorsementCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsementcount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsers": { + "properties": { + "0283452c-a607-4184-9806-1fac2f16d5b9": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "39d460e8-80ef-4045-8fe0-de4a78e78bc4": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "3d45fbd8-b911-4cc5-b503-61215902d780": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "48a2fbc6-df85-4a41-8e68-7057986aee5a": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "62354c16-29c7-419c-8d30-a30491bef7c3": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "7526ab9d-e8a6-478b-83e2-6ff1296c302e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "9645e749-39f0-4b73-993d-09e633eeea1d": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a1355233-6b82-4660-86f5-73b95c03aec9": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a3d4151b-4d3e-4068-8950-d5b27b10487e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "b2fff05d-dfc9-497c-840e-5675a2b78e57": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "be7efb23-6af9-4d92-82b3-a4d78fcfa2f6": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "c9f23b5f-cd4c-42db-9a24-1f3ebc60dc9a": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "d5efd1ab-3cad-4034-8143-32c480f5cc9e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + } + } + }, + "endorsersList": { + "properties": { + "endorseDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skillName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skillNameToLowercase": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherInBRC": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherInCRC": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherSchoolBoardAffiliation": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherStatus": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "teacherType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "tncAcceptedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "tncAcceptedVersion": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "trainingsCompleted": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "vernacularLanguageStudied": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "webPages": { + "properties": { + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/usercourses-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/usercourses-mapping.json new file mode 100644 index 0000000000..df068fcd5d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/usercourses-mapping.json @@ -0,0 +1,1132 @@ +{ + "dynamic": false, + "properties": { + "active": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "batchId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completedOn": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "contentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseLogoUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dateTime": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "delta": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "description": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encEmail": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "encPhone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "enrolledDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "firstName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "framework": { + "properties": { + "board": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gradeLevel": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "medium": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastReadContentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastReadContentStatus": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "leafNodesCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "locationIds": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "organisations": { + "properties": { + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvaldate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "approvedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "hashTagId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isApproved": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "isRejected": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "organisationId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgjoindate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "position": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileVisibility": { + "properties": { + "address": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "education": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "progress": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "roles": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "rootOrgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "properties": { + "endorsementCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsersList": { + "properties": { + "endorseDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skillName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skillNameToLowercase": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "status": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "tncAcceptedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "tncAcceptedVersion": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "tocUrl": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/userfeed-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/userfeed-mapping.json new file mode 100644 index 0000000000..deba277e57 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/userfeed-mapping.json @@ -0,0 +1,163 @@ +{ + "dynamic":false, + "properties": { + "status": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "category": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "data": { + "type": "object" + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "priority": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "createdOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "expireOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "updatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/usernotes-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/usernotes-mapping.json new file mode 100644 index 0000000000..c2aa64bfa2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/usernotes-mapping.json @@ -0,0 +1,240 @@ +{ + "dynamic": false, + "properties": { + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "completeness": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "contentId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "courseId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isDeleted": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "missingFields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "note": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "tags": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "title": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/userprofilevisibility-mapping.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/userprofilevisibility-mapping.json new file mode 100644 index 0000000000..3a064c02b5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/mappings/userprofilevisibility-mapping.json @@ -0,0 +1,1592 @@ +{ + "dynamic": false, + "properties": { + "address": { + "properties": { + "addType": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "country": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "all_fields": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower" + } + }, + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer" + }, + "avatar": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeAssertions": { + "properties": { + "assertionId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassImage": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeClassName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "badgeId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdts": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "issuerId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "countryCode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "dob": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "education": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "boardOrUniversity": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "degree": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "percentage": { + "type": "double", + "fields": { + "raw": { + "type": "double" + } + } + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "yearOfPassing": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + } + } + }, + "email": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "gender": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "grade": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "identifier": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "jobProfile": { + "properties": { + "address": { + "properties": { + "addressLine1": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "addressLine2": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "city": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "state": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "zipcode": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "addressId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "endDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "isCurrentJob": { + "type": "boolean", + "fields": { + "raw": { + "type": "boolean" + } + } + }, + "jobName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "joiningDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "orgId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "orgName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "role": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "updatedDate": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "language": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "location": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "loginId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "phone": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "profileSummary": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skills": { + "properties": { + "addedAt": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "addedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "createdOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "endorsementCount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsementcount": { + "type": "long", + "fields": { + "raw": { + "type": "long" + } + } + }, + "endorsers": { + "properties": { + "39d460e8-80ef-4045-8fe0-de4a78e78bc4": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "7526ab9d-e8a6-478b-83e2-6ff1296c302e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a1355233-6b82-4660-86f5-73b95c03aec9": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "a3d4151b-4d3e-4068-8950-d5b27b10487e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "d5efd1ab-3cad-4034-8143-32c480f5cc9e": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + } + } + }, + "endorsersList": { + "properties": { + "endorseDate": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "id": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedBy": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "lastUpdatedOn": { + "type": "date", + "fields": { + "raw": { + "type": "date" + } + } + }, + "skillName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "skillNameToLowercase": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + }, + "subject": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userId": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "userName": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "webPages": { + "properties": { + "type": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + }, + "url": { + "type": "text", + "fields": { + "raw": { + "type": "text", + "analyzer": "keylower", + "fielddata": true + } + }, + "copy_to": [ + "all_fields" + ], + "analyzer": "cs_index_analyzer", + "search_analyzer": "cs_search_analyzer", + "fielddata": true + } + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/README.md b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/README.md new file mode 100644 index 0000000000..d1b3d52604 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/README.md @@ -0,0 +1,35 @@ +This is the script which will perform reindexing on Elasticsearch Index... + +## How to run + - give permission to the script chmod +x reindex.sh + - bash reindex.sh {{es_ip}} {{old_index}} {{new_index}} {{alias_name}} {{index_req_filePath}} {{mappings_req_filePath}} + + + +## CLI ARGS DESCRIPTION + - es_ip: Ip of ElasticSearch and port is assumed to be 9200 + - old_index: Source Index from which reindexing to be done + - new_index: Destination Index, to which reindexing to be done + - alias_name: Name of Alias to which new_index to be mapped and old index need to be removed. + - index_req_filepath: .json file path which will have a request body for creating new_index. + - mapping_req_filepath: .json file path which will have a request body for creating mappings of new_index. + + + **NOTE**: old_index will be deleted by the script.
+ + + ## Following Steps will be done by Script: + + 1: Validating Input params + a) File paths + b) ElasticSearch health
+ 2: *Creating Backup file.
+ 3: mapping alias_name with `old_index`.
+ 4: creating indices and mapping of `new_index`.
+ 5: Reindexing from `old_index` index to `new_index` index.
+ 6: deleting alias with `old_index` and mapping alias with `new_index`.
+ 7: deleting `old_index`.
+ + +*BackUp file may not contain all the ES records(due to size limit in ES).
+SOURCE : https://engineering.carsguide.com.au/elasticsearch-zero-downtime-reindexing-e3a53000f0ac diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/indices/certreg_indices.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/indices/certreg_indices.json new file mode 100644 index 0000000000..8dca30f045 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/indices/certreg_indices.json @@ -0,0 +1,47 @@ +{ + "settings": { + "index": { + "number_of_shards": "5", + "number_of_replicas": "1", + "analysis": { + "filter": { + "mynGram": { + "token_chars": [ + "letter", + "digit", + "whitespace", + "punctuation", + "symbol" + ], + "min_gram": "1", + "type": "ngram", + "max_gram": "20" + } + }, + "analyzer": { + "cs_index_analyzer": { + "filter": [ + "lowercase", + "mynGram" + ], + "type": "custom", + "tokenizer": "standard" + }, + "keylower": { + "filter": "lowercase", + "type": "custom", + "tokenizer": "keyword" + }, + "cs_search_analyzer": { + "filter": [ + "lowercase", + "standard" + ], + "type": "custom", + "tokenizer": "standard" + } + } + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/mappings/certreg_mappings.json b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/mappings/certreg_mappings.json new file mode 100644 index 0000000000..d1ec23ab43 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/mappings/certreg_mappings.json @@ -0,0 +1,200 @@ +{ + "dynamic":"false", + "properties":{ + "accessCode":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + }, + "createdAt":{ + "type":"date", + "fields":{ + "raw":{ + "type":"date" + } + } + }, + "createdBy":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + }, + "data":{ + "type":"object" + }, + "id":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + }, + "isRevoked":{ + "type":"boolean", + "fields":{ + "raw":{ + "type":"boolean" + } + } + }, + "jsonUrl":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + }, + "pdfUrl":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + }, + "reason":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + }, + "recipient":{ + "properties":{ + "id":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + }, + "type":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + } + } + }, + "related":{ + "properties":{ + "type":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + } + } + }, + "updatedAt":{ + "type":"date", + "fields":{ + "raw":{ + "type":"date" + } + } + }, + "updatedBy":{ + "type":"text", + "fields":{ + "raw":{ + "type":"text", + "analyzer":"keylower", + "fielddata":true + } + }, + "copy_to":[ + "all_fields" + ], + "analyzer":"cs_index_analyzer", + "search_analyzer":"cs_search_analyzer", + "fielddata":true + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/reindex.sh b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/reindex.sh new file mode 100755 index 0000000000..9fc38b77f0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/main/resources/reindexing/reindex.sh @@ -0,0 +1,175 @@ +#!/bin/bash +set -eu -o pipefail + +perform_reindexing(){ + +echo ">>STEP1: mapping $alias_name with $old_index index" + + +alias_old_index_status=$( curl -s --write-out %{http_code} --silent --output --location --request POST 'http://'$es_ip':9200/_aliases?pretty' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "actions" : [ + { "add" : { "index" : "'$old_index'", "alias" : "'$alias_name'" } } + ] +}') + + +if [[ $alias_old_index_status == 200 ]] ; then + echo "'$old_index' index successfully map to alias $alias_name with status code 200" +else + echo "STEP1 FAILED:$old_index index is unable to map with alias $alias_name with status code $alias_old_index_status hence exiting program....." + exit 1 +fi + + +echo ">>STEP2: creating '$new_index' index" + +index_status_code=$( curl -s --write-out %{http_code} --silent --output --location --request PUT 'http://'$es_ip':9200/'$new_index'' \ +--header 'Content-Type: application/json' \ +-d @$index_req_filepath) + +if [[ $index_status_code == 200 ]] ; then + echo "'$new_index' index successfully created with status code 200" +else + echo "STEP2 FAILED:'$new_index' index is unable to create with status code $index_status_code hence exiting program....." + exit 1 +fi + +echo ">>STEP3: creating mapping of '$new_index' index\n" + +mapping_status_code=$( curl -s --write-out %{http_code} --silent --output --location --request PUT 'http://'$es_ip':9200/'$new_index'/_doc/_mapping' \ +--header 'Content-Type: application/json' \ +-d @$mapping_req_filepath) + +if [[ $mapping_status_code == 200 ]] ; then + echo "'$new_index' index mappings successfully created with status code 200" +else + echo "STEP3 FAILED:'$new_index' index is unable to create mappings with status code $mapping_status_code hence exiting program......" + exit 1 +fi + +echo ">>STEP4: copying $data_count certificates from '$old_index' index to '$new_index' index\n" + + +status_code=$( curl -s --write-out %{http_code} --silent --output --location --request POST 'http://'$es_ip':9200/_reindex' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "source": { + "index": "'$old_index'" + }, + "dest": { + "index": "'$new_index'" + } +}') + +if [[ $status_code == 200 ]] ; then + echo "$data_count certificates copied from '$old_index' to '$new_index' index with status code 200" +else + echo "STEP4 FAILED:to copy certificates with status code $status_code, please manually delete the temp index. exiting the program......" + exit 1 +fi + + +echo ">>STEP5: deleting $alias_name with $old_index index and mapping alias with $new_index" + +alias_new_index_status=$( curl -s --write-out %{http_code} --silent --output --location --request POST 'http://'$es_ip':9200/_aliases' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "actions" : [ + { "add" : { "index" : "'$new_index'", "alias" : "'$alias_name'" } }, + { "remove" : { "index" : "'$old_index'", "alias" : "'$alias_name'" }} + ] +}') + +if [[ $alias_new_index_status == 200 ]] ; then + echo "$alias_name successfully mapped to $new_index" +else + echo "$alias_name failed to map with $new_indexES with status code $alias_new_index_status, exiting....." + exit 1 +fi + +echo ">>STEP6: deleting previous $old_index index\n" + +index_delete_status_code=$( curl -s --write-out %{http_code} --silent --output --location --request DELETE 'http://'$es_ip':9200/'$old_index'' \ +--header 'Content-Type: application/json' ) + + +if [[ $index_delete_status_code == 200 ]] ; then + echo "$old_index index deleted with status code 200" +else + echo "STEP6 FAILED:to delete $old_index index with status code $index_delete_status_code exiting the program......" + exit 1 +fi + +} + + +echo "Starting REINDEXING PROGRAM IN ELASTICSEARCH......." + +es_ip=$1 +old_index=$2 +new_index=$3 +alias_name=$4 +index_req_filepath=$5 +mapping_req_filepath=$6 + +if [ "$#" -ne 6 ]; then + echo "PARAM INITIALIZATION FAILED, No command line arguments provided, Please provide esIp, old index, new index and alias name, index_req_filepath, mapping_req_filepath" + exit 1 +fi + + + +echo "checking provide file existence" + +[ -f "$index_req_filepath" ] || { echo "$index_req_filepath NOT FOUND" ; exit 1 ;} +[ -f "$mapping_req_filepath" ] || { echo "$mapping_req_filepath NOT FOUND" ; exit 1 ;} + + + + + +echo "ES_IP GOT: $es_ip\n" +echo "OLD INDEX(NEED TO BE DELETED) GOT: $old_index\n" +echo "NEW INDEX GOT: $new_index\n" +echo "Alias GOT: $alias_name\n" +echo "index json request path got $index_req_filepath" +echo "mapping request json path $mapping_req_filepath" +echo "=======Params Initialized==========\n" +echo "NOTE: IF ANY STEP FAILED PLEASE MANUALLY DELETE THE NEW INDEX from ElasticSearch i.e $new_index." + + + +eshealth_status_code=$( curl -s --write-out %{http_code} --silent --output --location --request GET 'http://'$es_ip':9200' \ +--header 'Content-Type: application/json' ) + +if [[ $eshealth_status_code == 200 ]] ; then + echo "ELASTICSEARCH IS ALIVE" +else + echo "ES is not alive please make sure es is up and running, exiting....." + exit 1 +fi + +DATE=`date "+%Y%m%d-%H%M%S"` +backup_file_name=certregBackup$DATE.txt +echo "PERFORMING '$old_index' BACKUP, can be found in file $backup_file_name" + +curl -s --location --request GET 'http://'$es_ip':9200/'$old_index'/_search?size=10000' --header 'Content-Type: application/json' --data-raw '{ + "query":{ + + "match_all":{} + + } +} + +' | jq '.' > $backup_file_name + + +data_count=$( curl -s --location --request GET 'http://'$es_ip':9200/'$old_index'/_count' --header 'Content-Type: application/json' --header 'Accept: text' | jq ."count" ) +echo "continue reindexing of $data_count records" +perform_reindexing + + + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/common/ElasticSearchRestHighImplTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/common/ElasticSearchRestHighImplTest.java new file mode 100644 index 0000000000..7dfc430778 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/common/ElasticSearchRestHighImplTest.java @@ -0,0 +1,465 @@ +package org.sunbird.common; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.doNothing; +import static org.powermock.api.mockito.PowerMockito.mock; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.action.bulk.BulkItemResponse; +import org.elasticsearch.action.bulk.BulkProcessor; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.delete.DeleteResponse; +import org.elasticsearch.action.get.GetRequestBuilder; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.action.update.UpdateResponse; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.util.concurrent.FutureUtils; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.aggregations.Aggregations; +import org.junit.Assert; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ConnectionManager; +import scala.concurrent.Future; + +/** + * Test class for Elastic search Rest High level client Impl + * + * @author github.com/iostream04 + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +@PrepareForTest({ + ConnectionManager.class, + RestHighLevelClient.class, + AcknowledgedResponse.class, + GetRequestBuilder.class, + HttpUtil.class, + BulkProcessor.class, + FutureUtils.class, + SearchHit.class, + SearchHits.class, + Aggregations.class, + ElasticSearchHelper.class +}) +public class ElasticSearchRestHighImplTest { + + private ElasticSearchService esService = EsClientFactory.getInstance(JsonKey.REST); + private static RestHighLevelClient client = null; + + @Before + public void initBeforeTest() { + mockBaseRules(); + mockRulesForSave(false); + } + + @Test + public void testSaveSuccess() { + mockRulesForSave(false); + Future result = esService.save("test", "001", new HashMap<>()); + String res = (String) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals("001", res); + } + + @Test + public void testSaveFailureWithEmptyIndex() { + + Future result = esService.save("", "001", new HashMap<>()); + String res = (String) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals("ERROR", res); + } + + @Test + public void testSaveFailureWithEmptyIdentifier() { + Future result = esService.save("test", "", new HashMap<>()); + String res = (String) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals("ERROR", res); + } + + @Test + public void testSaveFailure() { + mockRulesForSave(true); + Future result = esService.save("test", "001", new HashMap<>()); + String res = (String) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(null, res); + } + + @Test + public void testUpdateSuccess() { + mockRulesForUpdate(false); + Future result = esService.update("test", "001", new HashMap<>()); + boolean res = (boolean) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(true, res); + } + + @Test + public void testUpdateFailure() { + mockRulesForUpdate(true); + Future result = esService.update("test", "001", new HashMap<>()); + Object res = ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(null, res); + } + + @Test + public void testUpdateFailureWithEmptyIndex() { + try { + esService.update("", "001", new HashMap<>()); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testUpdateFailureWithEmptyIdentifier() { + try { + esService.update("test", "", new HashMap<>()); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testGetDataByIdentifierFailureWithEmptyIndex() { + try { + esService.getDataByIdentifier("", "001"); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testGetDataByIdentifierFailureWithEmptyIdentifier() { + try { + esService.getDataByIdentifier("test", ""); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testGetDataByIdentifierFailure() { + mockRulesForGet(true); + Future> result = esService.getDataByIdentifier("test", "001"); + Object res = ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(null, res); + } + + @Test + public void testDeleteSuccess() { + mockRulesForDelete(false, false); + Future result = esService.delete("test", "001"); + boolean res = (boolean) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(true, res); + } + + @Test + public void testDeleteSuccessWithoutDelete() { + mockRulesForDelete(false, true); + Future result = esService.delete("test", "001"); + boolean res = (boolean) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(false, res); + } + + @Test + public void testDeleteFailure() { + mockRulesForDelete(true, false); + Future result = esService.delete("test", "001"); + Object res = ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(null, res); + } + + @Test + public void testDeleteFailureWithEmptyIdentifier() { + try { + esService.delete("test", ""); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testDeleteFailureWithEmptyIndex() { + try { + esService.delete("", "001"); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testUpsertSuccess() { + mockRulesForUpdate(false); + Future result = esService.update("test", "001", new HashMap<>()); + boolean res = (boolean) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(true, res); + } + + @Test + public void testUpsertFailure() { + mockRulesForUpdate(true); + Future result = esService.update("test", "001", new HashMap<>()); + Object res = ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(null, res); + } + + @Test + public void testUpsertFailureWithEmptyIndex() { + try { + esService.update("", "001", new HashMap<>()); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testUpsertFailureWithEmptyIdentifier() { + try { + esService.update("test", "", new HashMap<>()); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), ResponseCode.invalidData.getResponseCode()); + } + } + + @Test + public void testBuilInsertSuccess() { + mockRulesForBulk(false); + List> list = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.IDENTIFIER, "0001"); + list.add(map); + Future result = esService.bulkInsert("test", list); + boolean res = (boolean) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(true, res); + } + + @Test + public void testBuilInsertFailure() { + mockRulesForBulk(true); + List> list = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.IDENTIFIER, "0001"); + list.add(map); + Future result = esService.bulkInsert("test", list); + boolean res = (boolean) ElasticSearchHelper.getResponseFromFuture(result); + assertEquals(false, res); + } + + private void mockBaseRules() { + client = mock(RestHighLevelClient.class); + PowerMockito.mockStatic(ConnectionManager.class); + try { + doNothing().when(ConnectionManager.class, "registerShutDownHook"); + } catch (Exception e) { + Assert.fail("Initialization of test case failed due to " + e.getLocalizedMessage()); + } + when(ConnectionManager.getRestClient()).thenReturn(client); + } + + private static void mockRulesForBulk(boolean fail) { + Iterator itr = mock(Iterator.class); + + BulkResponse response = mock(BulkResponse.class); + when(response.iterator()).thenReturn(itr); + when(itr.hasNext()).thenReturn(false); + + if (!fail) { + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + ((ActionListener) invocation.getArguments()[1]) + .onResponse(response); + return null; + } + }) + .when(client) + .bulkAsync(Mockito.any(), Mockito.any()); + } else { + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + + ((ActionListener) invocation.getArguments()[1]) + .onFailure(new NullPointerException()); + return null; + } + }) + .when(client) + .bulkAsync(Mockito.any(), Mockito.any()); + } + } + + private static void mockRulesForSave(boolean fail) { + IndexResponse ir = mock(IndexResponse.class); + when(ir.getId()).thenReturn("001"); + + if (!fail) { + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + ((ActionListener) invocation.getArguments()[1]).onResponse(ir); + return null; + } + }) + .when(client) + .indexAsync(Mockito.any(), Mockito.any()); + } else { + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + + ((ActionListener) invocation.getArguments()[1]) + .onFailure(new NullPointerException()); + return null; + } + }) + .when(client) + .indexAsync(Mockito.any(), Mockito.any()); + } + } + + @SuppressWarnings("rawtypes") + private static void mockRulesForUpdate(boolean fail) { + UpdateResponse updateRes = mock(UpdateResponse.class); + when(updateRes.getResult()).thenReturn(null); + + if (!fail) { + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + ((ActionListener) invocation.getArguments()[1]) + .onResponse(updateRes); + return null; + } + }) + .when(client) + .updateAsync(Mockito.any(), Mockito.any()); + } else { + + doAnswer( + new Answer() { + @SuppressWarnings("unchecked") + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + + ((ActionListener) invocation.getArguments()[1]) + .onFailure(new NullPointerException()); + return null; + } + }) + .when(client) + .updateAsync(Mockito.any(), Mockito.any()); + } + } + + @SuppressWarnings("rawtypes") + private static void mockRulesForGet(boolean fail) { + GetResponse getResponse = mock(GetResponse.class); + Map map = new HashMap<>(); + map.put("test", "any"); + when(getResponse.getSourceAsMap()).thenReturn(map); + when(getResponse.isExists()).thenReturn(true); + + if (!fail) { + + doAnswer( + new Answer() { + @SuppressWarnings("unchecked") + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + ((ActionListener) invocation.getArguments()[1]) + .onResponse(getResponse); + return null; + } + }) + .when(client) + .getAsync(Mockito.any(), Mockito.any()); + } else { + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + + ((ActionListener) invocation.getArguments()[1]) + .onFailure(new NullPointerException()); + return null; + } + }) + .when(client) + .getAsync(Mockito.any(), Mockito.any()); + } + } + + private static void mockRulesForDelete(boolean fail, boolean notFound) { + DeleteResponse delResponse = mock(DeleteResponse.class); + + if (!fail) { + if (notFound) { + when(delResponse.getResult()).thenReturn(DocWriteResponse.Result.NOT_FOUND); + } + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + ((ActionListener) invocation.getArguments()[1]) + .onResponse(delResponse); + return null; + } + }) + .when(client) + .deleteAsync(Mockito.any(), Mockito.any()); + } else { + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + + ((ActionListener) invocation.getArguments()[1]) + .onFailure(new NullPointerException()); + return null; + } + }) + .when(client) + .deleteAsync(Mockito.any(), Mockito.any()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/common/factory/EsClientFactoryTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/common/factory/EsClientFactoryTest.java new file mode 100644 index 0000000000..51db98ce04 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/common/factory/EsClientFactoryTest.java @@ -0,0 +1,21 @@ +package org.sunbird.common.factory; + +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.inf.ElasticSearchService; + +public class EsClientFactoryTest { + + @Test + public void testGetRestClient() { + ElasticSearchService service = EsClientFactory.getInstance("rest"); + Assert.assertTrue(service instanceof ElasticSearchRestHighImpl); + } + + @Test + public void testInstanceNull() { + ElasticSearchService service = EsClientFactory.getInstance("test"); + Assert.assertNull(service); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ConnectionManagerTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ConnectionManagerTest.java new file mode 100644 index 0000000000..da88b4fe53 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ConnectionManagerTest.java @@ -0,0 +1,42 @@ +package org.sunbird.helper; + +import org.elasticsearch.action.bulk.BulkProcessor; +import org.elasticsearch.action.get.GetRequestBuilder; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.util.concurrent.FutureUtils; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.aggregations.Aggregations; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.models.util.HttpUtil; + +/** @author manzarul */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +@PrepareForTest({ + ConnectionManager.class, + AcknowledgedResponse.class, + GetRequestBuilder.class, + HttpUtil.class, + BulkProcessor.class, + FutureUtils.class, + SearchHit.class, + SearchHits.class, + Aggregations.class +}) +public class ConnectionManagerTest { + + // @Test + public void testGetRestClientNull() { + RestHighLevelClient client = ConnectionManager.getRestClient(); + Assert.assertNull(client); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ElasticSearchMappingTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ElasticSearchMappingTest.java new file mode 100644 index 0000000000..37ad6061a1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ElasticSearchMappingTest.java @@ -0,0 +1,13 @@ +package org.sunbird.helper; + +import org.junit.Assert; +import org.junit.Test; + +public class ElasticSearchMappingTest { + + @Test + public void testcreateMapping() { + String mapping = ElasticSearchMapping.createMapping(); + Assert.assertNotNull(mapping); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ElasticSearchSettingsTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ElasticSearchSettingsTest.java new file mode 100644 index 0000000000..f21f539c99 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/java/org/sunbird/helper/ElasticSearchSettingsTest.java @@ -0,0 +1,14 @@ +package org.sunbird.helper; + +import org.junit.Assert; +import org.junit.Test; + +public class ElasticSearchSettingsTest { + + @Test + public void testcreateSettingsForIndex() { + + String settings = ElasticSearchSettings.createSettingsForIndex(); + Assert.assertNotNull(settings); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/resources/elasticsearch.config.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/resources/elasticsearch.config.properties new file mode 100644 index 0000000000..84aafa4ddc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-es-utils/src/test/resources/elasticsearch.config.properties @@ -0,0 +1,3 @@ +es.cluster.name=test +es.host.name=localhost +es.host.port=9300 \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/.gitignore new file mode 100644 index 0000000000..9a4eed9248 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/.gitignore @@ -0,0 +1,8 @@ +/target/ +/.project +/.settings +/.classpath + +/bin/ + +*.iml diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/pom.xml new file mode 100644 index 0000000000..01108aed5d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + + org.sunbird + sunbird-notification + 1.0-SNAPSHOT + jar + + + 1.8 + 1.8 + UTF-8 + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.0.0 + + + package + + shade + + + + + classworlds:classworlds + junit:junit + jmock:* + *:xml-apis + org.apache.maven:lib:tests + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + + + + org.jboss.logging + jboss-logging + 3.3.1.Final + + + org.apache.httpcomponents + httpclient + 4.5.2 + + + junit + junit + 4.12 + test + + + org.powermock + powermock-module-junit4 + 1.6.5 + test + + + junit + junit + + + + + org.powermock + powermock-api-mockito + 1.6.5 + test + + + com.fasterxml.jackson.core + jackson-databind + 2.9.5 + + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/Sms.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/Sms.java new file mode 100644 index 0000000000..7959309ad9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/Sms.java @@ -0,0 +1,34 @@ +package org.sunbird.notification.sms; + +import java.io.Serializable; +import java.util.List; + +/** @author Manzarul */ +public class Sms implements Serializable { + + /** */ + private static final long serialVersionUID = -5055157442558614964L; + + private String message; + private List to; + + public Sms(String message, List to) { + this.message = message; + this.to = to; + } + + /** @return the serialversionuid */ + public static long getSerialversionuid() { + return serialVersionUID; + } + + /** @return the message */ + public String getMessage() { + return message; + } + + /** @return the to */ + public List getTo() { + return to; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/provider/ISmsProvider.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/provider/ISmsProvider.java new file mode 100644 index 0000000000..95ce9bc2bd --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/provider/ISmsProvider.java @@ -0,0 +1,37 @@ +package org.sunbird.notification.sms.provider; + +import java.util.List; + +public interface ISmsProvider { + + /** + * This method will send the SMS with default country code. default country code value will differ + * based on Installation, for sunbird default is 91 + * + * @param phoneNumber String + * @param smsText Sms text + * @return boolean + */ + boolean send(String phoneNumber, String smsText); + + /** + * This method will send SMS on user provider country code, basically it will override the value + * of default country code. + * + * @param phoneNumber String + * @param countryCode + * @param smsText + * @return boolean + */ + boolean send(String phoneNumber, String countryCode, String smsText); + + /** + * This method will send the SMS to list of phone number at the same time. default country code + * value will differ based on Installation, for sunbird default is 91 + * + * @param phoneNumber List + * @param smsText Sms text + * @return boolean + */ + boolean send(List phoneNumber, String smsText); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/provider/ISmsProviderFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/provider/ISmsProviderFactory.java new file mode 100644 index 0000000000..ba9f9f957c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/provider/ISmsProviderFactory.java @@ -0,0 +1,6 @@ +package org.sunbird.notification.sms.provider; + +public interface ISmsProviderFactory { + + ISmsProvider create(); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProvider.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProvider.java new file mode 100644 index 0000000000..bb6d5dddc0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProvider.java @@ -0,0 +1,447 @@ +package org.sunbird.notification.sms.providerimpl; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.apache.http.HttpEntity; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.jboss.logging.Logger; +import org.sunbird.notification.sms.Sms; +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.utils.JsonUtil; +import org.sunbird.notification.utils.PropertiesCache; + +public class Msg91SmsProvider implements ISmsProvider { + + private static Logger logger = Logger.getLogger(Msg91SmsProvider.class); + + private static String baseUrl = null; + private static String getUrl = null; + private static String postUrl = null; + private static String sender = null; + private static String smsRoute = null; + private static String smsMethodType = null; + private static String authKey = null; + private static String country = null; + + static { + boolean resposne = init(); + logger.info("SMS configuration values are set ==" + resposne); + } + + /** this method will do the SMS properties initialization. */ + public static boolean init() { + baseUrl = PropertiesCache.getInstance().getProperty("sunbird.msg.91.baseurl"); + getUrl = PropertiesCache.getInstance().getProperty("sunbird.msg.91.get.url"); + postUrl = PropertiesCache.getInstance().getProperty("sunbird.msg.91.post.url"); + sender = System.getenv("sunbird_msg_sender"); + if (JsonUtil.isStringNullOREmpty(sender)) { + sender = PropertiesCache.getInstance().getProperty("sunbird.msg.91.sender"); + } + smsRoute = PropertiesCache.getInstance().getProperty("sunbird.msg.91.route"); + smsMethodType = PropertiesCache.getInstance().getProperty("sunbird.msg.91.method"); + country = PropertiesCache.getInstance().getProperty("sunbird.msg.91.country"); + // first read authkey from ENV variable if not found then read it from property + // file. + authKey = System.getenv("sunbird_msg_91_auth"); + if (JsonUtil.isStringNullOREmpty(authKey)) { + authKey = PropertiesCache.getInstance().getProperty("sunbird.msg.91.auth"); + } + return validateSettings(); + } + + @Override + public boolean send(String phoneNumber, String smsText) { + if ("POST".equalsIgnoreCase(smsMethodType)) { + return sendSmsUsingPost(phoneNumber, smsText); + } + return sendSmsGetMethod(phoneNumber, smsText); + } + + @Override + public boolean send(String phoneNumber, String countryCode, String smsText) { + if ("POST".equalsIgnoreCase(smsMethodType)) { + return sendSmsUsingPost(phoneNumber, smsText); + } + return sendSmsGetMethod(phoneNumber, smsText); + } + + /** + * This method will send SMS using Post method + * + * @param mobileNumber String + * @param smsText String + * @return boolean + */ + private boolean sendSmsUsingPost(String mobileNumber, String smsText) { + logger.debug("Msg91SmsProvider@Sending " + smsText + " to mobileNumber " + mobileNumber); + logger.debug( + "Msg91SmsProvider@SMS Provider parameters \n" + + "Gateway - " + + baseUrl + + "\n" + + "authKey - " + + authKey + + "\n" + + "sender - " + + sender + + "\n" + + "country - " + + country + + "\n" + + "smsMethodType - " + + smsMethodType + + "\n" + + "smsRoute - " + + smsRoute + + "\n"); + + CloseableHttpClient httpClient = null; + try { + httpClient = HttpClients.createDefault(); + + String path = null; + + if (validateSettings(mobileNumber, smsText)) { + String tempMobileNumber = removePlusFromMobileNumber(mobileNumber); + + logger.debug("Msg91SmsProvider - after removePlusFromMobileNumber " + tempMobileNumber); + path = baseUrl + postUrl; + logger.debug("Msg91SmsProvider -Executing request - " + path); + + HttpPost httpPost = new HttpPost(path); + + // add content-type headers + httpPost.setHeader("content-type", "application/json"); + + // add authkey header + httpPost.setHeader("authkey", authKey); + + List mobileNumbers = new ArrayList<>(); + mobileNumbers.add(tempMobileNumber); + + // create sms + Sms sms = new Sms(getDoubleEncodedSMS(smsText), mobileNumbers); + + List smsList = new ArrayList<>(); + smsList.add(sms); + + // create body + ProviderDetails providerDetails = + new ProviderDetails(sender, smsRoute, country, 1, smsList); + + String providerDetailsString = JsonUtil.toJson(providerDetails); + + if (!JsonUtil.isStringNullOREmpty(providerDetailsString)) { + logger.debug("Msg91SmsProvider - Body - " + providerDetailsString); + + HttpEntity entity = + new ByteArrayEntity(providerDetailsString.getBytes(StandardCharsets.UTF_8)); + httpPost.setEntity(entity); + + CloseableHttpResponse response = httpClient.execute(httpPost); + StatusLine sl = response.getStatusLine(); + response.close(); + if (sl.getStatusCode() != 200) { + logger.error( + "SMS code for " + + tempMobileNumber + + " could not be sent: " + + sl.getStatusCode() + + " - " + + sl.getReasonPhrase()); + } + return sl.getStatusCode() == 200; + } else { + return false; + } + + } else { + logger.debug("Msg91SmsProvider - Some mandatory parameters are empty!"); + return false; + } + } catch (IOException e) { + logger.error(e); + return false; + } catch (Exception e) { + logger.info("Msg91SmsProvider - Error in coverting providerDetails to string!"); + return false; + } finally { + closeHttpResource(httpClient); + } + } + + /** + * This method is used to send SMS using Get method + * + * @param mobileNumber String + * @param smsText String + * @return boolean + */ + public boolean sendSmsGetMethod(String mobileNumber, String smsText) { + CloseableHttpClient httpClient = null; + try { + httpClient = HttpClients.createDefault(); + String path = null; + if (validateSettings(mobileNumber, smsText)) { + + String tempMobileNumber = removePlusFromMobileNumber(mobileNumber); + + logger.debug("Msg91SmsProvider - after removePlusFromMobileNumber " + tempMobileNumber); + + logger.debug("Inside GET"); + path = + getCompletePath( + baseUrl + getUrl, + sender, + smsRoute, + tempMobileNumber, + authKey, + URLEncoder.encode(getDoubleEncodedSMS(smsText), "UTF-8")); + + logger.debug("Msg91SmsProvider -Executing request - " + path); + + HttpGet httpGet = new HttpGet(path); + + CloseableHttpResponse response = httpClient.execute(httpGet); + StatusLine sl = response.getStatusLine(); + response.close(); + if (sl.getStatusCode() != 200) { + logger.error( + "SMS code for " + + tempMobileNumber + + " could not be sent: " + + sl.getStatusCode() + + " - " + + sl.getReasonPhrase()); + } + return sl.getStatusCode() == 200; + + } else { + logger.debug("Msg91SmsProvider - Some mandatory parameters are empty!"); + return false; + } + } catch (IOException e) { + logger.error(e); + return false; + } finally { + closeHttpResource(httpClient); + } + } + + /** + * Removing + symbol from mobile number + * + * @param mobileNumber String + * @return String + */ + private String removePlusFromMobileNumber(String mobileNumber) { + logger.debug("Msg91SmsProvider - removePlusFromMobileNumber " + mobileNumber); + + if (mobileNumber.startsWith("+")) { + return mobileNumber.substring(1); + } + return mobileNumber; + } + + /** + * This method will create complete request path + * + * @param gateWayUrl String + * @param sender String (SMS receiver will get this name as sender) + * @param smsRoute String + * @param mobileNumber String + * @param authKey String (SMS gateway key) + * @param smsText String + * @return String + */ + private String getCompletePath( + String gateWayUrl, + String sender, + String smsRoute, + String mobileNumber, + String authKey, + String smsText) { + StringBuilder builder = new StringBuilder(); + builder.append(gateWayUrl).append("sender=").append(sender).append("&route=").append(smsRoute); + builder.append("&mobiles=").append(mobileNumber).append("&authkey=").append(authKey); + builder.append("&message=").append(getDoubleEncodedSMS(smsText)); + return builder.toString(); + } + + /** + * This method will close the http resource. + * + * @param httpClient + */ + private void closeHttpResource(CloseableHttpClient httpClient) { + if (httpClient != null) { + try { + httpClient.close(); + } catch (IOException e) { + logger.error(e); + } + } + } + + /** + * @param phone + * @param smsText + * @return + */ + private boolean validateSettings(String phone, String smsText) { + if (!JsonUtil.isStringNullOREmpty(sender) + && !JsonUtil.isStringNullOREmpty(smsRoute) + && !JsonUtil.isStringNullOREmpty(phone) + && !JsonUtil.isStringNullOREmpty(authKey) + && !JsonUtil.isStringNullOREmpty(country) + && !JsonUtil.isStringNullOREmpty(smsText)) { + return true; + } + logger.error("SMS value is not configure properly."); + return false; + } + + /** @return */ + private static boolean validateSettings() { + if (!JsonUtil.isStringNullOREmpty(sender) + && !JsonUtil.isStringNullOREmpty(smsRoute) + && !JsonUtil.isStringNullOREmpty(authKey) + && !JsonUtil.isStringNullOREmpty(country)) { + return true; + } + logger.error("SMS value is not configure properly."); + return false; + } + + @Override + public boolean send(List phoneNumber, String smsText) { + List phoneNumberList = null; + logger.debug("Msg91SmsProvider@Sending " + smsText + " to mobileNumber "); + logger.debug( + "Msg91SmsProvider@SMS Provider parameters \n" + + "Gateway - " + + baseUrl + + "\n" + + "authKey - " + + authKey + + "\n" + + "sender - " + + sender + + "\n" + + "country - " + + country + + "\n" + + "smsMethodType - " + + smsMethodType + + "\n" + + "smsRoute - " + + smsRoute + + "\n"); + if (JsonUtil.isStringNullOREmpty(smsText)) { + logger.debug("can't sent empty msg."); + return false; + } + phoneNumberList = validatePhoneList(phoneNumber); + if (phoneNumberList == null || phoneNumberList.isEmpty()) { + logger.debug("can't sent msg with empty phone list."); + return false; + } + CloseableHttpClient httpClient = null; + try { + httpClient = HttpClients.createDefault(); + + String path = null; + logger.debug("Inside POST"); + + path = baseUrl + postUrl; + logger.debug("Msg91SmsProvider -Executing request - " + path); + + HttpPost httpPost = new HttpPost(path); + + // add content-type headers + httpPost.setHeader("content-type", "application/json"); + + // add authkey header + httpPost.setHeader("authkey", authKey); + // create sms + Sms sms = new Sms(getDoubleEncodedSMS(smsText), phoneNumberList); + + List smsList = new ArrayList<>(); + smsList.add(sms); + + // create body + ProviderDetails providerDetails = new ProviderDetails(sender, smsRoute, country, 1, smsList); + + String providerDetailsString = JsonUtil.toJson(providerDetails); + + if (!JsonUtil.isStringNullOREmpty(providerDetailsString)) { + logger.debug("Msg91SmsProvider - Body - " + providerDetailsString); + + HttpEntity entity = + new ByteArrayEntity(providerDetailsString.getBytes(StandardCharsets.UTF_8)); + httpPost.setEntity(entity); + + CloseableHttpResponse response = httpClient.execute(httpPost); + StatusLine sl = response.getStatusLine(); + response.close(); + if (sl.getStatusCode() != 200) { + logger.error( + "SMS code for " + + phoneNumberList + + " could not be sent: " + + sl.getStatusCode() + + " - " + + sl.getReasonPhrase()); + } + return sl.getStatusCode() == 200; + } else { + return false; + } + + } catch (IOException e) { + logger.error(e); + return false; + } catch (Exception e) { + logger.error("Msg91SmsProvider : send : error in converting providerDetails to String"); + return false; + } finally { + closeHttpResource(httpClient); + } + } + + /** + * This method will verify list of phone numbers. if any phone number is empty or null then will + * remove it form list. + * + * @param phones List + * @return List + */ + private List validatePhoneList(List phones) { + if (phones != null) { + Iterator itr = phones.iterator(); + while (itr.hasNext()) { + String phone = itr.next(); + if (JsonUtil.isStringNullOREmpty(phone) || phone.length() < 10) { + itr.remove(); + } + } + } + return phones; + } + + private String getDoubleEncodedSMS(String smsText) { + String smsUtf8 = new String(smsText.getBytes(), StandardCharsets.UTF_8); + String doubleEncodedSMS = new String(smsUtf8.getBytes(), StandardCharsets.UTF_8); + return doubleEncodedSMS; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProviderFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProviderFactory.java new file mode 100644 index 0000000000..54d4f4ec6d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/Msg91SmsProviderFactory.java @@ -0,0 +1,17 @@ +package org.sunbird.notification.sms.providerimpl; + +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.sms.provider.ISmsProviderFactory; + +public class Msg91SmsProviderFactory implements ISmsProviderFactory { + + private static Msg91SmsProvider msg91SmsProvider = null; + + @Override + public ISmsProvider create() { + if (msg91SmsProvider == null) { + msg91SmsProvider = new Msg91SmsProvider(); + } + return msg91SmsProvider; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/ProviderDetails.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/ProviderDetails.java new file mode 100644 index 0000000000..40349e3904 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/sms/providerimpl/ProviderDetails.java @@ -0,0 +1,55 @@ +package org.sunbird.notification.sms.providerimpl; + +import java.io.Serializable; +import java.util.List; +import org.sunbird.notification.sms.Sms; + +/** @author Manzarul */ +public class ProviderDetails implements Serializable { + /** */ + private static final long serialVersionUID = 6602089097922616775L; + + private String sender; + private String route; + private String country; + private int unicode; + private List sms; + + public ProviderDetails(String sender, String route, String country, int unicode, List sms) { + this.sender = sender; + this.route = route; + this.country = country; + this.sms = sms; + this.unicode = unicode; + } + + /** @return the serialversionuid */ + public static long getSerialversionuid() { + return serialVersionUID; + } + + /** @return the sender */ + public String getSender() { + return sender; + } + + /** @return the route */ + public String getRoute() { + return route; + } + + /** @return the country */ + public String getCountry() { + return country; + } + + /** @return the sms */ + public List getSms() { + return sms; + } + + /** @return the unicode */ + public int getUnicode() { + return unicode; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/JsonUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/JsonUtil.java new file mode 100644 index 0000000000..07643733a1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/JsonUtil.java @@ -0,0 +1,41 @@ +package org.sunbird.notification.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import org.jboss.logging.Logger; + +public class JsonUtil { + private static Logger logger = Logger.getLogger(JsonUtil.class); + + public static String toJson(Object object) { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.writeValueAsString(object); + } catch (Exception e) { + // ProjectLogger.log("JsonUtil:getJsonString error occured : " + e, LoggerEnum.INFO); + } + return null; + } + + public static boolean isStringNullOREmpty(String value) { + if (value == null || "".equals(value.trim())) { + return true; + } + return false; + } + + public static T getAsObject(String res, Class clazz) { + ObjectMapper mapper = new ObjectMapper(); + + T result = null; + try { + JsonNode node = mapper.readTree(res); + result = mapper.convertValue(node, clazz); + } catch (IOException e) { + // ProjectLogger.log("JsonUtil:getAsObject error occured : " + e, LoggerEnum.INFO); + e.printStackTrace(); + } + return result; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/PropertiesCache.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/PropertiesCache.java new file mode 100644 index 0000000000..da63829d5c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/PropertiesCache.java @@ -0,0 +1,51 @@ +package org.sunbird.notification.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.jboss.logging.Logger; + +public class PropertiesCache { + private static Logger logger = Logger.getLogger(PropertiesCache.class); + private final String fileName = "configuration.properties"; + private final Properties configProp = new Properties(); + + /** private default constructor */ + private PropertiesCache() { + InputStream in = this.getClass().getClassLoader().getResourceAsStream(fileName); + try { + configProp.load(in); + } catch (IOException e) { + logger.error("Error in properties cache", e); + } + } + + private static class LazyHolder { + private static final PropertiesCache INSTANCE = new PropertiesCache(); + } + + public static PropertiesCache getInstance() { + return LazyHolder.INSTANCE; + } + + /** + * Method to read value from resource file and if key not found then by default return key values + * itself. + * + * @param key + * @return + */ + public String getProperty(String key) { + return configProp.getProperty(key) != null ? configProp.getProperty(key) : null; + } + + /** + * Method to read value from resource file . + * + * @param key + * @return + */ + public String readProperty(String key) { + return configProp.getProperty(key); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/SMSFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/SMSFactory.java new file mode 100644 index 0000000000..32117b4ad3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/java/org/sunbird/notification/utils/SMSFactory.java @@ -0,0 +1,31 @@ +/** */ +package org.sunbird.notification.utils; + +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.sms.provider.ISmsProviderFactory; +import org.sunbird.notification.sms.providerimpl.Msg91SmsProviderFactory; + +/** + * This class will provide object of factory. + * + * @author Manzarul + */ +public class SMSFactory { + + /** + * This method will provide SMS Provide object to trigger the SMS it will by default return + * Msg91SmsProvider class instance + * + * @param objectName String ,{"91SMS","some other impl"} + * @return ISmsProvider + */ + public static ISmsProvider getInstance(String objectName) { + if ("91SMS".equalsIgnoreCase(objectName)) { + ISmsProviderFactory factory = new Msg91SmsProviderFactory(); + return factory.create(); + } else { + ISmsProviderFactory factory = new Msg91SmsProviderFactory(); + return factory.create(); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/resources/configuration.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/resources/configuration.properties new file mode 100644 index 0000000000..be140c6a98 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/main/resources/configuration.properties @@ -0,0 +1,8 @@ +sunbird.msg.91.country=91 +sunbird.msg.91.sender=TesSun +sunbird.msg.91.auth= +sunbird.msg.91.method=POST +sunbird.msg.91.route=4 +sunbird.msg.91.baseurl=http://api.msg91.com/ +sunbird.msg.91.get.url=api/sendhttp.php? +sunbird.msg.91.post.url=api/v2/sendsms diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/BaseMessageTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/BaseMessageTest.java new file mode 100644 index 0000000000..d43f867beb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/BaseMessageTest.java @@ -0,0 +1,56 @@ +package org.sunbird.notification.sms; + +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.spy; + +import org.apache.http.StatusLine; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.notification.utils.PropertiesCache; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +@PrepareForTest({HttpClients.class, PropertiesCache.class}) +public abstract class BaseMessageTest { + + @BeforeClass + public static void initMockRules() { + CloseableHttpClient httpClient = mock(CloseableHttpClient.class); + CloseableHttpResponse httpResp = mock(CloseableHttpResponse.class); + StatusLine statusLine = mock(StatusLine.class); + PowerMockito.mockStatic(HttpClients.class); + try { + doReturn(httpClient).when(HttpClients.class, "createDefault"); + doReturn(httpResp).when(httpClient).execute(Mockito.any(HttpPost.class)); + doReturn(statusLine).when(httpResp).getStatusLine(); + doReturn(200).when(statusLine).getStatusCode(); + } catch (Exception e) { + Assert.fail("Exception while mocking static " + e.getLocalizedMessage()); + } + + PropertiesCache pc = spy(PropertiesCache.getInstance()); + PowerMockito.mockStatic(PropertiesCache.class); + try { + doReturn(pc).when(PropertiesCache.class, "getInstance"); + } catch (Exception e) { + Assert.fail("Exception while mocking static " + e.getLocalizedMessage()); + } + // doReturn("randomString").when(pc).getProperty(Mockito.eq("sunbird.msg.91.auth")); + // + // doCallRealMethod().when(pc).getProperty(AdditionalMatchers.not(Mockito.eq("sunbird.msg.91.auth"))); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/Message91GetSMSTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/Message91GetSMSTest.java new file mode 100644 index 0000000000..4565c2959a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/Message91GetSMSTest.java @@ -0,0 +1,29 @@ +package org.sunbird.notification.sms; + +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.notification.sms.providerimpl.Msg91SmsProvider; + +public class Message91GetSMSTest extends BaseMessageTest { + + @Test + public void testSendSmsGetMethodSuccess() { + Msg91SmsProvider megObj = new Msg91SmsProvider(); + boolean response = megObj.sendSmsGetMethod("4321111111", "say hai!"); + Assert.assertTrue(response); + } + + @Test + public void testSendSmsGetMethodFailureWithoutMessage() { + Msg91SmsProvider megObj = new Msg91SmsProvider(); + boolean response = megObj.sendSmsGetMethod("4321111111", ""); + Assert.assertFalse(response); + } + + @Test + public void testSendSmsGetMethodFailureWithEmptySpace() { + Msg91SmsProvider megObj = new Msg91SmsProvider(); + boolean response = megObj.sendSmsGetMethod("4321111111", " "); + Assert.assertFalse(response); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/Message91Test.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/Message91Test.java new file mode 100644 index 0000000000..8c1e531ab4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/java/org/sunbird/notification/sms/Message91Test.java @@ -0,0 +1,137 @@ +package org.sunbird.notification.sms; + +import java.util.ArrayList; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.notification.sms.provider.ISmsProvider; +import org.sunbird.notification.sms.providerimpl.Msg91SmsProvider; +import org.sunbird.notification.utils.SMSFactory; + +public class Message91Test extends BaseMessageTest { + + @Test + public void testInitSuccess() { + boolean response = Msg91SmsProvider.init(); + Assert.assertTrue(response); + } + + @Test + public void testGetInstanceSuccessWithoutName() { + ISmsProvider object = SMSFactory.getInstance(null); + Assert.assertTrue(object instanceof Msg91SmsProvider); + } + + @Test + public void testGetInstanceSuccessWithName() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + Assert.assertTrue(object instanceof Msg91SmsProvider); + } + + @Test + public void testSendSuccess() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("9666666666", "test sms"); + Assert.assertTrue(response); + } + + @Test + public void testSendFailureWithFormattedPhone() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("(966) 3890-445", "test sms 122"); + Assert.assertFalse(response); + } + + @Test + public void testSendSuccessWithoutCountryCodeArg() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("919666666666", "test sms 122"); + Assert.assertTrue(response); + } + + @Test + public void testSendSuccessWithoutCountryCodeArgAndPlus() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("+919666666666", "test sms 122"); + Assert.assertTrue(response); + } + + @Test + public void testSendFailureWithEmptyPhone() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("", "test sms 122"); + Assert.assertFalse(response); + } + + @Test + public void testSendFailureWithEmptyMessage() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("9663890445", ""); + Assert.assertFalse(response); + } + + @Test + public void testSendWithEmptyPhoneAndMessage() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("", ""); + Assert.assertFalse(response); + } + + @Test + public void testSendFailureWithInvalidPhone() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("981se12345", "some message"); + Assert.assertFalse(response); + } + + @Test + public void testSendSuccessWithValidPhone() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("1111111111", "some message"); + Assert.assertTrue(response); + } + + @Test + public void testSendSuccessWithCountryCode() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("1234567898", "91", "some message"); + Assert.assertTrue(response); + } + + @Test + public void testSendSuccessWithCountryCodeAndPlus() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + boolean response = object.send("0000000000", "+91", "some message"); + Assert.assertTrue(response); + } + + @Test + public void testSendSuccessWithMultiplePhones() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + List phones = new ArrayList<>(); + phones.add("1234567898"); + phones.add("1111111111"); + boolean response = object.send(phones, "some message"); + Assert.assertTrue(response); + } + + @Test + public void testSendFailureWithMultipleInvalidPhones() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + List phones = new ArrayList<>(); + phones.add("12345678"); + phones.add("11111"); + boolean response = object.send(phones, "some message"); + Assert.assertFalse(response); + } + + @Test + public void testSendFailureWithMultipleInvalidPhonesAndEmptyMsg() { + ISmsProvider object = SMSFactory.getInstance("91SMS"); + List phones = new ArrayList<>(); + phones.add("12345678"); + phones.add("11111"); + boolean response = object.send(phones, " "); + Assert.assertFalse(response); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/resources/configuration.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/resources/configuration.properties new file mode 100644 index 0000000000..a62d293b4c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-notification/src/test/resources/configuration.properties @@ -0,0 +1,8 @@ +sunbird.msg.91.country=91 +sunbird.msg.91.sender=TesSun +sunbird.msg.91.auth=randomstring +sunbird.msg.91.method=POST +sunbird.msg.91.route=4 +sunbird.msg.91.baseurl=http://api.msg91.com/ +sunbird.msg.91.get.url=api/sendhttp.php? +sunbird.msg.91.post.url=api/v2/sendsms diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/.gitignore new file mode 100644 index 0000000000..918338544d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/.gitignore @@ -0,0 +1,6 @@ +/target/ +/.classpath +/.project +/.settings +/logs +/bin/ diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/pom.xml new file mode 100644 index 0000000000..8429c2aee7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/pom.xml @@ -0,0 +1,139 @@ + + 4.0.0 + + org.sunbird + actor-core + 1.0-SNAPSHOT + actor-core + + 2.3.1 + 1.8 + 1.8 + UTF-8 + UTF-8 + 1.1.1 + 1.6.1 + 1.0.7 + 2.5.19 + + + + org.sunbird + common-util + 0.0.1-SNAPSHOT + + + com.typesafe.akka + akka-actor_2.11 + ${learner.akka.version} + + + com.typesafe.akka + akka-slf4j_2.11 + ${learner.akka.version} + + + com.typesafe.akka + akka-remote_2.11 + ${learner.akka.version} + + + org.reflections + reflections + 0.9.10 + + + log4j + log4j + 1.2.17 + + + com.fasterxml.jackson.core + jackson-core + 2.10.1 + + + com.fasterxml.jackson.core + jackson-databind + 2.10.1 + + + + + com.google.guava + guava + 18.0 + + + io.netty + netty-codec + 4.1.11.Final + + + + io.netty + netty-transport + 4.1.11.Final + + + + io.netty + netty-buffer + 4.1.11.Final + + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + **/*Spec.java + **/*Test.java + + + + + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/BaseActor.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/BaseActor.java new file mode 100644 index 0000000000..ecb64606a1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/BaseActor.java @@ -0,0 +1,107 @@ +package org.sunbird.actor.core; + +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import akka.actor.UntypedAbstractActor; +import akka.util.Timeout; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import org.sunbird.actor.router.BackgroundRequestRouter; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actor.service.BaseMWService; +import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import scala.concurrent.duration.Duration; + +public abstract class BaseActor extends UntypedAbstractActor { + + public abstract void onReceive(Request request) throws Throwable; + + public static final int AKKA_WAIT_TIME = 30; + protected static Timeout timeout = new Timeout(AKKA_WAIT_TIME, TimeUnit.SECONDS); + + @Override + public void onReceive(Object message) throws Throwable { + if (message instanceof Request) { + Request request = (Request) message; + String operation = request.getOperation(); + ProjectLogger.log( + "BaseActor: onReceive called for operation: " + operation, LoggerEnum.INFO.name()); + try { + onReceive(request); + } catch (Exception e) { + ProjectLogger.log( + "BaseActor: FAILED onReceive called for operation: " + operation, + LoggerEnum.INFO.name()); + onReceiveException(operation, e); + } + } + } + + public void tellToAnother(Request request) { + SunbirdMWService.tellToBGRouter(request, self()); + } + + public void unSupportedMessage() throws Exception { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + + public void onReceiveUnsupportedOperation(String callerName) throws Exception { + ProjectLogger.log(callerName + ": unsupported message"); + unSupportedMessage(); + } + + public void onReceiveUnsupportedMessage(String callerName) { + ProjectLogger.log(callerName + ": unsupported operation"); + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidOperationName.getErrorCode(), + ResponseCode.invalidOperationName.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + + protected void onReceiveException(String callerName, Exception exception) throws Exception { + ProjectLogger.log( + "Exception in message processing for: " + + callerName + + " :: message: " + + exception.getMessage(), + exception); + sender().tell(exception, self()); + } + + protected ActorRef getActorRef(String operation) { + int waitTime = 10; + ActorSelection select = null; + ActorRef actor = RequestRouter.getActor(operation); + if (null != actor) { + return actor; + } else { + select = + (BaseMWService.getRemoteRouter(RequestRouter.class.getSimpleName()) == null + ? (BaseMWService.getRemoteRouter(BackgroundRequestRouter.class.getSimpleName())) + : BaseMWService.getRemoteRouter(RequestRouter.class.getSimpleName())); + CompletionStage futureActor = + select.resolveOneCS(Duration.create(waitTime, "seconds")); + try { + actor = futureActor.toCompletableFuture().get(); + } catch (Exception e) { + ProjectLogger.log( + "InterServiceCommunicationImpl : getResponse - unable to get actorref from actorselection " + + e.getMessage(), + e); + } + return actor; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/BaseRouter.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/BaseRouter.java new file mode 100644 index 0000000000..85b4ada438 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/BaseRouter.java @@ -0,0 +1,119 @@ +package org.sunbird.actor.core; + +import akka.actor.ActorRef; +import akka.actor.Props; +import akka.routing.FromConfig; +import java.util.Set; +import org.apache.commons.lang3.StringUtils; +import org.reflections.Reflections; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Mahesh Kumar Gangula */ +public abstract class BaseRouter extends BaseActor { + + public abstract String getRouterMode(); + + public abstract void route(Request request) throws Throwable; + + protected abstract void cacheActor(String key, ActorRef actor); + + @Override + public void onReceive(Request request) throws Throwable { + String senderPath = sender().path().toString(); + if (RouterMode.LOCAL.name().equalsIgnoreCase(getRouterMode()) + && !StringUtils.startsWith(senderPath, "akka://")) { + throw new RouterException( + "Invalid invocation of the router. Processing not possible from: " + senderPath); + } + route(request); + } + + private Set> getActors() { + synchronized (BaseRouter.class) { + Reflections reflections = new Reflections("org.sunbird"); + Set> actors = reflections.getSubTypesOf(BaseActor.class); + return actors; + } + } + + protected void initActors(ActorContext context, String name) { + Set> actors = getActors(); + for (Class actor : actors) { + ActorConfig routerDetails = actor.getAnnotation(ActorConfig.class); + if (null != routerDetails) { + String dispatcher = routerDetails.dispatcher(); + switch (name) { + case "BackgroundRequestRouter": + String[] bgOperations = routerDetails.asyncTasks(); + dispatcher = (StringUtils.isNotBlank(dispatcher)) ? dispatcher : "brr-usr-dispatcher"; + createActor(context, actor, bgOperations, dispatcher); + break; + case "RequestRouter": + String[] operations = routerDetails.tasks(); + dispatcher = (StringUtils.isNotBlank(dispatcher)) ? dispatcher : "rr-usr-dispatcher"; + createActor(context, actor, operations, dispatcher); + break; + default: + System.out.println("Router with name '" + name + "' not supported."); + break; + } + } else { + // System.out.println(actor.getSimpleName() + " don't have config."); + } + } + } + + private void createActor( + ActorContext context, + Class actor, + String[] operations, + String dispatcher) { + if (null != operations && operations.length > 0) { + Props props = null; + if (StringUtils.isNotBlank(dispatcher)) { + props = Props.create(actor).withDispatcher(dispatcher); + } else { + props = Props.create(actor); + } + ActorRef actorRef = + context.actorOf(FromConfig.getInstance().props(props), actor.getSimpleName()); + for (String operation : operations) { + String parentName = self().path().name(); + cacheActor(getKey(parentName, operation), actorRef); + } + } + } + + protected static String getKey(String name, String operation) { + return name + ":" + operation; + } + + protected static String getPropertyValue(String key) { + String mode = System.getenv(key); + if (StringUtils.isBlank(mode)) { + mode = PropertiesCache.getInstance().getProperty(key); + } + return mode; + } + + @Override + public void unSupportedMessage() { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, ActorRef.noSender()); + } + + @Override + public void onReceiveException(String callerName, Exception e) { + ProjectLogger.log(callerName + ": exception in message processing = " + e.getMessage(), e); + sender().tell(e, ActorRef.noSender()); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/RouterException.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/RouterException.java new file mode 100644 index 0000000000..8faa212ea3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/RouterException.java @@ -0,0 +1,12 @@ +package org.sunbird.actor.core; + +/** @author Mahesh Kumar Gangula */ +public class RouterException extends RuntimeException { + + /** */ + private static final long serialVersionUID = 7669891026222754334L; + + public RouterException(String message) { + super(message); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/RouterMode.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/RouterMode.java new file mode 100644 index 0000000000..a4e56629c2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/core/RouterMode.java @@ -0,0 +1,8 @@ +package org.sunbird.actor.core; + +/** @author Mahesh Kumar Gangula */ +public enum RouterMode { + OFF, + LOCAL, + REMOTE; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/ActorConfig.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/ActorConfig.java new file mode 100644 index 0000000000..b28de705f4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/ActorConfig.java @@ -0,0 +1,19 @@ +package org.sunbird.actor.router; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** @author Mahesh Kumar Gangula */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ActorConfig { + String[] tasks(); + + String[] asyncTasks(); + + String dispatcher() default ""; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/BackgroundRequestRouter.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/BackgroundRequestRouter.java new file mode 100644 index 0000000000..79ec41e140 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/BackgroundRequestRouter.java @@ -0,0 +1,59 @@ +package org.sunbird.actor.router; + +import akka.actor.ActorRef; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseRouter; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; + +/** @author Mahesh Kumar Gangula */ +public class BackgroundRequestRouter extends BaseRouter { + + private static String mode; + private static String name; + private static Map routingMap = new HashMap<>(); + + public BackgroundRequestRouter() { + getMode(); + } + + @Override + public void preStart() throws Exception { + super.preStart(); + name = self().path().name(); + initActors(getContext(), BackgroundRequestRouter.class.getSimpleName()); + } + + @Override + protected void cacheActor(String key, ActorRef actor) { + routingMap.put(key, actor); + } + + @Override + public void route(Request request) throws Throwable { + String operation = request.getOperation(); + ActorRef ref = routingMap.get(getKey(self().path().name(), operation)); + if (null != ref) { + ref.tell(request, self()); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + public String getRouterMode() { + return getMode(); + } + + public static String getMode() { + if (StringUtils.isBlank(mode)) { + mode = getPropertyValue(JsonKey.BACKGROUND_ACTOR_PROVIDER); + } + return mode; + } + + public static ActorRef getActor(String operation) { + return routingMap.get(getKey(name, operation)); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/RequestRouter.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/RequestRouter.java new file mode 100644 index 0000000000..b396cb5bf7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/router/RequestRouter.java @@ -0,0 +1,122 @@ +package org.sunbird.actor.router; + +import akka.actor.ActorRef; +import akka.dispatch.OnComplete; +import akka.pattern.Patterns; +import akka.util.Timeout; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseRouter; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import scala.concurrent.ExecutionContext; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +/** @author Mahesh Kumar Gangula */ +public class RequestRouter extends BaseRouter { + + private static String mode; + private static String name; + public static Map routingMap = new HashMap<>(); + + public RequestRouter() { + getMode(); + } + + @Override + public void preStart() throws Exception { + super.preStart(); + name = self().path().name(); + initActors(getContext(), RequestRouter.class.getSimpleName()); + } + + @Override + protected void cacheActor(String key, ActorRef actor) { + routingMap.put(key, actor); + } + + @Override + public void route(Request request) throws Throwable { + String operation = request.getOperation(); + ActorRef ref = routingMap.get(getKey(self().path().name(), operation)); + if (null != ref) { + route(ref, request, getContext().dispatcher()); + } else { + onReceiveUnsupportedOperation(request.getOperation()); + } + } + + public static ActorRef getActor(String operation) { + return routingMap.get(getKey(name, operation)); + } + + public String getRouterMode() { + return getMode(); + } + + public static String getMode() { + if (StringUtils.isBlank(mode)) { + mode = getPropertyValue(JsonKey.API_ACTOR_PROVIDER); + } + return mode; + } + + /** + * method will route the message to corresponding router pass into the argument . + * + * @param router + * @param message + * @return boolean + */ + private boolean route(ActorRef router, Request message, ExecutionContext ec) { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "Actor Service Call start for api ==" + + message.getOperation() + + " start time " + + startTime, + LoggerEnum.PERF_LOG); + Timeout timeout = new Timeout(Duration.create(message.getTimeout(), TimeUnit.SECONDS)); + Future future = Patterns.ask(router, message, timeout); + ActorRef parent = sender(); + future.onComplete( + new OnComplete() { + @Override + public void onComplete(Throwable failure, Object result) { + if (failure != null) { + // We got a failure, handle it here + ProjectLogger.log(failure.getMessage(), failure); + if (failure instanceof ProjectCommonException) { + parent.tell(failure, self()); + } else if (failure instanceof akka.pattern.AskTimeoutException) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.operationTimeout.getErrorCode(), + ResponseCode.operationTimeout.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + parent.tell(exception, self()); + + } else { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + parent.tell(exception, self()); + } + } else { + parent.tell(result, self()); + } + } + }, + ec); + return true; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/service/BaseMWService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/service/BaseMWService.java new file mode 100644 index 0000000000..3763c922d1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/service/BaseMWService.java @@ -0,0 +1,115 @@ +package org.sunbird.actor.service; + +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.routing.FromConfig; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.RouterMode; +import org.sunbird.actor.router.BackgroundRequestRouter; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; + +/** @author Mahesh Kumar Gangula */ +public class BaseMWService { + + public static Config config = + ConfigFactory.systemEnvironment().withFallback(ConfigFactory.load()); + private static String actorMode; + protected static ActorSystem system; + protected static String name = "SunbirdMWSystem"; + protected static ActorRef requestRouter; + protected static ActorRef bgRequestRouter; + + protected static String getMode() { + if (StringUtils.isBlank(actorMode)) { + List routers = + Arrays.asList(RequestRouter.getMode(), BackgroundRequestRouter.getMode()); + long localCount = + routers.stream().filter(mode -> StringUtils.equalsIgnoreCase(mode, "local")).count(); + actorMode = (routers.size() == localCount) ? "local" : "remote"; + } + return actorMode; + } + + public static Object getRequestRouter() { + if (null != requestRouter) return requestRouter; + else { + return getRemoteRouter(RequestRouter.class.getSimpleName()); + } + } + + public static Object getBackgroundRequestRouter() { + if (null != bgRequestRouter) return bgRequestRouter; + else { + return getRemoteRouter(BackgroundRequestRouter.class.getSimpleName()); + } + } + + public static ActorSelection getRemoteRouter(String router) { + String path = null; + if (BackgroundRequestRouter.class.getSimpleName().equals(router)) { + path = config.getString("sunbird_remote_bg_req_router_path"); + return system.actorSelection(path); + } else if (RequestRouter.class.getSimpleName().equals(router)) { + path = config.getString("sunbird_remote_req_router_path"); + return system.actorSelection(path); + } else { + return null; + } + } + + protected static ActorSystem getActorSystem(String host, String port) { + if (null == system) { + Config conf; + if ("remote".equals(getMode())) { + Config remote = getRemoteConfig(host, port); + conf = remote.withFallback(config.getConfig(name)); + } else { + conf = config.getConfig(name); + } + ProjectLogger.log("ActorSystem starting with mode: " + getMode(), LoggerEnum.INFO.name()); + system = ActorSystem.create(name, conf); + } + return system; + } + + protected static Config getRemoteConfig(String host, String port) { + List details = new ArrayList(); + details.add("akka.actor.provider=akka.remote.RemoteActorRefProvider"); + details.add("akka.remote.enabled-transports = [\"akka.remote.netty.tcp\"]"); + if (StringUtils.isNotBlank(host)) details.add("akka.remote.netty.tcp.hostname=" + host); + if (StringUtils.isNotBlank(port)) details.add("akka.remote.netty.tcp.port=" + port); + + return ConfigFactory.parseString(StringUtils.join(details, ",")); + } + + protected static void initRouters() { + ProjectLogger.log("RequestRouter mode: " + RequestRouter.getMode(), LoggerEnum.INFO.name()); + if (!RouterMode.OFF.name().equalsIgnoreCase(RequestRouter.getMode())) { + requestRouter = + system.actorOf( + FromConfig.getInstance() + .props(Props.create(RequestRouter.class).withDispatcher("rr-dispatcher")), + RequestRouter.class.getSimpleName()); + } + ProjectLogger.log( + "BackgroundRequestRouter mode: " + BackgroundRequestRouter.getMode(), + LoggerEnum.INFO.name()); + if (!RouterMode.OFF.name().equalsIgnoreCase(BackgroundRequestRouter.getMode())) { + bgRequestRouter = + system.actorOf( + FromConfig.getInstance() + .props( + Props.create(BackgroundRequestRouter.class).withDispatcher("brr-dispatcher")), + BackgroundRequestRouter.class.getSimpleName()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/service/SunbirdMWService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/service/SunbirdMWService.java new file mode 100644 index 0000000000..04af0b6b10 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-core/src/main/java/org/sunbird/actor/service/SunbirdMWService.java @@ -0,0 +1,41 @@ +package org.sunbird.actor.service; + +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import org.sunbird.actor.router.BackgroundRequestRouter; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; + +/** @author Mahesh Kumar Gangula */ +public class SunbirdMWService extends BaseMWService { + + public static void init() { + String host = System.getenv(JsonKey.MW_SYSTEM_HOST); + String port = System.getenv(JsonKey.MW_SYSTEM_PORT); + getActorSystem(host, port); + initRouters(); + } + + public static void tellToRequestRouter(Request request, ActorRef sender) { + String operation = request.getOperation(); + ActorRef actor = RequestRouter.getActor(operation); + if (null == actor) { + ActorSelection select = getRemoteRouter(RequestRouter.class.getSimpleName()); + select.tell(request, sender); + } else { + actor.tell(request, sender); + } + } + + public static void tellToBGRouter(Request request, ActorRef sender) { + String operation = request.getOperation(); + ActorRef actor = BackgroundRequestRouter.getActor(operation); + if (null == actor) { + ActorSelection select = getRemoteRouter(BackgroundRequestRouter.class.getSimpleName()); + select.tell(request, sender); + } else { + actor.tell(request, sender); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/.gitignore new file mode 100644 index 0000000000..55977f8f94 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/.gitignore @@ -0,0 +1,7 @@ +/target/ +.classpath +.project +.settings +/bin/ + +*.iml diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/pom.xml new file mode 100644 index 0000000000..a5be7a916b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/pom.xml @@ -0,0 +1,87 @@ + + 4.0.0 + + org.sunbird + actor-util + 0.0.1-SNAPSHOT + jar + + actor-util + http://maven.apache.org + + + UTF-8 + 2.5.19 + + + + + com.typesafe.akka + akka-actor_2.11 + ${learner.akka.version} + + + com.typesafe.akka + akka-slf4j_2.11 + ${learner.akka.version} + + + com.typesafe.akka + akka-remote_2.11 + ${learner.akka.version} + + + + org.scala-lang + scala-library + 2.11.11 + + + + com.fasterxml.jackson.core + jackson-core + 2.10.1 + + + com.fasterxml.jackson.core + jackson-databind + 2.10.1 + + + org.apache.commons + commons-lang3 + 3.0 + + + org.sunbird + common-util + 0.0.1-SNAPSHOT + + + junit + junit + 3.8.1 + test + + + org.sunbird + sunbird-es-utils + 1.0-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/InterServiceCommunication.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/InterServiceCommunication.java new file mode 100644 index 0000000000..d62c171c94 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/InterServiceCommunication.java @@ -0,0 +1,23 @@ +package org.sunbird.actorutil; + +import akka.actor.ActorRef; +import org.sunbird.common.request.Request; +import scala.concurrent.Future; + +/** Interface for actor to actor communication. */ +public interface InterServiceCommunication { + + /** + * @param actorRef Actor reference + * @param request Request object + * @return Response object + */ + public Object getResponse(ActorRef actorRef, Request request); + + /* + * @param actorRef Actor reference + * @param request Request object + * @return Future for given actor and request operation + */ + public Future getFuture(ActorRef actorRef, Request request); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/InterServiceCommunicationFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/InterServiceCommunicationFactory.java new file mode 100644 index 0000000000..88c4a9ae6c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/InterServiceCommunicationFactory.java @@ -0,0 +1,26 @@ +package org.sunbird.actorutil; + +import org.sunbird.actorutil.impl.InterServiceCommunicationImpl; + +/** + * @Desc Factory class for InterServiceCommunication. + * + * @author Arvind + */ +public class InterServiceCommunicationFactory { + + private static InterServiceCommunication instance; + + private InterServiceCommunicationFactory() {} + + static { + instance = new InterServiceCommunicationImpl(); + } + + public static InterServiceCommunication getInstance() { + if (null == instance) { + instance = new InterServiceCommunicationImpl(); + } + return instance; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/courseenrollment/CourseEnrollmentClient.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/courseenrollment/CourseEnrollmentClient.java new file mode 100644 index 0000000000..999418579a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/courseenrollment/CourseEnrollmentClient.java @@ -0,0 +1,16 @@ +package org.sunbird.actorutil.courseenrollment; + +import akka.actor.ActorRef; +import java.util.Map; +import org.sunbird.common.models.response.Response; + +public interface CourseEnrollmentClient { + /** + * Unenroll user from course. + * + * @param actorRef Actor reference + * @param request Request containing unenroll information + * @return Response containing unenroll request status + */ + Response unenroll(ActorRef actorRef, Map request); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/courseenrollment/impl/CourseEnrollmentClientImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/courseenrollment/impl/CourseEnrollmentClientImpl.java new file mode 100644 index 0000000000..237c0bf3dc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/courseenrollment/impl/CourseEnrollmentClientImpl.java @@ -0,0 +1,44 @@ +package org.sunbird.actorutil.courseenrollment.impl; + +import akka.actor.ActorRef; +import java.util.Map; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.courseenrollment.CourseEnrollmentClient; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +public class CourseEnrollmentClientImpl implements CourseEnrollmentClient { + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + private static CourseEnrollmentClientImpl courseEnrollmentClient = null; + + public static CourseEnrollmentClientImpl getInstance() { + if (null == courseEnrollmentClient) { + courseEnrollmentClient = new CourseEnrollmentClientImpl(); + } + return courseEnrollmentClient; + } + + @Override + public Response unenroll(ActorRef actorRef, Map map) { + Request request = new Request(); + request.setOperation(ActorOperations.UNENROLL_COURSE.getValue()); + request.setRequest(map); + Object obj = interServiceCommunication.getResponse(actorRef, request); + if (obj instanceof Response) { + Response response = (Response) obj; + return response; + } else if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/EmailServiceClient.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/EmailServiceClient.java new file mode 100644 index 0000000000..463f2abc45 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/EmailServiceClient.java @@ -0,0 +1,16 @@ +package org.sunbird.actorutil.email; + +import akka.actor.ActorRef; +import java.util.Map; +import org.sunbird.common.models.response.Response; + +public interface EmailServiceClient { + /** + * Send mail user from course. + * + * @param actorRef Actor reference + * @param request Request containing email realted information + * @return Response containing email send status + */ + Response sendMail(ActorRef actorRef, Map request); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/EmailServiceFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/EmailServiceFactory.java new file mode 100644 index 0000000000..5891f4b2d8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/EmailServiceFactory.java @@ -0,0 +1,21 @@ +package org.sunbird.actorutil.email; + +import org.sunbird.actorutil.email.impl.EmailServiceClientImpl; + +public class EmailServiceFactory { + + private static EmailServiceClient instance; + + private EmailServiceFactory() {} + + static { + instance = new EmailServiceClientImpl(); + } + + public static EmailServiceClient getInstance() { + if (null == instance) { + instance = new EmailServiceClientImpl(); + } + return instance; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/impl/EmailServiceClientImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/impl/EmailServiceClientImpl.java new file mode 100644 index 0000000000..ea880fccac --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/email/impl/EmailServiceClientImpl.java @@ -0,0 +1,40 @@ +package org.sunbird.actorutil.email.impl; + +import akka.actor.ActorRef; +import java.util.HashMap; +import java.util.Map; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.email.EmailServiceClient; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +public class EmailServiceClientImpl implements EmailServiceClient { + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + + @Override + public Response sendMail(ActorRef actorRef, Map requestMap) { + Request actorRequest = new Request(); + Map request = new HashMap(); + request.put(JsonKey.EMAIL_REQUEST, requestMap); + actorRequest.setOperation((String) requestMap.get(JsonKey.REQUEST)); + actorRequest.setRequest(request); + + Object obj = interServiceCommunication.getResponse(actorRef, actorRequest); + if (obj instanceof Response) { + Response response = (Response) obj; + return response; + } else if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/impl/InterServiceCommunicationImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/impl/InterServiceCommunicationImpl.java new file mode 100644 index 0000000000..7cee8c1324 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/impl/InterServiceCommunicationImpl.java @@ -0,0 +1,59 @@ +package org.sunbird.actorutil.impl; + +import akka.actor.ActorRef; +import akka.pattern.Patterns; +import akka.util.Timeout; +import java.util.concurrent.TimeUnit; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +public class InterServiceCommunicationImpl implements InterServiceCommunication { + + private Timeout t = new Timeout(Duration.create(10, TimeUnit.SECONDS)); + + @Override + public Object getResponse(ActorRef actorRef, Request request) { + try { + return Await.result(getFuture(actorRef, request), t.duration()); + } catch (Exception e) { + ProjectLogger.log( + "InterServiceCommunicationImpl:getResponse: Exception occurred with error message = " + + e.getMessage(), + e); + ProjectCommonException.throwServerErrorException( + ResponseCode.unableToCommunicateWithActor, + ResponseCode.unableToCommunicateWithActor.getErrorMessage()); + } + return null; + } + + @Override + public Future getFuture(ActorRef actorRef, Request request) { + if (null == actorRef) { + ProjectLogger.log( + "InterServiceCommunicationImpl:getFuture: actorRef is null", LoggerEnum.INFO); + ProjectCommonException.throwServerErrorException( + ResponseCode.unableToCommunicateWithActor, + ResponseCode.unableToCommunicateWithActor.getErrorMessage()); + } + try { + return Patterns.ask(actorRef, request, t); + } catch (Exception e) { + ProjectLogger.log( + "InterServiceCommunicationImpl:getFuture: Exception occured with error message = " + + e.getMessage(), + e); + ProjectCommonException.throwServerErrorException( + ResponseCode.unableToCommunicateWithActor, + ResponseCode.unableToCommunicateWithActor.getErrorMessage()); + } + return null; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/location/LocationClient.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/location/LocationClient.java new file mode 100644 index 0000000000..4eb3189b72 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/location/LocationClient.java @@ -0,0 +1,63 @@ +package org.sunbird.actorutil.location; + +import akka.actor.ActorRef; +import java.util.List; +import org.sunbird.models.location.Location; +import org.sunbird.models.location.apirequest.UpsertLocationRequest; + +/** + * This interface defines methods supported by Location service. + * + * @author Amit Kumar + */ +public interface LocationClient { + + /** + * @desc This method will fetch location details by list of code. + * @param actorRef Actor reference. + * @param codeList List of location code. + * @return List of location. + */ + List getLocationsByCodes(ActorRef actorRef, List codeList); + + public List getLocationByIds(ActorRef actorRef, List idsList); + /** + * @desc This method will fetch location details by id. + * @param actorRef Actor reference. + * @param id Location id. + * @return Location details. + */ + Location getLocationById(ActorRef actorRef, String id); + + /** + * @desc This method will fetch location details by code. + * @param actorRef Actor reference. + * @param locationCode location code. + * @return Location details. + */ + Location getLocationByCode(ActorRef actorRef, String locationCode); + + /** + * @desc This method will create Location and returns the response. + * @param actorRef Actor reference. + * @param location Location details. + * @return Location id. + */ + String createLocation(ActorRef actorRef, UpsertLocationRequest location); + + /** + * @desc This method will update location details. + * @param actorRef Actor reference. + * @param location Location details. + */ + void updateLocation(ActorRef actorRef, UpsertLocationRequest location); + + /** + * @desc For given location codes, fetch location IDs (including, if any, those of its parent or + * ancestor(s) locations). + * @param actorRef Actor reference. + * @param codes List of location codes. + * @return List of related location IDs + */ + List getRelatedLocationIds(ActorRef actorRef, List codes); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/location/impl/LocationClientImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/location/impl/LocationClientImpl.java new file mode 100644 index 0000000000..d0653101ff --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/location/impl/LocationClientImpl.java @@ -0,0 +1,148 @@ +package org.sunbird.actorutil.location.impl; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.location.LocationClient; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.GeoLocationJsonKey; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LocationActorOperation; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.models.location.Location; +import org.sunbird.models.location.apirequest.UpsertLocationRequest; + +public class LocationClientImpl implements LocationClient { + + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + private ObjectMapper mapper = new ObjectMapper(); + + @Override + public List getLocationsByCodes(ActorRef actorRef, List codeList) { + return getSearchResponse(actorRef, GeoLocationJsonKey.CODE, codeList); + } + + @Override + public List getLocationByIds(ActorRef actorRef, List idsList) { + return getSearchResponse(actorRef, GeoLocationJsonKey.ID, idsList); + } + + @Override + public Location getLocationById(ActorRef actorRef, String id) { + List locationList = getSearchResponse(actorRef, JsonKey.ID, id); + if (CollectionUtils.isNotEmpty(locationList)) { + return locationList.get(0); + } else { + return null; + } + } + + private List getSearchResponse(ActorRef actorRef, String param, Object value) { + List response = null; + Map filters = new HashMap<>(); + Map searchRequestMap = new HashMap<>(); + filters.put(param, value); + searchRequestMap.put(JsonKey.FILTERS, filters); + Request request = new Request(); + request.setOperation(LocationActorOperation.SEARCH_LOCATION.getValue()); + request.getRequest().putAll(searchRequestMap); + ProjectLogger.log("LocationClientImpl : callSearchLocation ", LoggerEnum.INFO); + Object obj = interServiceCommunication.getResponse(actorRef, request); + if (obj instanceof Response) { + Response responseObj = (Response) obj; + List> responseList = + (List>) responseObj.getResult().get(JsonKey.RESPONSE); + return responseList + .stream() + .map(s -> mapper.convertValue(s, Location.class)) + .collect(Collectors.toList()); + } else { + response = new ArrayList<>(); + } + return response; + } + + @Override + public Location getLocationByCode(ActorRef actorRef, String locationCode) { + String param = GeoLocationJsonKey.CODE; + Object value = locationCode; + List locationList = getSearchResponse(actorRef, param, value); + if (CollectionUtils.isNotEmpty(locationList)) { + return locationList.get(0); + } else { + return null; + } + } + + @Override + public String createLocation(ActorRef actorRef, UpsertLocationRequest location) { + Request request = new Request(); + String locationId = null; + request.getRequest().putAll(mapper.convertValue(location, Map.class)); + Map resLocation = new HashMap<>(); + request.setOperation(LocationActorOperation.CREATE_LOCATION.getValue()); + ProjectLogger.log("LocationClientImpl : callCreateLocation ", LoggerEnum.INFO); + Object obj = interServiceCommunication.getResponse(actorRef, request); + checkLocationResponseForException(obj); + if (obj instanceof Response) { + Response response = (Response) obj; + locationId = (String) response.get(JsonKey.ID); + } + return locationId; + } + + @Override + public void updateLocation(ActorRef actorRef, UpsertLocationRequest location) { + Request request = new Request(); + request.getRequest().putAll(mapper.convertValue(location, Map.class)); + request.setOperation(LocationActorOperation.UPDATE_LOCATION.getValue()); + ProjectLogger.log("LocationClientImpl : callUpdateLocation ", LoggerEnum.INFO); + Object obj = interServiceCommunication.getResponse(actorRef, request); + checkLocationResponseForException(obj); + } + + @Override + public List getRelatedLocationIds(ActorRef actorRef, List codes) { + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.LOCATION_CODES, codes); + + Request request = new Request(); + request.setOperation(LocationActorOperation.GET_RELATED_LOCATION_IDS.getValue()); + request.getRequest().putAll(requestMap); + + ProjectLogger.log("LocationClientImpl: getRelatedLocationIds called", LoggerEnum.INFO); + Object obj = interServiceCommunication.getResponse(actorRef, request); + checkLocationResponseForException(obj); + + if (obj instanceof Response) { + Response responseObj = (Response) obj; + List responseList = (List) responseObj.getResult().get(JsonKey.RESPONSE); + return responseList; + } + + return new ArrayList<>(); + } + + private void checkLocationResponseForException(Object obj) { + if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else if (obj instanceof Exception) { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/org/OrganisationClient.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/org/OrganisationClient.java new file mode 100644 index 0000000000..bbc9cdd0fb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/org/OrganisationClient.java @@ -0,0 +1,69 @@ +package org.sunbird.actorutil.org; + +import akka.actor.ActorRef; +import java.util.List; +import java.util.Map; +import org.sunbird.models.organisation.Organisation; + +public interface OrganisationClient { + + /** + * Create organisation. + * + * @param actorRef Actor reference + * @param orgMap Organisation details + * @return Organisation ID + */ + String createOrg(ActorRef actorRef, Map orgMap); + + /** + * Update organisation details. + * + * @param actorRef Actor reference + * @param orgMap Organisation details + */ + void updateOrg(ActorRef actorRef, Map orgMap); + + /** + * Get details of organisation for given ID. + * + * @param actorRef Actor reference + * @param orgId Organisation ID + * @return Organisation details + */ + Organisation getOrgById(ActorRef actorRef, String orgId); + + /** + * Get details of organisation for given external ID and provider. + * + * @param externalId External ID + * @param provider provider + * @return Organisation details + */ + Organisation esGetOrgByExternalId(String externalId, String provider); + + /** + * Get details of organisation for given ID. + * + * @param orgId Organisation ID + * @return Organisation details + */ + Organisation esGetOrgById(String orgId); + + /** + * Search organisations using specified filter. + * + * @param filter Filter criteria for organisation search + * @return List of organisations + */ + List esSearchOrgByFilter(Map filter); + + /** + * Search organisations by IDs. + * + * @param orgIds List of org IDs + * @param outputColumns List of attributes required in each organisation search result + * @return List of organisations found + */ + List esSearchOrgByIds(List orgIds, List outputColumns); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/org/impl/OrganisationClientImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/org/impl/OrganisationClientImpl.java new file mode 100644 index 0000000000..0c131c5e17 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/org/impl/OrganisationClientImpl.java @@ -0,0 +1,197 @@ +package org.sunbird.actorutil.org.impl; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.models.organisation.Organisation; +import scala.concurrent.Future; + +public class OrganisationClientImpl implements OrganisationClient { + + public static OrganisationClient organisationClient = null; + public static OrganisationClient getInstance() { + if (organisationClient == null) { + synchronized (OrganisationClientImpl.class) { + if (organisationClient == null) { + organisationClient = new OrganisationClientImpl(); + } + } + } + return organisationClient; + } + + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + ObjectMapper objectMapper = new ObjectMapper(); + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public String createOrg(ActorRef actorRef, Map orgMap) { + ProjectLogger.log("OrganisationClientImpl: createOrg called", LoggerEnum.INFO); + return upsertOrg(actorRef, orgMap, ActorOperations.CREATE_ORG.getValue()); + } + + @Override + public void updateOrg(ActorRef actorRef, Map orgMap) { + ProjectLogger.log("OrganisationClientImpl: updateOrg called", LoggerEnum.INFO); + upsertOrg(actorRef, orgMap, ActorOperations.UPDATE_ORG.getValue()); + } + + private String upsertOrg(ActorRef actorRef, Map orgMap, String operation) { + String orgId = null; + + Request request = new Request(); + request.setRequest(orgMap); + request.setOperation(operation); + request.getContext().put(JsonKey.CALLER_ID, JsonKey.BULK_ORG_UPLOAD); + Object obj = interServiceCommunication.getResponse(actorRef, request); + + if (obj instanceof Response) { + Response response = (Response) obj; + orgId = (String) response.get(JsonKey.ORGANISATION_ID); + } else if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else if (obj instanceof Exception) { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + return orgId; + } + + @Override + public Organisation getOrgById(ActorRef actorRef, String orgId) { + ProjectLogger.log("OrganisationClientImpl: getOrgById called", LoggerEnum.INFO); + Organisation organisation = null; + + Request request = new Request(); + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.ORGANISATION_ID, orgId); + request.setRequest(requestMap); + request.setOperation(ActorOperations.GET_ORG_DETAILS.getValue()); + + Object obj = interServiceCommunication.getResponse(actorRef, request); + + if (obj instanceof Response) { + ObjectMapper objectMapper = new ObjectMapper(); + Response response = (Response) obj; + + // Convert contact details (received from ES) format from map to + // JSON string (as in Cassandra contact details are stored as text) + Map map = (Map) response.get(JsonKey.RESPONSE); + map.put(JsonKey.CONTACT_DETAILS, String.valueOf(map.get(JsonKey.CONTACT_DETAILS))); + organisation = objectMapper.convertValue(map, Organisation.class); + } else if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else if (obj instanceof Exception) { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + return organisation; + } + + @Override + public Organisation esGetOrgByExternalId(String externalId, String provider) { + Organisation organisation = null; + Map map = null; + SearchDTO searchDto = new SearchDTO(); + Map filter = new HashMap<>(); + filter.put(JsonKey.EXTERNAL_ID, externalId); + filter.put(JsonKey.PROVIDER, provider); + searchDto.getAdditionalProperties().put(JsonKey.FILTERS, filter); + Future> esResponseF = + esUtil.search(searchDto, ProjectUtil.EsType.organisation.getTypeName()); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponseF); + List> list = (List>) esResponse.get(JsonKey.CONTENT); + if (!list.isEmpty()) { + map = list.get(0); + map.put(JsonKey.CONTACT_DETAILS, String.valueOf(map.get(JsonKey.CONTACT_DETAILS))); + organisation = objectMapper.convertValue(map, Organisation.class); + } + return organisation; + } + + @Override + public Organisation esGetOrgById(String id) { + Map map = null; + Future> mapF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), id); + + map = (Map) ElasticSearchHelper.getResponseFromFuture(mapF); + if (MapUtils.isEmpty(map)) { + return null; + } else { + map.put(JsonKey.CONTACT_DETAILS, String.valueOf(map.get(JsonKey.CONTACT_DETAILS))); + return objectMapper.convertValue(map, Organisation.class); + } + } + + @Override + public List esSearchOrgByFilter(Map filter) { + SearchDTO searchDto = new SearchDTO(); + searchDto.getAdditionalProperties().put(JsonKey.FILTERS, filter); + return searchOrganisation(searchDto); + } + + @SuppressWarnings("unchecked") + private List searchOrganisation(SearchDTO searchDto) { + List orgList = new ArrayList<>(); + Future> resultF = + esUtil.search(searchDto, ProjectUtil.EsType.organisation.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + + List> orgMapList = (List>) result.get(JsonKey.CONTENT); + if (CollectionUtils.isNotEmpty(orgMapList)) { + for (Map orgMap : orgMapList) { + orgMap.put(JsonKey.CONTACT_DETAILS, String.valueOf(orgMap.get(JsonKey.CONTACT_DETAILS))); + orgList.add(objectMapper.convertValue(orgMap, Organisation.class)); + } + return orgList; + } else { + return Collections.emptyList(); + } + } + + @Override + public List esSearchOrgByIds(List orgIds, List outputColumns) { + SearchDTO searchDTO = new SearchDTO(); + + searchDTO.setFields(outputColumns); + + Map filters = new HashMap<>(); + filters.put(JsonKey.ID, orgIds); + + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + + return searchOrganisation(searchDTO); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/systemsettings/SystemSettingClient.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/systemsettings/SystemSettingClient.java new file mode 100644 index 0000000000..7e8f220f8d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/systemsettings/SystemSettingClient.java @@ -0,0 +1,34 @@ +package org.sunbird.actorutil.systemsettings; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.core.type.TypeReference; +import org.sunbird.models.systemsetting.SystemSetting; + +/** + * This interface defines methods supported by System Setting service. + * + * @author Amit Kumar + */ +public interface SystemSettingClient { + + /** + * Get system setting information for given field (setting) name. + * + * @param actorRef Actor reference + * @param field System setting field name + * @return System setting details + */ + SystemSetting getSystemSettingByField(ActorRef actorRef, String field); + + /** + * Get system setting information for given field (setting) and key name. + * + * @param actorRef Actor reference + * @param field System setting field name + * @param key Key (e.g. csv.mandatoryColumns) within system setting information + * @param typeReference Type reference for value corresponding to specified key + * @return System setting value corresponding to given field and key name + */ + T getSystemSettingByFieldAndKey( + ActorRef actorRef, String field, String key, TypeReference typeReference); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/systemsettings/impl/SystemSettingClientImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/systemsettings/impl/SystemSettingClientImpl.java new file mode 100644 index 0000000000..212d6710be --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/systemsettings/impl/SystemSettingClientImpl.java @@ -0,0 +1,88 @@ +package org.sunbird.actorutil.systemsettings.impl; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.models.systemsetting.SystemSetting; + +public class SystemSettingClientImpl implements SystemSettingClient { + + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + private static SystemSettingClient systemSettingClient = null; + + public static SystemSettingClient getInstance() { + if (null == systemSettingClient) { + systemSettingClient = new SystemSettingClientImpl(); + } + return systemSettingClient; + } + + @Override + public SystemSetting getSystemSettingByField(ActorRef actorRef, String field) { + ProjectLogger.log( + "SystemSettingClientImpl:getSystemSettingByField: field is " + field, + LoggerEnum.INFO.name()); + SystemSetting systemSetting = getSystemSetting(actorRef, JsonKey.FIELD, field); + return systemSetting; + } + + @Override + public T getSystemSettingByFieldAndKey( + ActorRef actorRef, String field, String key, TypeReference typeReference) { + SystemSetting systemSetting = getSystemSettingByField(actorRef, field); + ObjectMapper objectMapper = new ObjectMapper(); + if (systemSetting != null) { + try { + Map valueMap = objectMapper.readValue(systemSetting.getValue(), Map.class); + String[] keys = key.split("\\."); + int numKeys = keys.length; + for (int i = 0; i < numKeys - 1; i++) { + valueMap = objectMapper.convertValue(valueMap.get(keys[i]), Map.class); + } + return (T) objectMapper.convertValue(valueMap.get(keys[numKeys - 1]), typeReference); + } catch (Exception e) { + ProjectLogger.log( + "SystemSettingClientImpl:getSystemSettingByFieldAndKey: Exception occurred with error message = " + + e.getMessage(), + LoggerEnum.ERROR.name()); + } + } + return null; + } + + private SystemSetting getSystemSetting(ActorRef actorRef, String param, Object value) { + ProjectLogger.log("SystemSettingClientImpl: getSystemSetting called", LoggerEnum.DEBUG); + Request request = new Request(); + Map map = new HashMap<>(); + map.put(param, value); + request.setContext(map); + request.setOperation(ActorOperations.GET_SYSTEM_SETTING.getValue()); + Object obj = interServiceCommunication.getResponse(actorRef, request); + + if (obj instanceof Response) { + Response responseObj = (Response) obj; + return (SystemSetting) responseObj.getResult().get(JsonKey.RESPONSE); + } else if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/user/UserClient.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/user/UserClient.java new file mode 100644 index 0000000000..692a69d5b3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/user/UserClient.java @@ -0,0 +1,41 @@ +package org.sunbird.actorutil.user; + +import akka.actor.ActorRef; +import org.sunbird.common.request.Request; + +import java.util.Map; + +public interface UserClient { + + /** + * Create user. + * + * @param actorRef Actor reference + * @param userMap User details + * @return User ID + */ + String createUser(ActorRef actorRef, Map userMap); + + /** + * Update user details. + * + * @param actorRef Actor reference + * @param userMap User details + */ + void updateUser(ActorRef actorRef, Map userMap); + + /** Verify phone uniqueness across all users in the system. */ + void esVerifyPhoneUniqueness(); + + /** Verify email uniqueness across all users in the system. */ + void esVerifyEmailUniqueness(); + + /** + * Search user details. + * + * @param actorRef Actor reference + * @param req Search req + */ + Map searchManagedUser(ActorRef actorRef, Request req); + +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/user/impl/UserClientImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/user/impl/UserClientImpl.java new file mode 100644 index 0000000000..2b842c47a1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/actorutil/user/impl/UserClientImpl.java @@ -0,0 +1,183 @@ +package org.sunbird.actorutil.user.impl; + +import akka.actor.ActorRef; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import akka.pattern.Patterns; +import akka.util.Timeout; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.user.UserClient; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +public class UserClientImpl implements UserClient { + + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public String createUser(ActorRef actorRef, Map userMap) { + ProjectLogger.log("UserClientImpl: createUser called", LoggerEnum.INFO); + return upsertUser(actorRef, userMap, ActorOperations.CREATE_USER.getValue()); + } + + @Override + public void updateUser(ActorRef actorRef, Map userMap) { + ProjectLogger.log("UserClientImpl: updateUser called", LoggerEnum.INFO); + upsertUser(actorRef, userMap, ActorOperations.UPDATE_USER.getValue()); + } + + @Override + public void esVerifyPhoneUniqueness() { + esVerifyFieldUniqueness(JsonKey.ENC_PHONE, JsonKey.PHONE); + } + + @Override + public void esVerifyEmailUniqueness() { + esVerifyFieldUniqueness(JsonKey.ENC_EMAIL, JsonKey.EMAIL); + } + + private void esVerifyFieldUniqueness(String facetsKey, String objectType) { + SearchDTO searchDto = null; + searchDto = new SearchDTO(); + searchDto.setLimit(0); + + Map facets = new HashMap<>(); + facets.put(facetsKey, null); + List> list = new ArrayList<>(); + list.add(facets); + searchDto.setFacets(list); + + Future> esResponseF = + esUtil.search(searchDto, ProjectUtil.EsType.user.getTypeName()); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponseF); + + if (null != esResponse) { + List> facetsResponse = + (List>) esResponse.get(JsonKey.FACETS); + + if (CollectionUtils.isNotEmpty(facetsResponse)) { + Map map = facetsResponse.get(0); + List> valueList = (List>) map.get("values"); + + for (Map value : valueList) { + long count = (long) value.get(JsonKey.COUNT); + if (count > 1) { + throw new ProjectCommonException( + ResponseCode.errorDuplicateEntries.getErrorCode(), + MessageFormat.format( + ResponseCode.errorDuplicateEntries.getErrorMessage(), objectType), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } + } + } + + private String upsertUser(ActorRef actorRef, Map userMap, String operation) { + String userId = null; + + Request request = new Request(); + request.setRequest(userMap); + request.setOperation(operation); + request.getContext().put(JsonKey.VERSION, JsonKey.VERSION_2); + request.getContext().put(JsonKey.CALLER_ID, JsonKey.BULK_USER_UPLOAD); + request.getContext().put(JsonKey.ROOT_ORG_ID, userMap.get(JsonKey.ROOT_ORG_ID)); + userMap.remove(JsonKey.ROOT_ORG_ID); + Object obj = interServiceCommunication.getResponse(actorRef, request); + if (obj instanceof Response) { + Response response = (Response) obj; + userId = (String) response.get(JsonKey.USER_ID); + } else if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else if (obj instanceof Exception) { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + return userId; + } + + /** + * Get managed user list for LUA uuid (JsonKey.ID) + * @param actorRef + * @param req + * + * @return Map + */ + public Map searchManagedUser(ActorRef actorRef, Request req) { + ProjectLogger.log("UserServiceImpl: searchManagedUser called", LoggerEnum.DEBUG); + + Map searchRequestMap = new HashMap<>(); + Map filters = new HashMap<>(); + filters.put(JsonKey.MANAGED_BY, (String)req.get(JsonKey.ID)); + List objectType = new ArrayList(); + objectType.add("user"); + filters.put(JsonKey.OBJECT_TYPE, objectType); + searchRequestMap.put(JsonKey.FILTERS, filters); + + String sortByField = (String) req.get(JsonKey.SORTBY); + if(StringUtils.isNotEmpty(sortByField)) { + String order = (String) req.get(JsonKey.ORDER); + Map sortby = new HashMap<>(); + sortby.put(sortByField, StringUtils.isEmpty(order)?"asc":order); + searchRequestMap.put(JsonKey.SORT_BY, sortby); + } + + Request request = new Request(); + request.getRequest().putAll(searchRequestMap); + request.setOperation(ActorOperations.COMPOSITE_SEARCH.getValue()); + + Object obj = null; + try { + Timeout t = new Timeout(Duration.create(10, TimeUnit.SECONDS)); + obj = Await.result(Patterns.ask(actorRef, request, t), t.duration()); + }catch (Exception e) { + ProjectLogger.log( + "getFuture: Exception occured with error message = " + + e.getMessage(), + e); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + if (obj instanceof Response) { + Response responseObj = (Response) obj; + return (Map)responseObj.getResult().get(JsonKey.RESPONSE); + } else if (obj instanceof ProjectCommonException) { + throw (ProjectCommonException) obj; + } else { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/location/Location.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/location/Location.java new file mode 100644 index 0000000000..898d7de4b2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/location/Location.java @@ -0,0 +1,63 @@ +package org.sunbird.models.location; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import java.io.Serializable; + +/** + * @desc POJO class for Location + * @author Amit Kumar + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class Location implements Serializable { + + private static final long serialVersionUID = -7967252522327069670L; + + private String id; + private String code; + private String name; + private String type; + private String parentId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/location/apirequest/UpsertLocationRequest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/location/apirequest/UpsertLocationRequest.java new file mode 100644 index 0000000000..0214f94f81 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/location/apirequest/UpsertLocationRequest.java @@ -0,0 +1,70 @@ +package org.sunbird.models.location.apirequest; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +/** + * Class to represent the location api request object. + * + * @author arvind. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class UpsertLocationRequest { + + private String id; + private String code; + private String name; + private String type; + private String parentId; + private String parentCode; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public String getParentCode() { + return parentCode; + } + + public void setParentCode(String parentCode) { + this.parentCode = parentCode; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/organisation/Organisation.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/organisation/Organisation.java new file mode 100644 index 0000000000..1af6ca4201 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/organisation/Organisation.java @@ -0,0 +1,357 @@ +package org.sunbird.models.organisation; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.List; + +/** + * @desc POJO class for Organisation + * @author Amit Kumar + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class Organisation implements Serializable { + + private static final long serialVersionUID = 3617862727235741692L; + private String id; + private String addressId; + private String approvedBy; + private String approvedDate; + private String channel; + private String communityId; + private String contactDetail; + private String createdBy; + private String createdDate; + private Timestamp dateTime; + private String description; + private String email; + private String externalId; + private String hashTagId; + private String homeUrl; + private String imgUrl; + private Boolean isApproved; + private Boolean isDefault; + private Boolean isRootOrg; + private String locationId; + private Integer noOfMembers; + private String orgCode; + private String orgName; + private String orgType; + private String orgTypeId; + private String parentOrgId; + private String preferredLanguage; + private String provider; + private String rootOrgId; + private String slug; + private Integer status; + private String theme; + private String thumbnail; + private String updatedBy; + private String updatedDate; + private List locationIds; + private Boolean isSSOEnabled; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAddressId() { + return addressId; + } + + public void setAddressId(String addressId) { + this.addressId = addressId; + } + + public String getApprovedBy() { + return approvedBy; + } + + public void setApprovedBy(String approvedBy) { + this.approvedBy = approvedBy; + } + + public String getApprovedDate() { + return approvedDate; + } + + public void setApprovedDate(String approvedDate) { + this.approvedDate = approvedDate; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getCommunityId() { + return communityId; + } + + public void setCommunityId(String communityId) { + this.communityId = communityId; + } + + public String getContactDetail() { + return contactDetail; + } + + public void setContactDetail(String contactDetail) { + this.contactDetail = contactDetail; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public String getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(String createdDate) { + this.createdDate = createdDate; + } + + public Timestamp getDateTime() { + return dateTime; + } + + public void setDateTime(Timestamp dateTime) { + this.dateTime = dateTime; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getHashTagId() { + return hashTagId; + } + + public void setHashTagId(String hashTagId) { + this.hashTagId = hashTagId; + } + + public String getHomeUrl() { + return homeUrl; + } + + public void setHomeUrl(String homeUrl) { + this.homeUrl = homeUrl; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getLocationId() { + return locationId; + } + + public void setLocationId(String locationId) { + this.locationId = locationId; + } + + public Integer getNoOfMembers() { + return noOfMembers; + } + + public void setNoOfMembers(Integer noOfMembers) { + this.noOfMembers = noOfMembers; + } + + public String getOrgCode() { + return orgCode; + } + + public void setOrgCode(String orgCode) { + this.orgCode = orgCode; + } + + public String getOrgName() { + return orgName; + } + + public void setOrgName(String orgName) { + this.orgName = orgName; + } + + public String getOrgType() { + return orgType; + } + + public void setOrgType(String orgType) { + this.orgType = orgType; + } + + public String getOrgTypeId() { + return orgTypeId; + } + + public void setOrgTypeId(String orgTypeId) { + this.orgTypeId = orgTypeId; + } + + public String getParentOrgId() { + return parentOrgId; + } + + public void setParentOrgId(String parentOrgId) { + this.parentOrgId = parentOrgId; + } + + public String getPreferredLanguage() { + return preferredLanguage; + } + + public void setPreferredLanguage(String preferredLanguage) { + this.preferredLanguage = preferredLanguage; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getRootOrgId() { + return rootOrgId; + } + + public void setRootOrgId(String rootOrgId) { + this.rootOrgId = rootOrgId; + } + + public String getSlug() { + return slug; + } + + public void setSlug(String slug) { + this.slug = slug; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getTheme() { + return theme; + } + + public void setTheme(String theme) { + this.theme = theme; + } + + public String getThumbnail() { + return thumbnail; + } + + public void setThumbnail(String thumbnail) { + this.thumbnail = thumbnail; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(String updatedDate) { + this.updatedDate = updatedDate; + } + + public List getLocationIds() { + return locationIds; + } + + public void setLocationIds(List locationIds) { + this.locationIds = locationIds; + } + + @JsonProperty(value = "isApproved") + public Boolean isApproved() { + return isApproved; + } + + public void setApproved(Boolean isApproved) { + this.isApproved = isApproved; + } + + @JsonProperty(value = "isDefault") + public Boolean isDefault() { + return isDefault; + } + + public void setDefault(Boolean isDefault) { + this.isDefault = isDefault; + } + + @JsonProperty(value = "isRootOrg") + public Boolean isRootOrg() { + return isRootOrg; + } + + public void setRootOrg(Boolean isRootOrg) { + this.isRootOrg = isRootOrg; + } + + @JsonProperty(value = "isSSOEnabled") + public Boolean isSSOEnabled() { + return isSSOEnabled; + } + + public void setSSOEnabled(Boolean isSsoEnabled) { + this.isSSOEnabled = isSsoEnabled; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/systemsetting/SystemSetting.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/systemsetting/SystemSetting.java new file mode 100644 index 0000000000..0e5813fd7c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/actor-util/src/main/java/org/sunbird/models/systemsetting/SystemSetting.java @@ -0,0 +1,47 @@ +package org.sunbird.models.systemsetting; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import java.io.Serializable; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class SystemSetting implements Serializable { + private static final long serialVersionUID = 1L; + private String id; + private String field; + private String value; + + public SystemSetting() {} + + public SystemSetting(String id, String field, String value) { + this.id = id; + this.field = field; + this.value = value; + } + + public String getId() { + return this.id; + } + + public String getField() { + return this.field; + } + + public String getValue() { + return this.value; + } + + public void setId(String id) { + this.id = id; + } + + public void setField(String field) { + this.field = field; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/.gitignore new file mode 100644 index 0000000000..55977f8f94 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/.gitignore @@ -0,0 +1,7 @@ +/target/ +.classpath +.project +.settings +/bin/ + +*.iml diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/pom.xml new file mode 100644 index 0000000000..0e0ab863bb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/pom.xml @@ -0,0 +1,316 @@ + + 4.0.0 + + org.sunbird + common-util + 0.0.1-SNAPSHOT + common-util + http://maven.apache.org + + + UTF-8 + + 2.5.19 + + + + + junit + junit + 4.12 + test + + + com.typesafe.akka + akka-actor_2.11 + ${learner.akka.version} + + + com.typesafe.akka + akka-slf4j_2.11 + ${learner.akka.version} + + + com.typesafe.akka + akka-remote_2.11 + ${learner.akka.version} + + + org.apache.logging.log4j + log4j-api + 2.8.2 + + + org.apache.logging.log4j + log4j-core + 2.8.2 + + + + org.apache.commons + commons-lang3 + 3.0 + + + + org.keycloak + keycloak-admin-client + 6.0.1 + + + org.jboss.resteasy + jaxrs-api + 3.0.11.Final + + + org.jboss.resteasy + resteasy-client + 3.1.0.Final + + + + com.microsoft.azure + azure-storage + 5.4.0 + + + + org.apache.velocity + velocity-tools + 2.0 + + + + javax.mail + javax.mail-api + 1.5.1 + + + + com.sun.mail + javax.mail + 1.6.0 + + + + org.jboss.resteasy + resteasy-jackson2-provider + 3.1.3.Final + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-databind + + + + + + + com.moparisthebest + junidecode + 0.1.1 + + + + org.apache.poi + poi-ooxml + 3.15 + + + com.fasterxml.jackson.core + jackson-core + 2.10.1 + + + com.fasterxml.jackson.core + jackson-databind + 2.10.1 + + + com.fasterxml.jackson.core + jackson-annotations + 2.10.1 + + + + org.apache.commons + commons-csv + 1.4 + + + + org.jvnet.mock-javamail + mock-javamail + 1.9 + test + + + + com.googlecode.libphonenumber + libphonenumber + 8.10.2 + + + + org.apache.tika + tika-core + 1.16 + + + + + org.apache.httpcomponents + httpclient + 4.5 + + + + + org.apache.httpcomponents + httpmime + 4.5.2 + + + + org.powermock + powermock-module-junit4 + 1.6.5 + + + + + org.powermock + powermock-api-mockito + 1.6.5 + + + + + + org.apache.httpcomponents + httpcore + 4.4.4 + + + com.mashape.unirest + unirest-java + 1.4.9 + + + + com.google.guava + guava + 18.0 + + + org.sunbird + cloud-store-sdk + 1.2.6 + + + com.sun.jersey + jersey-core + + + com.sun.jersey + jersey-server + + + com.fasterxml.jackson.module + jackson-module-scala_2.11 + + + slf4j-log4j12 + org.slf4j + + + + + com.fasterxml.jackson.module + jackson-module-scala_2.11 + 2.10.1 + + + org.glassfish.jersey.core + jersey-common + 2.27 + + + org.glassfish.jersey.core + jersey-client + 2.27 + + + org.glassfish.jersey.core + jersey-server + 2.27 + + + org.apache.kafka + kafka-clients + 0.10.0.1 + + + + + + cloud-store + https://oss.sonatype.org/content/repositories/orgsunbird-1021 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.17 + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/exception/ProjectCommonException.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/exception/ProjectCommonException.java new file mode 100644 index 0000000000..4fddff1804 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/exception/ProjectCommonException.java @@ -0,0 +1,128 @@ +/** */ +package org.sunbird.common.exception; + +import java.text.MessageFormat; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * This exception will be used across all backend code. This will send status code and error message + * + * @author Manzarul.Haque + */ +public class ProjectCommonException extends RuntimeException { + + /** serialVersionUID. */ + private static final long serialVersionUID = 1L; + /** code String code ResponseCode. */ + private String code; + /** message String ResponseCode. */ + private String message; + /** responseCode int ResponseCode. */ + private int responseCode; + + /** + * This code is for client to identify the error and based on that do the message localization. + * + * @return String + */ + public String getCode() { + return code; + } + + /** + * To set the client code. + * + * @param code String + */ + public void setCode(String code) { + this.code = code; + } + + /** + * message for client in english. + * + * @return String + */ + @Override + public String getMessage() { + return message; + } + + /** @param message String */ + public void setMessage(String message) { + this.message = message; + } + + /** + * This method will provide response code, this code will be used in response header. + * + * @return int + */ + public int getResponseCode() { + return responseCode; + } + + /** @param responseCode int */ + public void setResponseCode(int responseCode) { + this.responseCode = responseCode; + } + + /** + * three argument constructor. + * + * @param code String + * @param message String + * @param responseCode int + */ + public ProjectCommonException(String code, String message, int responseCode) { + super(); + this.code = code; + this.message = message; + this.responseCode = responseCode; + } + + public ProjectCommonException( + String code, String messageWithPlaceholder, int responseCode, String... placeholderValue) { + super(); + this.code = code; + this.message = MessageFormat.format(messageWithPlaceholder, placeholderValue); + this.responseCode = responseCode; + } + + public static void throwClientErrorException(ResponseCode responseCode, String exceptionMessage) { + throw new ProjectCommonException( + responseCode.getErrorCode(), + StringUtils.isBlank(exceptionMessage) ? responseCode.getErrorMessage() : exceptionMessage, + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + public static void throwResourceNotFoundException() { + throw new ProjectCommonException( + ResponseCode.resourceNotFound.getErrorCode(), + ResponseCode.resourceNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + + public static void throwServerErrorException(ResponseCode responseCode, String exceptionMessage) { + throw new ProjectCommonException( + responseCode.getErrorCode(), + StringUtils.isBlank(exceptionMessage) ? responseCode.getErrorMessage() : exceptionMessage, + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + public static void throwServerErrorException(ResponseCode responseCode) { + throwServerErrorException(responseCode, responseCode.getErrorMessage()); + } + + public static void throwClientErrorException(ResponseCode responseCode) { + throwClientErrorException(responseCode, responseCode.getErrorMessage()); + } + + public static void throwUnauthorizedErrorException() { + throw new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ResponseCode.unAuthorized.getErrorMessage(), + ResponseCode.UNAUTHORIZED.getResponseCode()); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/exception/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/exception/package-info.java new file mode 100644 index 0000000000..18e910d04b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/exception/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.exception; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/hash/HashGeneratorUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/hash/HashGeneratorUtil.java new file mode 100644 index 0000000000..0f28662dfa --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/hash/HashGeneratorUtil.java @@ -0,0 +1,33 @@ +package org.sunbird.common.hash; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.sunbird.common.models.util.datasecurity.OneWayHashing; + +public class HashGeneratorUtil { + private static List primes = null; + private static int MAX_NUMBER = 300; + private static int numPrimes = 7; + + private static List getPrimes() { + List list = new ArrayList<>(); + boolean prime[] = new boolean[MAX_NUMBER + 1]; + Arrays.fill(prime, true); + for (int p = 2; p * p <= MAX_NUMBER; p++) { + if (prime[p] == true) { + for (int i = p * p; i <= MAX_NUMBER; i += p) prime[i] = false; + } + } + for (int i = numPrimes; i <= MAX_NUMBER; i++) { + if (prime[i] == true) { + list.add(i); + } + } + return list; + } + + public static String getHashCode(String jsonString) { + return OneWayHashing.encryptVal(jsonString); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/ClientErrorResponse.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/ClientErrorResponse.java new file mode 100644 index 0000000000..d1f8c7fd5e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/ClientErrorResponse.java @@ -0,0 +1,21 @@ +package org.sunbird.common.models.response; + +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.responsecode.ResponseCode; + +public class ClientErrorResponse extends Response { + + private ProjectCommonException exception = null; + + public ClientErrorResponse() { + responseCode = ResponseCode.CLIENT_ERROR; + } + + public ProjectCommonException getException() { + return exception; + } + + public void setException(ProjectCommonException exception) { + this.exception = exception; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/HttpUtilResponse.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/HttpUtilResponse.java new file mode 100644 index 0000000000..501b957f23 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/HttpUtilResponse.java @@ -0,0 +1,33 @@ +package org.sunbird.common.models.response; + +public class HttpUtilResponse { + private String body; + private int statusCode; + + public HttpUtilResponse() {} + + public HttpUtilResponse(String body, int statusCode) { + this.body = body; + this.statusCode = statusCode; + } + + /** @return the body */ + public String getBody() { + return body; + } + + /** @param body the body to set */ + public void setBody(String body) { + this.body = body; + } + + /** @return the statusCode */ + public int getStatusCode() { + return statusCode; + } + + /** @param statusCode the statusCode to set */ + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/Params.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/Params.java new file mode 100644 index 0000000000..9d740f5c61 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/Params.java @@ -0,0 +1,68 @@ +package org.sunbird.common.models.response; + +import java.io.Serializable; + +/** + * Common response parameter bean + * + * @author Manzarul + */ +public class Params implements Serializable { + + private static final long serialVersionUID = -8786004970726124473L; + private String resmsgid; + private String msgid; + private String err; + private String status; + private String errmsg; + + /** @return String */ + public String getResmsgid() { + return resmsgid; + } + + /** @param resmsgid Stirng */ + public void setResmsgid(String resmsgid) { + this.resmsgid = resmsgid; + } + + /** @return Stirng */ + public String getMsgid() { + return msgid; + } + + /** @param msgid String */ + public void setMsgid(String msgid) { + this.msgid = msgid; + } + + /** @return String */ + public String getErr() { + return err; + } + + /** @param err String */ + public void setErr(String err) { + this.err = err; + } + + /** @return String */ + public String getStatus() { + return status; + } + + /** @param status Stirng */ + public void setStatus(String status) { + this.status = status; + } + + /** @return Stirng */ + public String getErrmsg() { + return errmsg; + } + + /** @param errmsg Stirng */ + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/Response.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/Response.java new file mode 100644 index 0000000000..adbaed1748 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/Response.java @@ -0,0 +1,150 @@ +package org.sunbird.common.models.response; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * This is a common response class for all the layer. All layer will send same response object. + * + * @author Manzarul + */ +public class Response implements Serializable, Cloneable { + + private static final long serialVersionUID = -3773253896160786443L; + protected String id; + protected String ver; + protected String ts; + protected ResponseParams params; + protected ResponseCode responseCode = ResponseCode.OK; + protected Map result = new HashMap<>(); + + /** + * This will provide request unique id. + * + * @return String + */ + public String getId() { + return id; + } + + /** + * set the unique id + * + * @param id String + */ + public void setId(String id) { + this.id = id; + } + + /** + * this will provide api version + * + * @return String + */ + public String getVer() { + return ver; + } + + /** + * set the api version + * + * @param ver String + */ + public void setVer(String ver) { + this.ver = ver; + } + + /** + * this will provide complete time value + * + * @return String + */ + public String getTs() { + return ts; + } + + /** + * set the time value + * + * @param ts String + */ + public void setTs(String ts) { + this.ts = ts; + } + + /** @return Map */ + public Map getResult() { + return result; + } + + /** + * @param key String + * @return Object + */ + public Object get(String key) { + return result.get(key); + } + + /** + * @param key String + * @param vo Object + */ + public void put(String key, Object vo) { + result.put(key, vo); + } + + /** @param map Map */ + public void putAll(Map map) { + result.putAll(map); + } + + public boolean containsKey(String key) { + return result.containsKey(key); + } + + /** + * This will provide response parameter object. + * + * @return ResponseParams + */ + public ResponseParams getParams() { + return params; + } + + /** + * set the response parameter object. + * + * @param params ResponseParams + */ + public void setParams(ResponseParams params) { + this.params = params; + } + + /** + * Set the response code for header. + * + * @param code ResponseCode + */ + public void setResponseCode(ResponseCode code) { + this.responseCode = code; + } + + /** + * get the response code + * + * @return ResponseCode + */ + public ResponseCode getResponseCode() { + return this.responseCode; + } + + public Response clone(Response response) { + try { + return (Response) response.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/ResponseParams.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/ResponseParams.java new file mode 100644 index 0000000000..e463551689 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/ResponseParams.java @@ -0,0 +1,114 @@ +package org.sunbird.common.models.response; + +import java.io.Serializable; + +/** + * This class will contains response envelop. + * + * @author Manzarul + */ +public class ResponseParams implements Serializable { + + private static final long serialVersionUID = 6772142067149203497L; + private String resmsgid; + private String msgid; + private String err; + private String status; + private String errmsg; + + public enum StatusType { + SUCCESSFUL, + WARNING, + FAILED; + } + + /** + * This will contains response message id. + * + * @return String + */ + public String getResmsgid() { + return resmsgid; + } + + /** + * set the response message id. + * + * @param resmsgid String + */ + public void setResmsgid(String resmsgid) { + this.resmsgid = resmsgid; + } + + /** + * This will provide request specific message id. + * + * @return String + */ + public String getMsgid() { + return msgid; + } + + /** + * Set the request specific message id. + * + * @param msgid + */ + public void setMsgid(String msgid) { + this.msgid = msgid; + } + + /** + * This will provide error message + * + * @return String + */ + public String getErr() { + return err; + } + + /** + * Set the error message + * + * @param err String + */ + public void setErr(String err) { + this.err = err; + } + + /** + * This will return api call status + * + * @return String + */ + public String getStatus() { + return status; + } + + /** + * Set the api call status + * + * @param status + */ + public void setStatus(String status) { + this.status = status; + } + + /** + * This will provide Error message in english + * + * @return String + */ + public String getErrmsg() { + return errmsg; + } + + /** + * Set the error message in English. + * + * @param message String + */ + public void setErrmsg(String message) { + this.errmsg = message; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/package-info.java new file mode 100644 index 0000000000..db25691173 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/response/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.models.response; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ActorOperations.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ActorOperations.java new file mode 100644 index 0000000000..100bf615b4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ActorOperations.java @@ -0,0 +1,199 @@ +package org.sunbird.common.models.util; + +/** + * This enum will contains different operation for a learner {addCourse, getCourse, update , + * getContent} + * + * @author Manzarul + */ +public enum ActorOperations { + ENROLL_COURSE("enrollCourse"), + UNENROLL_COURSE("unenrollCourse"), + GET_COURSE("getCourse"), + ADD_CONTENT("addContent"), + GET_CONTENT("getContent"), + CREATE_COURSE("createCourse"), + UPDATE_COURSE("updateCourse"), + PUBLISH_COURSE("publishCourse"), + SEARCH_COURSE("searchCourse"), + DELETE_COURSE("deleteCourse"), + CREATE_USER("createUser"), + UPDATE_USER("updateUser"), + USER_AUTH("userAuth"), + GET_USER_PROFILE("getUserProfile"), + GET_USER_PROFILE_V2("getUserProfileV2"), + CREATE_ORG("createOrg"), + UPDATE_ORG("updateOrg"), + UPDATE_ORG_STATUS("updateOrgStatus"), + GET_ORG_DETAILS("getOrgDetails"), + CREATE_PAGE("createPage"), + UPDATE_PAGE("updatePage"), + DELETE_PAGE("deletePage"), + GET_PAGE_SETTINGS("getPageSettings"), + GET_PAGE_SETTING("getPageSetting"), + GET_PAGE_DATA("getPageData"), + GET_DIAL_PAGE_DATA("getDialPageData"), + CREATE_SECTION("createSection"), + UPDATE_SECTION("updateSection"), + GET_ALL_SECTION("getAllSection"), + GET_SECTION("getSection"), + GET_COURSE_BY_ID("getCourseById"), + UPDATE_USER_COUNT("updateUserCount"), + GET_RECOMMENDED_COURSES("getRecommendedCourses"), + UPDATE_USER_INFO_ELASTIC("updateUserInfoToElastic"), + GET_ROLES("getRoles"), + APPROVE_ORGANISATION("approveOrganisation"), + ADD_MEMBER_ORGANISATION("addMemberOrganisation"), + REMOVE_MEMBER_ORGANISATION("removeMemberOrganisation"), + COMPOSITE_SEARCH("compositeSearch"), + GET_USER_DETAILS_BY_LOGINID("getUserDetailsByLoginId"), + GET_USER_BY_KEY("getUserByKey"), + UPDATE_ORG_INFO_ELASTIC("updateOrgInfoToElastic"), + INSERT_ORG_INFO_ELASTIC("insertOrgInfoToElastic"), + DOWNLOAD_ORGS("downlaodOrg"), + BLOCK_USER("blockUser"), + DELETE_BY_IDENTIFIER("deleteByIdentifier"), + BULK_UPLOAD("bulkUpload"), + PROCESS_BULK_UPLOAD("processBulkUpload"), + ASSIGN_ROLES("assignRoles"), + UNBLOCK_USER("unblockUser"), + CREATE_BATCH("createBatch"), + UPDATE_BATCH("updateBatch"), + REMOVE_BATCH("removeBatch"), + ADD_USER_TO_BATCH("addUserBatch"), + REMOVE_USER_FROM_BATCH("removeUserFromBatch"), + GET_BATCH("getBatch"), + INSERT_COURSE_BATCH_ES("insertCourseBatchToEs"), + UPDATE_COURSE_BATCH_ES("updateCourseBatchToEs"), + GET_BULK_OP_STATUS("getBulkOpStatus"), + GET_BULK_UPLOAD_STATUS_DOWNLOAD_LINK("getBulkUploadStatusDownloadLink"), + ORG_CREATION_METRICS("orgCreationMetrics"), + ORG_CONSUMPTION_METRICS("orgConsumptionMetrics"), + ORG_CREATION_METRICS_DATA("orgCreationMetricsData"), + ORG_CONSUMPTION_METRICS_DATA("orgConsumptionMetricsData"), + COURSE_PROGRESS_METRICS("courseProgressMetrics"), + COURSE_PROGRESS_METRICS_V2("courseProgressMetricsV2"), + COURSE_CREATION_METRICS("courseConsumptionMetrics"), + USER_CREATION_METRICS("userCreationMetrics"), + USER_CONSUMPTION_METRICS("userConsumptionMetrics"), + GET_COURSE_BATCH_DETAIL("getCourseBatchDetail"), + UPDATE_USER_ORG_ES("updateUserOrgES"), + REMOVE_USER_ORG_ES("removeUserOrgES"), + UPDATE_USER_ROLES_ES("updateUserRoles"), + SYNC("sync"), + BACKGROUND_SYNC("backgroundSync"), + INSERT_USR_COURSES_INFO_ELASTIC("insertUserCoursesInfoToElastic"), + UPDATE_USR_COURSES_INFO_ELASTIC("updateUserCoursesInfoToElastic"), + SCHEDULE_BULK_UPLOAD("scheduleBulkUpload"), + COURSE_PROGRESS_METRICS_REPORT("courseProgressMetricsReport"), + COURSE_CREATION_METRICS_REPORT("courseConsumptionMetricsReport"), + ORG_CREATION_METRICS_REPORT("orgCreationMetricsReport"), + ORG_CONSUMPTION_METRICS_REPORT("orgConsumptionMetricsReport"), + EMAIL_SERVICE("emailService"), + FILE_STORAGE_SERVICE("fileStorageService"), + ADD_USER_BADGE_BKG("addUserBadgebackground"), + FILE_GENERATION_AND_UPLOAD("fileGenerationAndUpload"), + HEALTH_CHECK("healthCheck"), + SEND_MAIL("sendMail"), + PROCESS_DATA("processData"), + ACTOR("actor"), + CASSANDRA("cassandra"), + ES("es"), + EKSTEP("ekstep"), + GET_ORG_TYPE_LIST("getOrgTypeList"), + CREATE_ORG_TYPE("createOrgType"), + UPDATE_ORG_TYPE("updateOrgType"), + CREATE_NOTE("createNote"), + UPDATE_NOTE("updateNote"), + SEARCH_NOTE("searchNote"), + GET_NOTE("getNote"), + DELETE_NOTE("deleteNote"), + INSERT_USER_NOTES_ES("insertUserNotesToElastic"), + ENCRYPT_USER_DATA("encryptUserData"), + DECRYPT_USER_DATA("decryptUserData"), + UPDATE_USER_NOTES_ES("updateUserNotesToElastic"), + USER_CURRENT_LOGIN("userCurrentLogin"), + GET_MEDIA_TYPES("getMediaTypes"), + ADD_SKILL("addSkill"), + GET_SKILL("getSkill"), + UPDATE_SKILL("updateSkill"), + GET_SKILLS_LIST("getSkillsList"), + ADD_USER_SKILL_ENDORSEMENT("addUserSkillEndorsement"), + PROFILE_VISIBILITY("profileVisibility"), + CREATE_TENANT_PREFERENCE("createTanentPreference"), + UPDATE_TENANT_PREFERENCE("updateTenantPreference"), + GET_TENANT_PREFERENCE("getTenantPreference"), + REGISTER_CLIENT("registerClient"), + UPDATE_CLIENT_KEY("updateClientKey"), + GET_CLIENT_KEY("getClientKey"), + CREATE_GEO_LOCATION("createGeoLocation"), + GET_GEO_LOCATION("getGeoLocation"), + UPDATE_GEO_LOCATION("updateGeoLocation"), + DELETE_GEO_LOCATION("deleteGeoLocation"), + GET_USER_COUNT("getUserCount"), + UPDATE_USER_COUNT_TO_LOCATIONID("updateUserCountToLocationID"), + SEND_NOTIFICATION("sendNotification"), + SYNC_KEYCLOAK("syncKeycloak"), + UPDATE_SYSTEM_SETTINGS("updateSystemSettings"), + CREATE_DATA("createData"), + UPDATE_DATA("updateData"), + DELETE_DATA("deleteData"), + READ_DATA("readData"), + READ_ALL_DATA("readAllData"), + SEARCH_DATA("searchData"), + GET_METRICS("getMetrics"), + REG_CHANNEL("channelReg"), + UPDATE_LEARNER_STATE("updateLearnerState"), + GET_SYSTEM_SETTING("getSystemSetting"), + GET_ALL_SYSTEM_SETTINGS("getAllSystemSettings"), + SET_SYSTEM_SETTING("setSystemSetting"), + COURSE_BATCH_NOTIFICATION("courseBatchNotification"), + USER_TNC_ACCEPT("userTnCAccept"), + GENERATE_OTP("generateOTP"), + BACKGROUND_ENCRYPTION("backgroundEncryption"), + BACKGROUND_DECRYPTION("backgroundDecryption"), + VERIFY_OTP("verifyOTP"), + SEND_OTP("sendOTP"), + GET_USER_TYPES("getUserTypes"), + CLEAR_CACHE("clearCache"), + USER_TENANT_MIGRATE("userTenantMigrate"), + GET_PARTICIPANTS("getParticipants"), + GET_USER_COURSE("getUserCourse"), + FREEUP_USER_IDENTITY("freeUpUserIdentity"), + RESET_PASSWORD("resetPassword"), + MERGE_USER("mergeUser"), + MERGE_USER_TO_ELASTIC("mergeUserToElastic"), + VALIDATE_CERTIFICATE("validateCertificate"), + ADD_CERTIFICATE("addCertificate"), + ASSIGN_KEYS("assignKeys"), + DOWNLOAD_QR_CODES("downloadQRCodes"), + GET_SIGN_URL("getSignUrl"), + MERGE_USER_CERTIFICATE("mergeUserCertificate"), + MIGRATE_USER("migrateUser"), + REJECT_MIGRATION("rejectMigration"), + GET_USER_FEED_BY_ID("getUserFeedById"), + CREATE_USER_V3("createUserV3"), + CREATE_USER_V4("createUserV4"), + ONDEMAND_START_SCHEDULER("onDemandStartScheduler"), + GET_MANAGED_USERS("getManagedUsers"); + + private String value; + + /** + * constructor + * + * @param value String + */ + ActorOperations(String value) { + this.value = value; + } + + /** + * returns the enum value + * + * @return String + */ + public String getValue() { + return this.value; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/AuditLog.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/AuditLog.java new file mode 100644 index 0000000000..9c5d6d7219 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/AuditLog.java @@ -0,0 +1,70 @@ +package org.sunbird.common.models.util; + +import java.util.Map; + +public class AuditLog { + + private String requestId; + private String objectId; + private String objectType; + private String operationType; + private String date; + private String userId; + private Map logRecord; + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getObjectId() { + return objectId; + } + + public void setObjectId(String objectId) { + this.objectId = objectId; + } + + public String getObjectType() { + return objectType; + } + + public void setObjectType(String objectType) { + this.objectType = objectType; + } + + public String getOperationType() { + return operationType; + } + + public void setOperationType(String operationType) { + this.operationType = operationType; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Map getLogRecord() { + return logRecord; + } + + public void setLogRecord(Map logRecord) { + this.logRecord = logRecord; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BadgingActorOperations.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BadgingActorOperations.java new file mode 100644 index 0000000000..48df170222 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BadgingActorOperations.java @@ -0,0 +1,40 @@ +package org.sunbird.common.models.util; + +/** Created by arvind on 7/3/18. */ +public enum BadgingActorOperations { + CREATE_BADGE_CLASS("createBadgeClass"), + GET_BADGE_CLASS("getBadgeClass"), + SEARCH_BADGE_CLASS("searchBadgeClass"), + DELETE_BADGE_CLASS("deleteBadgeClass"), + CREATE_BADGE_ISSUER("createBadgeIssuer"), + ASSIGN_BADGE_MESSAGE("assignBadgeMessage"), + REVOKE_BADGE_MESSAGE("revokeBadgeMessage"), + CREATE_BADGE_ASSERTION("createBadgeAssertion"), + GET_BADGE_ASSERTION("getBadgeAssertion"), + GET_BADGE_ASSERTION_LIST("getBadgeAssertionList"), + REVOKE_BADGE("revokeBadge"), + GET_BADGE_ISSUER("getBadgeIssuer"), + GET_ALL_ISSUER("getAllIssuer"), + CREATE_BADGE_ASSOCIATION("createBadgeAssociation"), + REMOVE_BADGE_ASSOCIATION("removeBadgeAssociation"); + + private String value; + + /** + * constructor + * + * @param value String + */ + BadgingActorOperations(String value) { + this.value = value; + } + + /** + * returns the enum value + * + * @return String + */ + public String getValue() { + return this.value; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BadgingJsonKey.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BadgingJsonKey.java new file mode 100644 index 0000000000..025431a8bc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BadgingJsonKey.java @@ -0,0 +1,92 @@ +package org.sunbird.common.models.util; + +/** Created by arvind on 7/3/18. */ +public class BadgingJsonKey { + public static final String ASSERTIONS = "assertions"; + public static final String ASSERTION_SLUG = "assertionSlug"; + public static final String BADGE_CRITERIA = "criteria"; + public static final String BADGE_ID = "badgeId"; + public static final String BADGE_IDs = "badgeIds"; + public static final String BADGE_ID_URL = "badgeIdUrl"; + public static final String BADGE_LIST = "badgeList"; + public static final String BADGE_SLUG = "badgeSlug"; + public static final String BADGE_TYPE_USER = "user"; + public static final String BADGE_TYPE_CONTENT = "content"; + public static final String BADGER_BASE_URL = "sunbird_badger_baseurl"; + public static final String BADGES = "badges"; + public static final String BADGING_ASSERTION_LIST_SIZE = "badging_assertion_list_size"; + public static final String BADGING_AUTHORIZATION_KEY = "badging_authorization_key"; + public static final String CONTEXT = "context"; + public static final String CREATE_NOTIFICATION = "create_notification"; + public static final String CREATED_AT = "created_at"; + public static final String EVIDENCE = "evidence"; + public static final String ISSUER_ID = "issuerId"; + public static final String ISSUER_ID_URL = "issuerIdUrl"; + public static final String ISSUER_LIST = "issuerList"; + public static final String ISSUER_SLUG = "issuerSlug"; + public static final String ISSUER_URL = "issuerUrl"; + public static final String ISSUERS = "issuers"; + public static final String ASSERTION_ID = "assertionId"; + public static final String ASSOCIATION_ID = "associationId"; + public static final String JSON_CRITERIA = "json.criteria"; + public static final String JSON_DESCRIPTION = "json.description"; + public static final String JSON_EMAIL = "json.email"; + public static final String JSON_ID = "json.id"; + public static final String JSON_ISSUER = "json.issuer"; + public static final String JSON_URL = "json.url"; + public static final String NOTIFY = "notify"; + public static final String RECIPIENT_COUNT = "recipient_count"; + public static final String RECIPIENT_EMAIL = "recipientEmail"; + public static final String RECIPIENT_ID = "recipientId"; + public static final String RECIPIENT_IDENTIFIER = "recipient_identifier"; + public static final String RECIPIENT_TYPE = "recipientType"; + public static final String REVOCATION_REASON = "revocationReason"; + public static final String JSON_ISSUED_ON = "json.issuedOn"; + public static final String JSON_IMAGE = "json.image"; + public static final String JSON_BADGE = "json.badge"; + public static final String BADGE_CLASS = "badge_class"; + public static final String ISSUER = "issuer"; + public static final String JSON_RECIPIENT = "json.recipient"; + public static final String JSON_VERIFY = "json.verify"; + public static final String REVOCATION_REASON_BADGE = "revocation_reason"; + public static final String ASSERTION_DATE = "assertionDate"; + public static final String ASSERTION_ID_URL = "assertionIdUrl"; + public static final String ASSERTION_IMAGE_URL = "assertionImageUrl"; + public static final String RECIPIENT = "recipient"; + public static final String VERIFY = "verify"; + public static final String REVOKED = "revoked"; + public static final String CREATED_TS = "createdTS"; + public static final String BADGE_CLASS_NANE = "badgeClassName"; + public static final String NAME = "name"; + public static final String IMAGE = "image"; + public static final String BADGE_CLASS_IMAGE = "badgeClassImage"; + public static final String BADGE_ASSERTION = "badgeAssertion"; + public static final String SLUG = "slug"; + public static final String VALID_BADGE_SUBTYPES = "sunbird_valid_badge_subtypes"; + public static final String VALID_BADGE_ROLES = "sunbird_valid_badge_roles"; + public static final String BADGE_CLASS_ID = "badgeId"; + public static final String USER_BADGE_ASSERTION_DB = "user_badge_assertion"; + public static final String CONTENT_BADGE_ASSOCIATION_DB = "content_badge_association"; + public static final String BADGE_ASSERTIONS = "badgeAssertions"; + public static final String BADGE_ASSOCIATIONS = "badgeAssociations"; + public static final String BADGE = "badge"; + // this email will be set while sunbird installation and used to send the email + // in case of assertion , if user email is absent. + public static final String SUNBIRD_INSTALLATION_EMAIL = "sunbird_installation_email"; + public static final String BADGE_ISSUER = "BadgeIssuer"; + public static final String TELEMETRY_DB = "telemetry_raw_data"; + + public static final String TELE_MID = "mid"; + public static final String TELE_TS = "ts"; + public static final String TELE_EVENT_DATA = "eventData"; + public static final String TELE_PDATA_ID = "pdataId"; + public static final String TELE_EID = "eid"; + public static final String TELE_ETS = "ets"; + public static final String TELE_PDATA = "pdata"; + public static final String TELE_VERSION = "ver"; + public static final String TELE_CONTEXT = "context"; + public static final String USER = "user"; + public static final String CONTENT = "content"; + + private BadgingJsonKey() {} +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BulkUploadActorOperation.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BulkUploadActorOperation.java new file mode 100644 index 0000000000..66cc045da5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BulkUploadActorOperation.java @@ -0,0 +1,24 @@ +package org.sunbird.common.models.util; + +/** Enum to represent bulk upload operations */ +public enum BulkUploadActorOperation { + LOCATION_BULK_UPLOAD("locationBulkUpload"), + LOCATION_BULK_UPLOAD_BACKGROUND_JOB("locationBulkUploadBackground"), + + ORG_BULK_UPLOAD("orgBulkUpload"), + ORG_BULK_UPLOAD_BACKGROUND_JOB("orgBulkUploadBackground"), + + USER_BULK_UPLOAD("userBulkUpload"), + USER_BULK_UPLOAD_BACKGROUND_JOB("userBulkUploadBackground"), + USER_BULK_MIGRATION("userBulkMigration"); + + private String value; + + BulkUploadActorOperation(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BulkUploadJsonKey.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BulkUploadJsonKey.java new file mode 100644 index 0000000000..4cc2757c9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/BulkUploadJsonKey.java @@ -0,0 +1,18 @@ +package org.sunbird.common.models.util; + +/** + * Constants for Bulk Upload service. + * + * @author Arvind + */ +public class BulkUploadJsonKey { + + private BulkUploadJsonKey() {} + + public static final String TASK_COUNT = "taskCount"; + public static final String SEQUENCE_ID = "sequenceId"; + public static final String OPERATION_STATUS_MSG = "Operation is {0}."; + public static final String NOT_STARTED = "NOT STARTED"; + public static final String IN_PROGRESS = "IN PROGRESS"; + public static final String COMPLETED = "COMPLETED"; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/CassandraPropertyReader.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/CassandraPropertyReader.java new file mode 100644 index 0000000000..9d3c62806b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/CassandraPropertyReader.java @@ -0,0 +1,48 @@ +package org.sunbird.common.models.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * This class will be used to read cassandratablecolumn properties file. + * + * @author Amit Kumar + */ +public class CassandraPropertyReader { + + private final Properties properties = new Properties(); + private static final String file = "cassandratablecolumn.properties"; + private static CassandraPropertyReader cassandraPropertyReader = null; + + /** private default constructor */ + private CassandraPropertyReader() { + InputStream in = this.getClass().getClassLoader().getResourceAsStream(file); + try { + properties.load(in); + } catch (IOException e) { + ProjectLogger.log("Error in properties cache", e); + } + } + + public static CassandraPropertyReader getInstance() { + if (null == cassandraPropertyReader) { + synchronized (CassandraPropertyReader.class) { + if (null == cassandraPropertyReader) { + cassandraPropertyReader = new CassandraPropertyReader(); + } + } + } + return cassandraPropertyReader; + } + + /** + * Method to read value from resource file . + * + * @param key property value to read + * @return value corresponding to given key if found else will return key itself. + */ + public String readProperty(String key) { + return properties.getProperty(key) != null ? properties.getProperty(key) : key; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/DbConstant.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/DbConstant.java new file mode 100644 index 0000000000..7ea3d27f97 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/DbConstant.java @@ -0,0 +1,21 @@ +package org.sunbird.common.models.util; + +/** + * Enum contains the database related constants + * + * @author arvind + */ +public enum DbConstant { + sunbirdKeyspaceName("sunbird"), + userTableName("user"); + + DbConstant(String value) { + this.value = value; + } + + String value; + + public String getValue() { + return this.value; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/EmailValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/EmailValidator.java new file mode 100644 index 0000000000..821c73d55c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/EmailValidator.java @@ -0,0 +1,38 @@ +package org.sunbird.common.models.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; + +/** + * Helper class for validating email. + * + * @author Amit Kumar + */ +public class EmailValidator { + + private static Pattern pattern; + private static final String EMAIL_PATTERN = + "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; + + private EmailValidator() {} + + static { + pattern = Pattern.compile(EMAIL_PATTERN); + } + + /** + * Validates format of email. + * + * @param email Email value. + * @return True, if email format is valid. Otherwise, return false. + */ + public static boolean isEmailValid(String email) { + if (StringUtils.isBlank(email)) { + return false; + } + Matcher matcher = pattern.matcher(email); + return matcher.matches(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ExcelFileUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ExcelFileUtil.java new file mode 100644 index 0000000000..bc1503be64 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ExcelFileUtil.java @@ -0,0 +1,67 @@ +package org.sunbird.common.models.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +public class ExcelFileUtil extends FileUtil { + + @SuppressWarnings({"resource", "unused"}) + public File writeToFile(String fileName, List> dataValues) { + // Blank workbook + XSSFWorkbook workbook = new XSSFWorkbook(); + // Create a blank sheet + XSSFSheet sheet = workbook.createSheet("Data"); + FileOutputStream out = null; + File file = null; + int rownum = 0; + for (Object key : dataValues) { + Row row = sheet.createRow(rownum); + List objArr = dataValues.get(rownum); + int cellnum = 0; + for (Object obj : objArr) { + Cell cell = row.createCell(cellnum++); + if (obj instanceof String) { + cell.setCellValue((String) obj); + } else if (obj instanceof Integer) { + cell.setCellValue((Integer) obj); + } else if (obj instanceof List) { + cell.setCellValue(getListValue(obj)); + } else if (obj instanceof Double) { + cell.setCellValue((Double) obj); + } else { + if (ProjectUtil.isNotNull(obj)) { + cell.setCellValue(obj.toString()); + } + } + } + rownum++; + } + + try { + // Write the workbook in file system + file = new File(fileName + ".xlsx"); + out = new FileOutputStream(file); + workbook.write(out); + // out.close(); + ProjectLogger.log("File " + fileName + " created successfully"); + + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } finally { + if (null != out) { + try { + out.close(); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + } + } + return file; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/FileUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/FileUtil.java new file mode 100644 index 0000000000..cda6931f63 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/FileUtil.java @@ -0,0 +1,37 @@ +package org.sunbird.common.models.util; + +import java.io.File; +import java.util.List; +import org.apache.commons.lang3.StringUtils; + +public abstract class FileUtil { + + public abstract File writeToFile(String fileName, List> dataValues); + + @SuppressWarnings("unchecked") + protected static String getListValue(Object obj) { + List data = (List) obj; + if (!(data.isEmpty())) { + StringBuilder sb = new StringBuilder(); + for (Object value : data) { + sb.append((String) value).append(","); + } + sb.deleteCharAt(sb.length() - 1); + return sb.toString(); + } + return ""; + } + + public static FileUtil getFileUtil(String format) { + String tempformat = ""; + if (!StringUtils.isBlank(format)) { + tempformat = format.toLowerCase(); + } + switch (tempformat) { + case "excel": + return (new ExcelFileUtil()); + default: + return (new ExcelFileUtil()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/GeoLocationJsonKey.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/GeoLocationJsonKey.java new file mode 100644 index 0000000000..8c3b8c4ad7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/GeoLocationJsonKey.java @@ -0,0 +1,16 @@ +package org.sunbird.common.models.util; + +/** Created by arvind on 19/4/18. */ +public class GeoLocationJsonKey { + + private GeoLocationJsonKey() {} + + public static final String PARENT_CODE = "parentCode"; + public static final String CODE = "code"; + public static final String LOCATION_TYPE = "type"; + public static final String PARENT_ID = "parentId"; + public static final String SUNBIRD_VALID_LOCATION_TYPES = "sunbird_valid_location_types"; + public static final String PROPERTY_NAME = "name"; + public static final String PROPERTY_VALUE = "value"; + public static final String ID = "id"; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/HttpUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/HttpUtil.java new file mode 100644 index 0000000000..57d5b1cfe6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/HttpUtil.java @@ -0,0 +1,862 @@ +/** */ +package org.sunbird.common.models.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URI; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.annotation.NotThreadSafe; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.methods.HttpPatch; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.entity.mime.MIME; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.sunbird.common.models.response.HttpUtilResponse; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.util.KeycloakRequiredActionLinkUtil; + +/** + * This utility method will handle external http call + * + * @author Manzarul + */ +public class HttpUtil { + + private HttpUtil() {} + + /** + * Makes an HTTP request using GET method to the specified URL. + * + * @param requestURL the URL of the remote server + * @param headers the Map + * @return An String object + * @throws IOException thrown if any I/O error occurred + */ + public static String sendGetRequest(String requestURL, Map headers) + throws IOException { + long startTime = System.currentTimeMillis(); + HttpURLConnection httpURLConnection = getRequest(requestURL, headers, startTime); + String str = getResponse(httpURLConnection); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendGetRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return str; + } + + /** + * Makes an HTTP request using GET method to the specified URLand in response it will return Map + * of status code with get response in String format. + * + * @param requestURL the URL of the remote server + * @param headers the Map + * @return HttpUtilResponse + * @throws IOException thrown if any I/O error occurred + */ + public static HttpUtilResponse doGetRequest(String requestURL, Map headers) + throws IOException { + long startTime = System.currentTimeMillis(); + HttpURLConnection httpURLConnection = getRequest(requestURL, headers, startTime); + HttpUtilResponse response = null; + String body = ""; + try { + body = getResponse(httpURLConnection); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpURLConnection.getResponseCode()); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil doGetRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return response; + } + + /** + * @param requestURL + * @param headers + * @param startTime + * @return + * @throws MalformedURLException + * @throws IOException + * @throws ProtocolException + */ + private static HttpURLConnection getRequest( + String requestURL, Map headers, long startTime) throws IOException { + ProjectLogger.log( + "HttpUtil sendGetRequest method started at ==" + + startTime + + " for requestURL " + + requestURL, + LoggerEnum.PERF_LOG); + URL url = new URL(requestURL); + HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setUseCaches(false); + httpURLConnection.setDoInput(true); + httpURLConnection.setDoOutput(false); + httpURLConnection.setRequestMethod(ProjectUtil.Method.GET.name()); + if (headers != null && headers.size() > 0) { + setHeaders(httpURLConnection, headers); + } + return httpURLConnection; + } + + /** + * Makes an HTTP request using POST method to the specified URL. + * + * @param requestURL the URL of the remote server + * @param params A map containing POST data in form of key-value pairs + * @return String + * @throws IOException thrown if any I/O error occurred + */ + public static String sendPostRequest( + String requestURL, Map params, Map headers) + throws IOException { + long startTime = System.currentTimeMillis(); + HttpURLConnection httpURLConnection = postRequest(requestURL, params, headers, startTime); + String str = getResponse(httpURLConnection); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendPostRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return str; + } + + /** + * Makes an HTTP request using POST method to the specified URL and in response it will return Map + * of status code with post response in String format. + * + * @param requestURL the URL of the remote server + * @param params A map containing POST data in form of key-value pairs + * @return HttpUtilResponse + * @throws IOException thrown if any I/O error occurred + */ + public static HttpUtilResponse doPostRequest( + String requestURL, Map params, Map headers) + throws IOException { + long startTime = System.currentTimeMillis(); + HttpURLConnection httpURLConnection = postRequest(requestURL, params, headers, startTime); + HttpUtilResponse response = null; + String body = ""; + try { + body = getResponse(httpURLConnection); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpURLConnection.getResponseCode()); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil doPostRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return response; + } + + private static HttpURLConnection postRequest( + String requestURL, Map params, Map headers, long startTime) + throws IOException { + HttpURLConnection httpURLConnection = null; + OutputStreamWriter writer = null; + ProjectLogger.log( + "HttpUtil sendPostRequest method started at ==" + + startTime + + " for requestURL " + + requestURL, + LoggerEnum.PERF_LOG); + try { + URL url = new URL(requestURL); + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setUseCaches(false); + httpURLConnection.setDoInput(true); + httpURLConnection.setRequestMethod(ProjectUtil.Method.POST.name()); + StringBuilder requestParams = new StringBuilder(); + if (params != null && params.size() > 0) { + httpURLConnection.setDoOutput(true); + // creates the params string, encode them using URLEncoder + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + requestParams.append(URLEncoder.encode(key, "UTF-8")); + requestParams.append("=").append(URLEncoder.encode(value, "UTF-8")); + requestParams.append("&"); + } + } + if (headers != null && headers.size() > 0) { + setHeaders(httpURLConnection, headers); + } + if (requestParams.length() > 0) { + writer = + new OutputStreamWriter(httpURLConnection.getOutputStream(), StandardCharsets.UTF_8); + writer.write(requestParams.toString()); + writer.flush(); + } + } catch (IOException ex) { + ProjectLogger.log(ex.getMessage(), ex); + throw ex; + } finally { + if (null != writer) { + try { + writer.close(); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + } + } + return httpURLConnection; + } + + /** + * Makes an HTTP request using POST method to the specified URL. + * + * @param requestURL the URL of the remote server + * @param params A map containing POST data in form of key-value pairs + * @return An HttpURLConnection object + * @throws IOException thrown if any I/O error occurred + */ + public static String sendPostRequest( + String requestURL, String params, Map headers) throws IOException { + long startTime = System.currentTimeMillis(); + HttpURLConnection httpURLConnection = postRequest(requestURL, params, headers, startTime); + String str = getResponse(httpURLConnection); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendPostRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return str; + } + + private static HttpURLConnection postRequest( + String requestURL, String params, Map headers, long startTime) + throws IOException { + ProjectLogger.log( + "HttpUtil sendPostRequest method started at ==" + + startTime + + " for requestURL " + + requestURL, + LoggerEnum.PERF_LOG); + HttpURLConnection httpURLConnection = null; + OutputStreamWriter writer = null; + try { + URL url = new URL(requestURL); + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setUseCaches(false); + httpURLConnection.setDoInput(true); + httpURLConnection.setRequestMethod(ProjectUtil.Method.POST.name()); + httpURLConnection.setDoOutput(true); + if (headers != null && headers.size() > 0) { + setHeaders(httpURLConnection, headers); + } + writer = new OutputStreamWriter(httpURLConnection.getOutputStream(), StandardCharsets.UTF_8); + writer.write(params); + writer.flush(); + } catch (IOException e) { + ProjectLogger.log("HttpUtil:postRequest call failure with error = " + e.getMessage(), e); + throw e; + } finally { + if (null != writer) { + try { + writer.close(); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + } + } + return httpURLConnection; + } + + /** + * Makes an HTTP request using POST method to the specified URL and in response it will return Map + * of status code with post response in String format. + * + * @param requestURL the URL of the remote server + * @param params A map containing POST data in form of key-value pairs + * @return HttpUtilResponse + * @throws IOException thrown if any I/O error occurred + */ + public static HttpUtilResponse doPostRequest( + String requestURL, String params, Map headers) throws IOException { + long startTime = System.currentTimeMillis(); + HttpURLConnection httpURLConnection = postRequest(requestURL, params, headers, startTime); + HttpUtilResponse response = null; + String body = ""; + try { + body = getResponse(httpURLConnection); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpURLConnection.getResponseCode()); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil doPostRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return response; + } + + private static String getResponse(HttpURLConnection httpURLConnection) throws IOException { + InputStream inStream = null; + BufferedReader reader = null; + StringBuilder builder = new StringBuilder(); + try { + inStream = httpURLConnection.getInputStream(); + reader = new BufferedReader(new InputStreamReader(inStream, StandardCharsets.UTF_8)); + String line = null; + while ((line = reader.readLine()) != null) { + builder.append(line); + } + } catch (IOException e) { + ProjectLogger.log("Error in getResponse HttpUtil:", e); + throw e; + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + ProjectLogger.log("Error while closing the reader:", e); + } + } + if (inStream != null) { + try { + inStream.close(); + } catch (IOException e) { + ProjectLogger.log("Error while closing the stream:", e); + } + } + if (httpURLConnection != null) { + httpURLConnection.disconnect(); + } + } + return builder.toString(); + } + + /** + * Makes an HTTP request using PATCH method to the specified URL. + * + * @param requestURL the URL of the remote server + * @param params A map containing POST data in form of key-value pairs + * @return An HttpURLConnection object + * @throws IOException thrown if any I/O error occurred + */ + public static String sendPatchRequest( + String requestURL, String params, Map headers) throws IOException { + long startTime = System.currentTimeMillis(); + Map logInfo = genarateLogInfo(JsonKey.API_CALL, "API CALL : " + requestURL); + ProjectLogger.log( + "HttpUtil sendPatchRequest method started at ==" + + startTime + + " for requestURL and params " + + requestURL + + " param==" + + params, + LoggerEnum.PERF_LOG); + + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPatch patch = new HttpPatch(requestURL); + setHeaders(patch, headers); + StringEntity entity = new StringEntity(params); + patch.setEntity(entity); + CloseableHttpResponse response = httpClient.execute(patch); + if (response.getStatusLine().getStatusCode() == ResponseCode.OK.getResponseCode()) { + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendPatchRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return ResponseCode.success.getErrorCode(); + } + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "Patch request failure status code ==" + + response.getStatusLine().getStatusCode() + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return "Failure"; + } catch (Exception e) { + ProjectLogger.log("HttpUtil call fails == " + e.getMessage(), e); + } + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendPatchRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + return "Failure"; + } + + /** + * Set the header for request. + * + * @param httpPatch HttpURLConnection + * @param headers Map + */ + private static void setHeaders(HttpPatch httpPatch, Map headers) { + Iterator> itr = headers.entrySet().iterator(); + while (itr.hasNext()) { + Entry entry = itr.next(); + httpPatch.setHeader(entry.getKey(), entry.getValue()); + } + } + + /** + * Set the header for request. + * + * @param httpURLConnection HttpURLConnection + * @param headers Map + */ + private static void setHeaders(HttpURLConnection httpURLConnection, Map headers) { + Iterator> itr = headers.entrySet().iterator(); + while (itr.hasNext()) { + Entry entry = itr.next(); + httpURLConnection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + + private static Map genarateLogInfo(String logType, String message) { + + Map info = new HashMap<>(); + info.put(JsonKey.LOG_TYPE, logType); + long startTime = System.currentTimeMillis(); + info.put(JsonKey.START_TIME, startTime); + info.put(JsonKey.MESSAGE, message); + info.put(JsonKey.LOG_LEVEL, JsonKey.INFO); + return info; + } + + /** + * @description this method will send the patch request and in response it will return Map of + * status code with patch method response in String format + * @param requestURL + * @param params + * @param headers (Map) + * @return HttpUtilResponse + * @throws IOException + */ + public static HttpUtilResponse doPatchRequest( + String requestURL, String params, Map headers) throws IOException { + long startTime = System.currentTimeMillis(); + Map logInfo = genarateLogInfo(JsonKey.API_CALL, "API CALL : " + requestURL); + ProjectLogger.log( + "HttpUtil sendPatchRequest method started at ==" + + startTime + + " for requestURL " + + requestURL, + LoggerEnum.PERF_LOG); + + HttpPatch patch = new HttpPatch(requestURL); + setHeaders(patch, headers); + StringEntity entity = new StringEntity(params); + patch.setEntity(entity); + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + ProjectLogger.log("response code for Patch Resques"); + HttpResponse httpResponse = httpClient.execute(patch); + HttpUtilResponse response = null; + String body = ""; + try { + body = generateResponse(httpResponse); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpResponse.getStatusLine().getStatusCode()); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil doPatchRequest method end at ==" + + stopTime + + " for requestURL " + + requestURL + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + // telemetryProcessingCall(logInfo); + return response; + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + throw e; + } + } + + /** + * @description this method will post the form data and in response it will return Map of status + * code with post response in String format + * @param reqData (Map) + * @param fileData (Map) + * @param headers (Map) + * @param url + * @return HttpUtilResponse + * @throws IOException + */ + public static HttpUtilResponse postFormData( + Map reqData, + Map fileData, + Map headers, + String url) + throws IOException { + long startTime = System.currentTimeMillis(); + Map logInfo = genarateLogInfo(JsonKey.API_CALL, "API CALL : " + url); + ProjectLogger.log( + "HttpUtil postFormData method started at ==" + startTime + " for requestURL " + url, + LoggerEnum.PERF_LOG); + try (CloseableHttpClient client = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(url); + Set> headerEntry = headers.entrySet(); + for (Entry headerObj : headerEntry) { + httpPost.addHeader(headerObj.getKey(), headerObj.getValue()); + } + + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + Set> entry = reqData.entrySet(); + for (Entry entryObj : entry) { + builder.addTextBody( + entryObj.getKey(), + entryObj.getValue(), + ContentType.create("text/plain", MIME.UTF8_CHARSET)); + } + Set> fileEntry = fileData.entrySet(); + for (Entry entryObj : fileEntry) { + if (!StringUtils.isBlank(entryObj.getKey()) && null != entryObj.getValue()) { + builder.addBinaryBody( + entryObj.getKey(), + entryObj.getValue(), + ContentType.APPLICATION_OCTET_STREAM, + entryObj.getKey()); + } + } + HttpEntity multipart = builder.build(); + httpPost.setEntity(multipart); + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil postFormData method end at ==" + + stopTime + + " for requestURL " + + url + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + HttpResponse httpResponse = client.execute(httpPost); + HttpUtilResponse response = null; + String body = ""; + try { + body = generateResponse(httpResponse); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpResponse.getStatusLine().getStatusCode()); + // telemetryProcessingCall(logInfo); + return response; + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while calling postFormData method.", ex); + throw ex; + } + } + + private static String generateResponse(HttpResponse httpResponse) throws IOException { + StringBuilder builder1 = new StringBuilder(); + BufferedReader br = + new BufferedReader(new InputStreamReader((httpResponse.getEntity().getContent()))); + String output; + while ((output = br.readLine()) != null) { + builder1.append(output); + } + return builder1.toString(); + } + + /** + * @description this method will process send delete request and in response it will return Map of + * status code with post response in String format + * @param headers + * @param url + * @return HttpUtilResponse + * @throws IOException + */ + public static HttpUtilResponse sendDeleteRequest(Map headers, String url) + throws IOException { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "HttpUtil sendDeleteRequest method started at ==" + startTime + " for requestURL " + url, + LoggerEnum.PERF_LOG); + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + HttpDelete httpDelete = new HttpDelete(url); + ProjectLogger.log("Executing sendDeleteRequest " + httpDelete.getRequestLine()); + Map logInfo = genarateLogInfo(JsonKey.API_CALL, "API CALL : " + url); + Set> headerEntry = headers.entrySet(); + for (Entry headerObj : headerEntry) { + httpDelete.addHeader(headerObj.getKey(), headerObj.getValue()); + } + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendDeleteRequest method end at ==" + + stopTime + + " for requestURL " + + url + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + HttpResponse httpResponse = httpclient.execute(httpDelete); + HttpUtilResponse response = null; + String body = ""; + try { + body = generateResponse(httpResponse); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpResponse.getStatusLine().getStatusCode()); + // telemetryProcessingCall(logInfo); + return response; + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while calling sendDeleteRequest method.", ex); + throw ex; + } + } + + /** + * @description this method will process send delete request and in response it will return Map of + * status code with post response in String format + * @param headers + * @param url + * @param reqBody Map + * @return HttpUtilResponse + * @throws IOException + */ + public static HttpUtilResponse sendDeleteRequest( + Map reqBody, Map headers, String url) throws IOException { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "HttpUtil sendDeleteRequest method started at ==" + startTime + " for requestURL " + url, + LoggerEnum.PERF_LOG); + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + ObjectMapper mapper = new ObjectMapper(); + String reqString = mapper.writeValueAsString(reqBody); + HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(url); + StringEntity input = new StringEntity(reqString, ContentType.APPLICATION_JSON); + httpDelete.setEntity(input); + ProjectLogger.log("Executing sendDeleteRequest " + httpDelete.getRequestLine()); + Map logInfo = genarateLogInfo(JsonKey.API_CALL, "API CALL : " + url); + Set> headerEntry = headers.entrySet(); + for (Entry headerObj : headerEntry) { + httpDelete.addHeader(headerObj.getKey(), headerObj.getValue()); + } + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendDeleteRequest method end at ==" + + stopTime + + " for requestURL " + + url + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + HttpResponse httpResponse = httpclient.execute(httpDelete); + HttpUtilResponse response = null; + String body = ""; + try { + body = generateResponse(httpResponse); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpResponse.getStatusLine().getStatusCode()); + // telemetryProcessingCall(logInfo); + return response; + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while calling sendDeleteRequest method.", ex); + throw ex; + } + } + + /** + * this method call the http post method which accept post body as byte[] + * + * @param byteArr + * @param headers + * @param url + * @return + * @throws IOException + */ + public static HttpUtilResponse postInputStream( + byte[] byteArr, Map headers, String url) throws IOException { + try (CloseableHttpClient client = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(url); + HttpEntity entity = new ByteArrayEntity(byteArr); + httpPost.setEntity(entity); + Set> headerEntry = headers.entrySet(); + for (Entry headerObj : headerEntry) { + httpPost.addHeader(headerObj.getKey(), headerObj.getValue()); + } + HttpResponse httpResponse = client.execute(httpPost); + HttpUtilResponse response = null; + String body = ""; + try { + body = generateResponse(httpResponse); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpResponse.getStatusLine().getStatusCode()); + return response; + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while calling posting inputStream data method.", ex); + throw ex; + } + } + + /** + * @description this method will process send delete request and in response it will return Map of + * status code with post response in String format + * @param headers + * @param url + * @param reqBody as JSON String + * @return HttpUtilResponse + * @throws IOException + */ + public static HttpUtilResponse sendDeleteRequest( + String reqBody, Map headers, String url) throws IOException { + long startTime = System.currentTimeMillis(); + ProjectLogger.log( + "HttpUtil sendDeleteRequest method started at ==" + startTime + " for requestURL " + url, + LoggerEnum.PERF_LOG); + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(url); + StringEntity input = new StringEntity(reqBody, ContentType.APPLICATION_JSON); + httpDelete.setEntity(input); + ProjectLogger.log("Executing sendDeleteRequest " + httpDelete.getRequestLine()); + Map logInfo = genarateLogInfo(JsonKey.API_CALL, "API CALL : " + url); + Set> headerEntry = headers.entrySet(); + for (Entry headerObj : headerEntry) { + httpDelete.addHeader(headerObj.getKey(), headerObj.getValue()); + } + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + ProjectLogger.log( + "HttpUtil sendDeleteRequest method end at ==" + + stopTime + + " for requestURL " + + url + + " ,Total time elapsed = " + + elapsedTime, + LoggerEnum.PERF_LOG); + HttpResponse httpResponse = httpclient.execute(httpDelete); + HttpUtilResponse response = null; + String body = ""; + try { + body = generateResponse(httpResponse); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while reading body" + ex); + } + response = new HttpUtilResponse(body, httpResponse.getStatusLine().getStatusCode()); + // telemetryProcessingCall(logInfo); + return response; + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while calling sendDeleteRequest method.", ex); + throw ex; + } + } + + public static Map getHeader(Map input) throws Exception { + return new HashMap() { + { + put("Content-Type", "application/json"); + put( + JsonKey.X_AUTHENTICATED_USER_TOKEN, + KeycloakRequiredActionLinkUtil.getAdminAccessToken()); + if (MapUtils.isNotEmpty(input)) putAll(input); + } + }; + } +} + +@NotThreadSafe +class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase { + public static final String METHOD_NAME = "DELETE"; + + @Override + public String getMethod() { + return METHOD_NAME; + } + + public HttpDeleteWithBody(final String uri) { + super(); + setURI(URI.create(uri)); + } + + public HttpDeleteWithBody(final URI uri) { + super(); + setURI(uri); + } + + public HttpDeleteWithBody() { + super(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/JsonKey.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/JsonKey.java new file mode 100644 index 0000000000..b3dbac8bb6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/JsonKey.java @@ -0,0 +1,1052 @@ +package org.sunbird.common.models.util; + +import java.util.Arrays; +import java.util.List; + +/** + * This class will contains all the key related to request and response. + * + * @author Manzarul + */ +public final class JsonKey { + public static final String ANONYMOUS = "Anonymous"; + public static final String UNAUTHORIZED = "Unauthorized"; + public static final String MW_SYSTEM_HOST = "sunbird_mw_system_host"; + public static final String MW_SYSTEM_PORT = "sunbird_mw_system_port"; + public static final String MW_SYSTEM_CLIENT_PORT = "sunbird_mw_system_client_port"; + public static final String ACCESS_TOKEN = "access_token"; + public static final String ACCESSTOKEN = "accessToken"; + public static final String ACCOUNT_KEY = "sunbird_account_key"; + public static final String ACCOUNT_NAME = "sunbird_account_name"; + public static final String DOWNLOAD_LINK_EXPIRY_TIMEOUT = "download_link_expiry_timeout"; + public static final String SIGNED_URL = "signedUrl"; + public static final String REPORTS = "reports"; + public static final String PROGRESS_REPORT_SIGNED_URL = "courseProgressReportUrl"; + public static final String ASSESSMENT_REPORT_BLOB_URL = "reportUrl"; + public static final String ASSESSMENT_REPORT_SIGNED_URL = "assessmentReportUrl"; + public static final String BULK_UPLOAD_STATUS = "Status"; + public static final String BULK_UPLOAD_ERROR = "Remarks"; + public static final String ACTION_GROUP = "action_group"; + public static final String ACTION_GROUPS = "actionGroups"; + public static final String ACTION_NAME = "actionName"; + public static final String ACTION_URL = "actionUrl"; + public static final String ACTIONS = "actions"; + public static final String ACTIVE = "active"; + public static final String ACTOR_ID = "actorId"; + public static final String ACTOR_SERVICE = "Actor service"; + public static final String ACTOR_TYPE = "actorType"; + public static final String ADD_TYPE = "addType"; + public static final String ADDED_AT = "addedAt"; + public static final String ADDED_BY = "addedBy"; + public static final String ADDED_BY_NAME = "addedByName"; + public static final String ADDITIONAL_INFO = "ADDITIONAL_INFO"; + public static final String ADDRESS = "address"; + public static final String ADDRESS_DB = "address"; + public static final String ADDRESS_ID = "addressId"; + public static final String ADDRESS_LINE1 = "addressLine1"; + public static final String ADDRESS_LINE2 = "addressLine2"; + public static final String ADDRESS_TYPE = "address type"; + public static final String AGGREGATIONS = "aggregations"; + public static final String ALL = "all"; + public static final String ALLOWED_LOGIN = "allowedLogin"; + public static final String ANNOUNCEMENT = "announcement"; + public static final String API_ACCESS = "api_access"; + public static final String API_ACTOR_PROVIDER = "api_actor_provider"; + public static final String API_CALL = "API_CALL"; + public static final String API_ID = "apiId"; + public static final String APP_ICON = "appIcon"; + public static final String APP_MAP = "appMap"; + public static final String APP_SECTIONS = "appSections"; + public static final String APP_URL = "appUrl"; + public static final String APPICON = "appIcon"; + public static final String APPLICABLE_FOR = "applicableFor"; + public static final String APPROOVE_DATE = "approvalDate"; + public static final String APPROVED_BY = "approvedBy"; + public static final String APPROVED_BY_NAME = "approvedByName"; + public static final String APPROVED_DATE = "approvedDate"; + public static final String ASSESSMENT = "assessment"; + public static final String ASSESSMENT_EVENTS = "assessments"; + public static final String ASSESSMENT_TS = "assessmentTs"; + public static final String ASSESSMENT_ANSWERS = "answers"; + public static final String ASSESSMENT_ATTEMPT_DATE = "attemptedDate"; + public static final String ASSESSMENT_EVAL_DB = "assessment_eval_db"; + public static final String ASSESSMENT_GRADE = "grade"; + public static final String ASSESSMENT_ITEM_DB = "assessment_item_db"; + public static final String ASSESSMENT_ITEM_ID = "assessmentItemId"; + public static final String ASSESSMENT_MAX_SCORE = "maxScore"; + public static final String ASSESSMENT_SCORE = "score"; + public static final String ASSESSMENT_STATUS = "assessmentStatus"; + public static final String ASSESSMENT_TYPE = "assessmentType"; + public static final String ATTEMPT_ID = "attemptId"; + public static final String ATTEMPTED_COUNT = "attemptedCount"; + public static final String AUTH_TOKEN = "authToken"; + public static final String AUTH_USER_HEADER = "X-Authenticated-Userid"; + public static final String AUTH_WITH_MASTER_KEY = "authWithMasterKey"; + public static final String AUTHORIZATION = "Authorization"; + public static final String BACKGROUND_ACTOR_PROVIDER = "background_actor_provider"; + public static final String BAD_REQUEST = "badRequest"; + public static final String BADGE_TYPE_ID = "badgeTypeId"; + public static final String BADGES = "badges"; + public static final String BADGES_DB = "badge"; + public static final String BATCH = "batch"; + public static final String BATCH_ID = "batchId"; + public static final String BATCH_RELATIONS = "batch_relations"; + public static final String BEARER = "Bearer "; + public static final String BLOCKED = "blocked"; + public static final String BODY = "body"; + public static final String BULK_OP_DB = "BulkOpDb"; + public static final String BULK_UPLOAD_BATCH_DATA_SIZE = "bulk_upload_batch_data_size"; + public static final String BULK_UPLOAD_ORG_DATA_SIZE = "bulk_upload_org_data_size"; + public static final String BULK_UPLOAD_USER_DATA_SIZE = "sunbird_user_bulk_upload_size"; + public static final String BULK_USER_UPLOAD = "bulkUserUpload"; + public static final String CASSANDRA_IN_EMBEDDED_MODE = "cassandraInEmbeddedMode"; + public static final String CASSANDRA_SERVICE = "Cassandra service"; + public static final String CATEGORIES = "categories"; + public static final String CHANNEL = "channel"; + public static final String CHANNEL_REG_STATUS = "channelRegStatus"; + public static final String CHANNEL_REG_STATUS_ID = "003"; + public static final String CHANNELS = "channels"; + public static final String CHECKS = "checks"; + public static final String CHILD_OF = "childOf"; + public static final String CHILDREN = "children"; + public static final String CITY = "city"; + public static final String CLASS = "class"; + public static final String CLIENT_ID = "clientId"; + public static final String CLIENT_INFO_DB = "clientInfo_db"; + public static final String CLIENT_NAME = "clientName"; + public static final String CLIENT_NAMES = "client.names"; + public static final String CODE = "code"; + public static final String COMPLETED_COUNT = "completedCount"; + public static final String COMPLETENESS = "completeness"; + public static final String CONSUMER = "consumer"; + public static final String CONTACT_DETAILS = "contactDetail"; + public static final String CONTAINER = "container"; + public static final String CONTENT = "content"; + public static final String CONTENT_CREATOR = "CONTENT_CREATOR"; + public static final String CONTENT_ID = "contentId"; + public static final String CONTENT_IDS = "contentIds"; + public static final String CONTENT_LIST = "contentList"; + public static final String CONTENT_NAME = "contentName"; + public static final String CONTENT_PROGRESS = "progress"; + public static final String CONTENT_TYPE = "contentType"; + public static final String CONTENT_VERSION = "contentVersion"; + public static final String CONTENTS = "contents"; + public static final String CONTEXT = "context"; + public static final String CORRELATED_OBJECTS = "correlatedObjects"; + public static final String COUNT = "count"; + public static final String COUNT_DECREMENT_DATE = "countDecrementDate"; + public static final String COUNT_INCREMENT_DATE = "countIncrementDate"; + public static final String COUNTER_DECREMENT_STATUS = "countDecrementStatus"; + public static final String COUNTER_INCREMENT_STATUS = "countIncrementStatus"; + public static final String COUNTRY = "country"; + public static final String COUNTRY_CODE = "countryCode"; + public static final String COURSE = "course"; + public static final String COURSE_ADDITIONAL_INFO = "courseAdditionalInfo"; + public static final String COURSE_BATCH_DB = "courseBatchDB"; + public static final String COURSE_CREATED_FOR = "createdFor"; + public static final String COURSE_CREATOR = "courseCreator"; + public static final String COURSE_DURATION = "courseDuration"; + public static final String COURSE_ENROLL_DATE = "enrolledDate"; + public static final String COURSE_ID = "courseId"; + public static final String COURSE_IDS = "courseIds"; + public static final String COURSE_LIST = "courseList"; + public static final String COURSE_LOGO_URL = "courseLogoUrl"; + public static final String COURSE_MANAGEMENT_DB = "courseManagement_db"; + public static final String COURSE_NAME = "courseName"; + public static final String COURSE_PROGRESS = "progress"; + public static final String COURSE_PUBLISHED_STATUS = "course_publish_status"; + public static final String COURSE_VERSION = "courseVersion"; + public static final String CourseConsumption = "courseConsumption"; + public static final String CourseProgress = "courseProgress"; + public static final String COURSES = "courses"; + public static final String CREATE = "create"; + public static final String CREATED_BY = "createdBy"; + public static final String CREATED_DATE = "createdDate"; + public static final String CRITERIA = "criteria"; + public static final String CURRENT_LOGIN_TIME = "currentLoginTime"; + public static final String CURRENT_STATE = "CURRENT_STATE"; + public static final String DASHBOARD = "dashboard"; + public static final String DATA = "data"; + public static final String KEY = "key"; + public static final String KEYS = "keys"; + public static final String DATE = "date"; + public static final String DATE_HISTOGRAM = "DATE_HISTOGRAM"; + public static final String DATE_TIME = "dateTime"; + public static final String DB_IP = "db.ip"; + public static final String DB_KEYSPACE = "db.keyspace"; + public static final String DB_PASSWORD = "db.password"; + public static final String DB_PORT = "db.port"; + public static final String DB_USERNAME = "db.username"; + public static final String DEFAULT_ACTION_NAME = "Download Reports"; + public static final String DEFAULT_CONSUMER_ID = "internal"; + public static final String DEFAULT_ROOT_ORG_ID = "ORG_001"; + public static final String DEGREE = "degree"; + public static final String DELETE = "delete"; + public static final String DELTA = "delta"; + public static final String DESCRIPTION = "description"; + public static final String DOB = "dob"; + public static final String DOWNLOAD_URL = "downloadUrl"; + public static final String DUPLICATE = "duplicate"; + public static final String EDUCATION = "education"; + public static final String EDUCATION_DB = "user_education"; + public static final String EKS = "eks"; + public static final String SEARCH_SERVICE_API_BASE_URL = "sunbird_search_service_api_base_url"; + public static final String ANALYTICS_API_BASE_URL = "sunbird_analytics_api_base_url"; + public static final String EKSTEP_AUTHORIZATION = "ekstep_authorization"; + public static final String EKSTEP_BASE_URL = "ekstep_api_base_url"; + public static final String EKSTEP_CHANNEL_REG_API_URL = "ekstep.channel.reg.api.url"; + public static final String EKSTEP_CHANNEL_UPDATE_API_URL = "ekstep.channel.update.api.url"; + public static final String EKSTEP_CONCEPT_URL = "ekstep_concept_base_url"; + public static final String EKSTEP_CONTENT_SEARCH_BASE_URL = "ekstep_content_search_base_url"; + public static final String EKSTEP_CONTENT_SEARCH_URL = "ekstep_content_search_url"; + public static final String EKSTEP_CONTENT_UPDATE_URL = "ekstep.content.update.url"; + public static final String EKSTEP_CONTENT_URL = "content_url"; + public static final String EKSTEP_COURSE_PUBLISH_URL = "ekstep_course_publish_url"; + public static final String EKSTEP_DOMAIN_URL = "ekstep_domain_url"; + public static final String EKSTEP_ES_METRICS_API_URL = "ekstep_es_metrics_api_url"; + public static final String EKSTEP_GET_CHANNEL_LIST = "ekstep.channel.list.api.url"; + public static final String EKSTEP_METRICS_API_URL = "ekstep_metrics_api_url"; + public static final String EKSTEP_METRICS_AUTHORIZATION = "ekstep_metrics_authorization"; + public static final String EKSTEP_METRICS_URL = "ekstep_metrics_base_url"; + public static final String EKSTEP_SERVICE = "EkStep service"; + public static final String EKSTEP_TAG_API_URL = "ekstep.tag.api.url"; + public static final String EKSTEP_TELEMETRY_API_URL = "ekstep_telemetry_api_url"; + public static final String EKSTEP_TELEMETRY_BASE_URL = "ekstep_telemetry_api_base_url"; + public static final String EKSTEP_TELEMETRY_V3_URL = "eksetp_telemetry_V3_url"; + public static final String EMAIL = "email"; + public static final String EMAIL_REQUEST = "emailReq"; + public static final String EMAIL_SERVER_FROM = "sunbird_mail_server_from_email"; + public static final String EMAIL_SERVER_HOST = "sunbird_mail_server_host"; + public static final String EMAIL_SERVER_PASSWORD = "sunbird_mail_server_password"; + public static final String EMAIL_SERVER_PORT = "sunbird_mail_server_port"; + public static final String EMAIL_SERVER_USERNAME = "sunbird_mail_server_username"; + public static final String EMAIL_TEMPLATE_TYPE = "emailTemplateType"; + public static final String EMAIL_UNIQUE = "emailUnique"; + public static final String EMAIL_VERIFIED = "emailVerified"; + public static final String EMAIL_VERIFIED_UPDATED = "emailVerifiedUpdated"; + public static final String EMBEDDED = "embedded"; + public static final String EMBEDDED_CASSANDRA_HOST = "embedded_cassandra_host"; + public static final String EMBEDDED_CASSANDRA_PORT = "embedded_cassandra_port"; + public static final String EMBEDDED_CQL_FILE_NAME = "embedded_cql_file_name"; + public static final String EMBEDDED_MODE = "embedded"; + public static final String ENC_EMAIL = "encEmail"; + public static final String ENC_PHONE = "encPhone"; + public static final String ENCRYPTION_KEY = "sunbird_encryption_key"; + public static final String END_DATE = "endDate"; + public static final String END_TIME = "endTime"; + public static final String ENDORSE_DATE = "endorseDate"; + public static final String ENDORSED_USER_ID = "endorsedUserId"; + public static final String ENDORSEMENT_COUNT = "endorsementCount"; + public static final String ENDORSERS = "endorsers"; + public static final String ENDORSERS_LIST = "endorsersList"; + public static final String ENROLLMENT_END_DATE = "enrollmentEndDate"; + public static final String ENROLLMENT_START_DATE = "enrollementStartDate"; + public static final String ENROLLMENT_TYPE = "enrollmentType"; + public static final String ENROLMENTTYPE = "enrolmentType"; + public static final String ENV = "env"; + public static final String ERR_TYPE = "errtype"; + public static final String ERROR = "err"; + public static final String ERROR_MSG = "err_msg"; + public static final String ERRORMSG = "errmsg"; + public static final String ES_METRICS_PORT = "es_metrics_port"; + public static final String ES_SERVICE = "Elastic search service"; + public static final String ES_URL = "es_search_url"; + public static final String ESTIMATED_COUNT_REQ = "estimatedCountReq"; + public static final String EVENTS = "events"; + public static final String EXISTS = "exists"; + public static final String EXTERNAL_ID = "externalId"; + public static final String EXTERNAL_ID_VALUE = "externalIdValue"; + public static final String FACETS = "facets"; + public static final String FAILED = "FAILED"; + public static final String FAILURE = "failure"; + public static final String FAILURE_RESULT = "failureResult"; + public static final String FCM = "fcm"; + public static final String FCM_URL = "fcm.url"; + public static final String FIELD = "field"; + public static final String FIELDS = "fields"; + public static final String FILE = "file"; + public static final String FILE_NAME = "fileName"; + public static final String FILE_PARAMS = "fileParams"; + public static final String FILE_URL = "fileUrl"; + public static final String FILTER = "filter"; + public static final String FILTERS = "filters"; + public static final String FIRST_NAME = "firstName"; + public static final String FORM_PARAMS = "formParams"; + public static final String FORMAT = "format"; + public static final String FRAMEWORK = "framework"; + public static final String FROM_EMAIL = "fromEmail"; + public static final String GENDER = "gender"; + public static final String GEO_LOCATION_DB = "geoLocationDb"; + public static final String GRADE = "grade"; + public static final String GRADE_LEVEL = "gradeLevel"; + public static final String GROUP = "group"; + public static final String GROUP_QUERY = "groupQuery"; + public static final String HASH_TAG_ID = "hashtagid"; + public static final String HASHTAGID = "hashTagId"; + public static final String HEADER = "header"; + public static final String Healthy = "healthy"; + public static final String HOME_URL = "homeUrl"; + public static final String ID = "id"; + public static final String IDENTIFIER = "identifier"; + public static final String IMAGE = "image"; + public static final String INACTIVE = "inactive"; + public static final String INDEX = "index"; + public static final String INFO = "info"; + public static final String INSERT = "insert"; + public static final String INVITE_ONLY = "invite-only"; + public static final String IS_APPROVED = "isApproved"; + public static final String IS_AUTH_REQ = "isAuthReq"; + public static final String IS_DEFAULT = "isDefault"; + public static final String IS_DELETED = "isDeleted"; + public static final String IS_REJECTED = "isRejected"; + public static final String IS_ROOT_ORG = "isRootOrg"; + public static final String IS_SSO_ENABLED = "sso.enabled"; + public static final String IS_VERIFIED = "isVerified"; + public static final String JOB_NAME = "jobName"; + public static final String JOB_PROFILE = "jobProfile"; + public static final String JOB_PROFILE_DB = "user_job_profile"; + public static final String JOINING_DATE = "joiningDate"; + public static final String LANGUAGE = "language"; + public static final String LAST_ACCESS_TIME = "lastAccessTime"; + public static final String LAST_COMPLETED_TIME = "lastCompletedTime"; + public static final String LAST_LOGIN_TIME = "lastLoginTime"; + public static final String LAST_LOGOUT_TIME = "lastLogoutTime"; + public static final String LAST_NAME = "lastName"; + public static final String LAST_READ_CONTENT_STATUS = "lastReadContentStatus"; + public static final String LAST_READ_CONTENT_VERSION = "lastReadContentVersion"; + public static final String LAST_READ_CONTENTID = "lastReadContentId"; + public static final String LAST_UPDATED_TIME = "lastUpdatedTime"; + public static final String LEAF_NODE_COUNT = "leafNodesCount"; + public static final String LEARNER_CONTENT_DB = "learnerContent_db"; + public static final String LEARNER_COURSE_DB = "learnerCourse_db"; + public static final String LEARNER_SERVICE = "Learner service"; + public static final String LEVEL = "level"; + public static final String LIMIT = "limit"; + public static final String LIST = "List"; + public static final String LOC_ID = "locationId"; + public static final String LOCATION = "location"; + public static final String LOCATION_NAME = "locationName"; + public static final String LOCATION_ID = "locationId"; + public static final String LOCATION_IDS = "locationIds"; + public static final String LOCATIONS = "locations"; + public static final String LOG_LEVEL = "logLevel"; + public static final String LOG_RECORD = "logRecord"; + public static final String LOG_TYPE = "logType"; + public static final String LOGIN_GENERAL = "general"; + public static final String LOGIN_ID = "loginId"; + public static final String LOGIN_ID_DELIMETER = "@"; + public static final String LOGIN_TYPE = "type"; + public static final String MAIL_NOTE = "mail_note"; + public static final String MANDATORY_FIELDS = "mandatoryFields"; + public static final String MAP = "map"; + public static final String MAPPED_FORM_PARAMS = "mappedFormParams"; + public static final String MASKED_EMAIL = "maskedEmail"; + public static final String MASKED_PHONE = "maskedPhone"; + public static final String MASTER_ACTION = "master_action"; + public static final String MASTER_KEY = "masterKey"; + public static final String MEDIA_TYPE_DB = "mediaTypeDB"; + public static final String MENTORS = "mentors"; + public static final String MESSAGE = "message"; + public static final String MESSAGE_Id = "message_id"; + public static final String MESSAGE_ID = "X-msgId"; + public static final String METHOD = "method"; + public static final String METHOD_NAME = "methodName"; + public static final String METRICS = "metrics"; + public static final String MISSING_FIELDS = "missingFields"; + public static final String MOBILE = "mobile"; + public static final String NAME = "name"; + public static final String NEW_PASSWORD = "newPassword"; + public static final String NO_OF_LECTURES = "noOfLectures"; + public static final String NO_OF_MEMBERS = "noOfMembers"; + public static final String NOT_AVAILABLE = "NA"; + public static final String NOT_EXISTS = "not_exists"; + public static final String NOTE = "note"; + public static final String NOTE_ID = "noteId"; + public static final String NOTIFICATION = "notification"; + public static final String NULL = "null"; + public static final String OBJECT_ID = "objectId"; + public static final String OBJECT_IDS = "objectIds"; + public static final String OBJECT_TYPE = "objectType"; + public static final String OFFSET = "offset"; + public static final String ON = "ON"; + public static final String ONBOARDING_WELCOME_MAIL_BODY = "onboarding_welcome_mail_body"; + public static final String OPEN = "open"; + public static final String OPERATION = "operation"; + public static final String OPERATION_FOR = "operationFor"; + public static final String OPERATION_TYPE = "operationType"; + public static final String ORDER = "order"; + public static final String ORG_CODE = "orgCode"; + public static final String ORG_CODE_HEADER = "X-Org-code"; + public static final String ORG_EXT_ID_DB = "org_external_identity"; + public static final String ORG_DB = "org_db"; + public static final String ORG_ID = "orgId"; + public static final String ORG_ID_ONE = "orgIdOne"; + public static final String ORG_ID_TWO = "orgIdTwo"; + public static final String ORG_IMAGE_URL = "orgImageUrl"; + public static final String ORG_JOIN_DATE = "orgJoinDate"; + public static final String ORG_LEFT_DATE = "orgLeftDate"; + public static final String ORG_MAP_DB = "org_mapping"; + public static final String ORG_NAME = "orgName"; + public static final String ORG_RELATIONS = "org_relations"; + public static final String ORG_SERVER_FROM_NAME = "orgServerFromName"; + public static final String ORG_TYPE = "orgType"; + public static final String ORG_TYPE_DB = "org_type"; + public static final String ORG_TYPE_ID = "orgTypeId"; + public static final String ORGANISATION = "organisation"; + public static final String ORGANISATION_ID = "organisationId"; + public static final String ORGANISATION_NAME = "orgName"; + public static final String ORGANISATIONS = "organisations"; + public static final String OrgConsumption = "orgConsumption"; + public static final String OrgCreation = "orgCreation"; + public static final String OTP = "otp"; + public static final String OTP_EMAIL_RESET_PASSWORD_TEMPLATE = "otpEmailResetPasswordTemplate"; + public static final String OTP_PHONE_RESET_PASSWORD_TEMPLATE = "otpPhoneResetPasswordTemplate"; + public static final String VERIFY_PHONE_OTP_TEMPLATE = "verifyPhoneOtpTemplate"; + public static final String PAGE = "page"; + public static final String PAGE_ID = "pageId"; + public static final String PAGE_MGMT_DB = "page_mgmt_db"; + public static final String PAGE_NAME = "name"; + public static final String PAGE_SECTION = "page_section"; + public static final String PAGE_SECTION_DB = "page_section_db"; + public static final String PARAMS = "params"; + public static final String PARENT_OF = "parentOf"; + public static final String PARENT_ORG_ID = "parentOrgId"; + public static final String PARTICIPANT = "participant"; + public static final String PARTICIPANTS = "participants"; + public static final String PASSWORD = "password"; + public static final String PDATA = "pdata"; + + public static final String PERCENTAGE = "percentage"; + public static final String PERIOD = "period"; + public static final String PHONE = "phone"; + public static final String PHONE_NUMBER_VERIFIED = "phoneNumberVerified"; + public static final String PHONE_UNIQUE = "phoneUnique"; + public static final String PHONE_VERIFIED = "phoneVerified"; + public static final String PID = "pid"; + public static final String PORTAL_MAP = "portalMap"; + public static final String PORTAL_SECTIONS = "portalSections"; + public static final String POSITION = "position"; + public static final String PREFERRED_LANGUAGE = "preferredLanguage"; + public static final String PREV_STATE = "PREV_STATE"; + public static final String PRIMARY_KEY_DELIMETER = "##"; + public static final String PRIVATE = "private"; + public static final String PROCESS_END_TIME = "processEndTime"; + public static final String PROCESS_ID = "processId"; + public static final String PROCESS_START_TIME = "processStartTime"; + public static final String PROCESSING_STATUS = "processingStatus"; + public static final String PDATA_ID = "telemetry_pdata_id"; + public static final String PDATA_PID = "telemetry_pdata_pid"; + public static final String PDATA_VERSION = "telemetry_pdata_ver"; + public static final String PROFILE_SUMMARY = "profileSummary"; + public static final String PROFILE_VISIBILITY = "profileVisibility"; + public static final String PROGRESS = "progress"; + public static final String PROPERTIES = "properties"; + public static final String PROPS = "props"; + public static final String PROVIDER = "provider"; + public static final String PUBLIC = "public"; + public static final String PUBLISH_COURSE = "publishCourse"; + public static final String QUERY = "query"; + public static final String QUERY_FIELDS = "queryFields"; + public static final String RECEIVER_ID = "receiverId"; + public static final String RECIPIENT_COUNT = "recipientCount"; + public static final String RECIPIENT_EMAILS = "recipientEmails"; + public static final String RECIPIENT_USERIDS = "recipientUserIds"; + public static final String RECOMMEND_TYPE = "recommendType"; + public static final String REGISTERED_ORG = "registeredOrg"; + public static final String REGISTERED_ORG_ID = "regOrgId"; + public static final String RELATION = "relation"; + public static final String RELATIONS = "relations"; + public static final String REMOTE = "remote"; + public static final String REPLACE_WITH_ASTERISK = "*"; + public static final String REPLACE_WITH_X = "X"; + public static final String REPORT_TRACKING_DB = "reportTrackingDb"; + public static final String REQ_ID = "reqId"; + public static final String REQUEST = "request"; + public static final String REQUEST_ID = "requestId"; + public static final String REQUEST_MESSAGE_ID = "msgId"; + public static final String REQUEST_TYPE = "requestType"; + public static final String REQUESTED_BY = "requestedBy"; + public static final String RES_MSG_ID = "resmsgId"; + public static final String RESOURCE_ID = "resourceId"; + public static final String RESPONSE = "response"; + public static final String RESULT = "result"; + public static final String RETIRED = "retired"; + public static final String RETRY_COUNT = "retryCount"; + public static final String ROLE = "role"; + public static final String ROLE_GROUP = "role_group"; + public static final String ROLE_GROUP_ID = "rolegroupid"; + public static final String ROLES = "roles"; + public static final String ROLLUP = "rollup"; + public static final String ROOT_ORG = "rootOrg"; + public static final String ROOT_ORG_ID = "rootOrgId"; + public static final String SCHEDULER_JOB = "scheduler"; + public static final String SEARCH = "search"; + public static final String SEARCH_QUERY = "searchQuery"; + public static final String SEARCH_TOP_N = "searchTopN"; + public static final String SECTION = "section"; + public static final String SECTION_DATA_TYPE = "sectionDataType"; + public static final String SECTION_DISPLAY = "display"; + public static final String SECTION_ID = "sectionId"; + public static final String SECTION_MGMT_DB = "section_mgmt_db"; + public static final String SECTION_NAME = "name"; + public static final String SECTIONS = "sections"; + public static final String SERIES = "series"; + public static final String SIZE = "size"; + public static final String SKILL_ENDORSEMENT_DB = "skillEndorsementDb"; + public static final String SKILL_NAME = "skillName"; + public static final String SKILL_NAME_TO_LOWERCASE = "skillnametolowercase"; + public static final String SKILLS = "skills"; + public static final String SKILLS_LIST_DB = "skillsListDb"; + public static final String SLUG = "slug"; + public static final String SNAPSHOT = "snapshot"; + public static final String SORT = "sort"; + public static final String SORT_BY = "sort_by"; + public static final String SOURCE = "source"; + public static final String SOURCE_HEADER = "X-Source"; + public static final String SPLIT = "split"; + public static final String SSO_CLIENT_ID = "sso.client.id"; + public static final String SSO_CLIENT_SECRET = "sso.client.secret"; + public static final String SSO_PASSWORD = "sso.password"; + public static final String SSO_POOL_SIZE = "sso.connection.pool.size"; + public static final String SSO_PUBLIC_KEY = "sunbird_sso_publickey"; + public static final String SSO_REALM = "sso.realm"; + public static final String SSO_URL = "sso.url"; + public static final String SSO_USERNAME = "sso.username"; + public static final String STACKTRACE = "stacktrace"; + public static final String STANDALONE_MODE = "standalone"; + public static final String START_DATE = "startDate"; + public static final String START_TIME = "startTime"; + public static final String STATE = "state"; + public static final String STATUS = "status"; + public static final String STATUS_CODE = "statusCode"; + public static final String SUB_SECTIONS = "subSections"; + public static final String SUBJECT = "subject"; + public static final String SUBMIT_DATE = "submitDate"; + public static final String SUBTYPE = "subtype"; + public static final String SUCCESS = "SUCCESS"; + public static final String SUCCESS_RESULT = "successResult"; + public static final String SUMMARY = "summary"; + public static final String SUNBIRD = "sunbird"; + public static final String SUNBIRD_ALLOWED_LOGIN = "sunbird_allowed_login"; + public static final String SUNBIRD_APP_URL = "sunbird_app_url"; + public static final String SUNBIRD_API_BASE_URL = "sunbird_api_base_url"; + public static final String SUNBIRD_CASSANDRA_IP = "sunbird_cassandra_host"; + public static final String SUNBIRD_CASSANDRA_KEYSPACE = "sunbird_cassandra_keyspace"; + public static final String SUNBIRD_CASSANDRA_MODE = "sunbird_cassandra_mode"; + public static final String SUNBIRD_CASSANDRA_PASSWORD = "sunbird_cassandra_password"; + public static final String SUNBIRD_CASSANDRA_PORT = "sunbird_cassandra_port"; + public static final String SUNBIRD_CASSANDRA_USER_NAME = "sunbird_cassandra_username"; + public static final String SUNBIRD_ENCRYPTION = "sunbird_encryption"; + public static final String SUNBIRD_ENV_LOGO_URL = "sunbird_env_logo_url"; + public static final String SUNBIRD_ES_CHANNEL = "es.channel.name"; + public static final String SUNBIRD_ES_CLUSTER = "sunbird_es_cluster"; + public static final String SUNBIRD_ES_IP = "sunbird_es_host"; + public static final String SUNBIRD_ES_PORT = "sunbird_es_port"; + public static final String SUNBIRD_FCM_ACCOUNT_KEY = "sunbird_fcm_account_key"; + public static final String SUNBIRD_INSTALLATION = "sunbird_installation"; + public static final String SUNBIRD_NETTY_HOST = "sunbird_netty_host"; + public static final String SUNBIRD_NETTY_PORT = "sunbird_netty_port"; + public static final String SUNBIRD_PG_DB = "sunbird_pg_db"; + public static final String SUNBIRD_PG_HOST = "sunbird_pg_host"; + public static final String SUNBIRD_PG_PASSWORD = "sunbird_pg_password"; + public static final String SUNBIRD_PG_PORT = "sunbird_pg_port"; + public static final String SUNBIRD_PG_USER = "sunbird_pg_user"; + public static final String SUNBIRD_PLUGIN = "sunbirdplugin"; + public static final String SUNBIRD_QUARTZ_MODE = "sunbird_quartz_mode"; + public static final String SUNBIRD_SSO_CLIENT_ID = "sunbird_sso_client_id"; + public static final String SUNBIRD_SSO_CLIENT_SECRET = "sunbird_sso_client_secret"; + public static final String SUNBIRD_SSO_PASSWORD = "sunbird_sso_password"; + public static final String SUNBIRD_SSO_RELAM = "sunbird_sso_realm"; + public static final String SUNBIRD_SSO_URL = "sunbird_sso_url"; + public static final String SUNBIRD_SSO_USERNAME = "sunbird_sso_username"; + public static final String SUNBIRD_WEB_URL = "sunbird_web_url"; + public static final String SUNBIRD_GET_ORGANISATION_API = "sunbird_search_organisation_api"; + public static final String SUNBIRD_GET_SINGLE_USER_API = "sunbird_read_user_api"; + public static final String SUNBIRD_GET_MULTIPLE_USER_API = "sunbird_search_user_api"; + public static final String SUNBIRD_CHANNEL_READ_API = "sunbird_channel_read_api"; + public static final String SUNBIRD_FRAMEWORK_READ_API = "sunbird_framework_read_api"; + public static final String SUNBIRD_CONTENT_GET_HIERARCHY_API = "sunbird_get_hierarchy_api"; + public static final String SUNBIRD_CONTENT_READ_API = "sunbird_content_read_api"; + public static final String SUNBIRD_USERNAME_NUM_DIGITS = "sunbird_username_num_digits"; + public static final String SYSTEM = "system"; + public static final String SYSTEM_SETTINGS_DB = "system_settings"; + public static final String TAG = "tag"; + public static final String TAGS = "tags"; + public static final String TARGET_OBJECT = "targetObject"; + public static final String TC_UPDATED_DATE = "tcUpdatedAt"; + public static final String TELEMETRY_CONTEXT = "TELEMETRY_CONTEXT"; + public static final String TELEMETRY_EVENT_TYPE = "telemetryEventType"; + public static final String TELEMETRY_QUEUE_THRESHOLD_VALUE = "telemetry_queue_threshold_value"; + public static final String TEMPORARY_PASSWORD = "tempPassword"; + public static final String TENANT_PREFERENCE = "tenantPreference"; + public static final String TENANT_PREFERENCE_DB = "tenantPreferenceDb"; + public static final String TERM_AND_CONDITION_STATUS = "tcStatus"; + public static final String TERMS = "terms"; + public static final String THEME = "theme"; + public static final String THUMBNAIL = "thumbnail"; + public static final String TIME_TAKEN = "timeTaken"; + public static final String TIME_UNIT = "time_unit"; + public static final String TITLE = "title"; + public static final String TO = "to"; + public static final String TOC_URL = "tocUrl"; + public static final String TOKEN = "token"; + public static final String TOPIC = "topic"; + public static final String TOPIC_NAME = "topicName"; + public static final String TOPICS = "topics"; + public static final String TOPN = "topn"; + public static final String TRY_COUNT = "tryCount"; + public static final String TYPE = "type"; + public static final String UNDEFINED_IDENTIFIER = "Undefined column name "; + public static final String UNIQUE = "unique"; + public static final String UNKNOWN_IDENTIFIER = "Unknown identifier "; + public static final String UPDATE = "update"; + public static final String UPDATED_BY = "updatedBy"; + public static final String UPDATED_BY_NAME = "updatedByName"; + public static final String UPDATED_DATE = "updatedDate"; + public static final String UPLOADED_BY = "uploadedBy"; + public static final String UPLOADED_DATE = "uploadedDate"; + public static final String URL = "url"; + public static final String URL_ACTION = "url_action"; + public static final String URL_ACTION_ID = "url_action_ids"; + public static final String URLS = "urls"; + public static final String USER = "user"; + public static final String USER_ACTION_ROLE = "user_action_role"; + public static final String USER_AUTH_DB = "userAuth_db"; + public static final String USER_BADGES_DB = "user_badge"; + public static final String USER_COUNT = "userCount"; + public static final String USER_COUNT_TTL = "userCountTTL"; + public static final String USER_COURSE = "user_course"; + public static final String USER_COURSES = "userCourses"; + public static final String USER_DB = "user_db"; + public static final String USER_FOUND = "user exist with this login Id."; + public static final String USER_ID = "userId"; + public static final String USER_IDs = "userIds"; + public static final String USER_LIST = "userList"; + public static final String USER_LIST_REQ = "userListReq"; + public static final String USER_NAME = "username"; + public static final String USER_NOT_FOUND = "user does not exist with this login Id."; + public static final String USER_NOTES_DB = "userNotes_db"; + public static final String USER_ORG = "user_org"; + public static final String USER_ORG_DB = "user_org_db"; + public static final String USER_RELATIONS = "user_relations"; + public static final String USER_SKILL_DB = "userSkillDb"; + public static final String USERIDS = "userIds"; + public static final String USERNAME = "userName"; + public static final String USR_EXT_ID_DB = "user_external_identity"; + public static final String USR_ORG_DB = "user_org"; + public static final String VALUE = "value"; + public static final String VER = "ver"; + public static final String VERSION = "version"; + public static final String VIEW_COUNT = "viewCount"; + public static final String VIEW_POSITION = "viewPosition"; + public static final String WEB_PAGES = "webPages"; + public static final String WEB_URL = "webUrl"; + public static final String WELCOME_MESSAGE = "welcomeMessage"; + public static final String YEAR_OF_PASSING = "yearOfPassing"; + public static final String ZIPCODE = "zipcode"; + public static final String SUNBIRD_CONTENT_SERVICE_BASE_URL = "sunbird_content_service_base_url"; + public static final String SUNBIRD_CONTENT_SERVICE_AUTHORIZATION = + "sunbird_content_service_authorization"; + public static final String SUNBIRD_HEALTH_CHECK_ENABLE = "sunbird_health_check_enable"; + public static final String HEALTH = "health"; + public static final String SERVICE = "service"; + public static final String SOFT_CONSTRAINTS = "softConstraints"; + public static final String SUNBIRD_USER_ORG_API_BASE_URL = "sunbird_user_org_api_base_url"; + public static final String SUNBIRD_API_MGR_BASE_URL = "sunbird_api_mgr_base_url"; + public static final String SUNBIRD_AUTHORIZATION = "sunbird_authorization"; + public static final String SUNBIRD_CS_BASE_URL = "sunbird_cs_base_url"; + public static final String SUNBIRD_CS_SEARCH_PATH = "sunbird_cs_search_path"; + public static final String SUNBIRD_CONTENT_BADGE_ASSIGN_URL = "sunbird.content.badge.assign.url"; + public static final String SUNBIRD_CONTENT_BADGE_REVOKE_URL = "sunbird.content.badge.revoke.url"; + public static final String SUNBIRD_LMS_BASE_URL = "sunbird_lms_base_url"; + public static final String SUNBIRD_TELEMETRY_API_PATH = "sunbird_telemetry_api_path"; + public static final String SUNBIRD_LMS_TELEMETRY = "Sunbird_LMS_Telemetry"; + public static final String SUNBIRD_LMS_AUTHORIZATION = "sunbird_authorization"; + public static final String ETS = "ets"; + public static final String CONTENT_ENCODING = "Content-Encoding"; + public static final String EK_STEP = "EK-STEP"; + public static final String RESOURCE_NAME = "resourceName"; + public static final String BADGE_ASSERTIONS = "badgeAssertions"; + public static final String USER_BADGE_ASSERTION_DB = "user_badge_assertion"; + public static final String DURATION = "duration"; + public static final String OBJECT_STORE = "object-store"; + public static final String IMAGE_URL = "imgUrl"; + public static final String COMMUNITY_ID = "communityId"; + public static final String LOCATION_CODE = "locationCode"; + public static final String LATITUDE = "latitude"; + public static final String LONGITUDE = "longitude"; + public static final String UPLOAD_FILE_MAX_SIZE = "file_upload_max_size"; + public static final String PRIMARY_KEY = "PK"; + public static final String NON_PRIMARY_KEY = "NonPK"; + public static final String PARENT_ID = "parentId"; + public static final String CREATED_ON = "createdOn"; + public static final String UPDATED_ON = "updatedOn"; + public static final String LAST_UPDATED_ON = "lastUpdatedOn"; + public static final String LAST_UPDATED_BY = "lastUpdatedBy"; + public static final String SUNBIRD_DEFAULT_CHANNEL = "sunbird_default_channel"; + public static final String CASSANDRA_WRITE_BATCH_SIZE = "cassandra_write_batch_size"; + public static final String CASSANDRA_UPDATE_BATCH_SIZE = "cassandra_update_batch_size"; + public static final String ORG_EXTERNAL_ID = "orgExternalId"; + public static final String ORG_PROVIDER = "orgProvider"; + public static final String EXTERNAL_IDS = "externalIds"; + public static final String SUNBIRD_TELEMETRY_BASE_URL = "sunbird_telemetry_base_url"; + public static final String EXTERNAL_ID_TYPE = "externalIdType"; + public static final String ID_TYPE = "idType"; + public static final String ADD = "add"; + public static final String REMOVE = "remove"; + public static final String EDIT = "edit"; + public static final String DEFAULT_FRAMEWORK = "defaultFramework"; + public static final String SUNBIRD_OPENSABER_BRIDGE_ENABLE = "sunbird_open_saber_bridge_enable"; + public static final String EXTERNAL_ID_PROVIDER = "externalIdProvider"; + public static final String SUNBIRD_INSTALLATION_DISPLAY_NAME = + "sunbird_installation_display_name"; + public static final String USR_EXT_IDNT_TABLE = "usr_external_identity"; + public static final String END_TIME_IN_HOUR_MINUTE_SECOND = " 23:59:59"; + public static final String REGISTRY_ID = "registryId"; + public static final String RESPONSE_CODE = "responseCode"; + public static final String OK = "ok"; + public static final String SUNBIRD_APP_NAME = "sunbird_app_name"; + public static final String SUNBIRD_DEFAULT_COUNTRY_CODE = "sunbird_default_country_code"; + public static final String ONBOARDING_MAIL_SUBJECT = "onboarding_mail_subject"; + public static final String ONBOARDING_MAIL_MESSAGE = "onboarding_welcome_message"; + public static final String SUNBIRD_DEFAULT_WELCOME_MSG = "sunbird_default_welcome_sms"; + public static final String SUNBIRD_DEFAULT_USER_TYPE = "sunbird_default_user_type"; + public static final String ES_TYPES = "types"; + public static final String RECIPIENT_SEARCH_QUERY = "recipientSearchQuery"; + public static final String SUNBIRD_EMAIL_MAX_RECEPIENT_LIMIT = + "sunbird_email_max_recipients_limit"; + public static final String ORIGINAL_EXTERNAL_ID = "originalExternalId"; + public static final String ORIGINAL_ID_TYPE = "originalIdType"; + public static final String ORIGINAL_PROVIDER = "originalProvider"; + public static final String SUNBIRD_CASSANDRA_CONSISTENCY_LEVEL = + "sunbird_cassandra_consistency_level"; + public static final String VERSION_2 = "v2"; + public static final String CUSTODIAN_ORG_CHANNEL = "custodianOrgChannel"; + public static final String CUSTODIAN_ORG_ID = "custodianOrgId"; + public static final String APP_ID = "appId"; + public static final String REDIRECT_URI = "redirectUri"; + public static final String SET_PASSWORD_LINK = "set_password_link"; + public static final String VERIFY_EMAIL_LINK = "verify_email_link"; + public static final String LINK = "link"; + public static final String SET_PW_LINK = "setPasswordLink"; + public static final String SUNBIRD_URL_SHORTNER_ENABLE = "sunbird_url_shortner_enable"; + public static final String USER_PROFILE_CONFIG = "userProfileConfig"; + public static final String PUBLIC_FIELDS = "publicFields"; + public static final String PRIVATE_FIELDS = "privateFields"; + public static final String SUNBIRD_USER_PROFILE_FIELD_DEFAULT_VISIBILITY = + "sunbird_user_profile_field_default_visibility"; + public static final String DEFAULT_PROFILE_FIELD_VISIBILITY = "defaultProfileFieldVisibility"; + + public static final String SUNBIRD_COURSE_BATCH_NOTIFICATIONS_ENABLED = + "sunbird_course_batch_notification_enabled"; + + public static final String BATCH_START_DATE = "batchStartDate"; + public static final String BATCH_END_DATE = "batchEndDate"; + public static final String BATCH_NAME = "batchName"; + public static final String BATCH_MENTOR_ENROL = "batchMentorEnrol"; + public static final String BATCH_LEARNER_ENROL = "batchLearnerEnrol"; + public static final String COURSE_INVITATION = "Course Invitation"; + public static final String BATCH_LEARNER_UNENROL = "batchLearnerUnenrol"; + public static final String BATCH_MENTOR_UNENROL = "batchMentorUnenrol"; + public static final String UNENROLL_FROM_COURSE_BATCH = "Unenrolled from Training"; + public static final String OPEN_BATCH_LEARNER_UNENROL = "openBatchLearnerUnenrol"; + + public static final String MENTOR = "mentor"; + public static final String OLD = "old"; + public static final String NEW = "new"; + public static final String COURSE_BATCH = "courseBatch"; + public static final String ADDED_MENTORS = "addedMentors"; + public static final String REMOVED_MENTORS = "removedMentors"; + public static final String ADDED_PARTICIPANTS = "addedParticipants"; + public static final String REMOVED_PARTICIPANTS = "removedParticipants"; + public static final String URL_QUERY_STRING = "urlQueryString"; + public static final String SUNBIRD_API_REQUEST_LOWER_CASE_FIELDS = + "sunbird_api_request_lower_case_fields"; + public static final String ATTRIBUTE = "attribute"; + public static final String ERRORS = "errors"; + public static final String ROLE_LIST = "roleList"; + public static final String SUNBIRD_USER_PROFILE_READ_EXCLUDED_FIELDS = "read.excludedFields"; + public static final String COMPLETED_ON = "completedOn"; + public static final String CALLER_ID = "callerId"; + public static final String USER_TYPE = "userType"; + public static final String MANAGED_BY = "managedBy"; + public static final String MANAGED_FOR = "managedFor"; + + public static final String COURSE_BATCH_URL = "courseBatchUrl"; + public static final String SUNBIRD_COURSE_BATCH_NOTIFICATION_SIGNATURE = + "sunbird_course_batch_notification_signature"; + public static final String SIGNATURE = "signature"; + public static final String OPEN_BATCH_LEARNER_ENROL = "openBatchLearnerEnrol"; + public static final String CONTENT_PROPERTY_MEDIUM = "medium"; + public static final String CONTENT_PROPERTY_GRADE_LEVEL = "gradeLevel"; + public static final String CONTENT_PROPERTY_SUBJECT = "subject"; + public static final String CONTENT_PROPERTY_NAME = "name"; + public static final String CONTENT_PROPERTY_VISIBILITY = "visibility"; + public static final String CONTENT_PROPERTY_VISIBILITY_PARENT = "Parent"; + public static final String CONTENT_PROPERTY_MIME_TYPE = "mimeType"; + public static final String CONTENT_MIME_TYPE_COLLECTION = + "application/vnd.ekstep.content-collection"; + public static final String VERSION_KEY = "versionKey"; + public static final String CSV_SEPERATOR = ","; + public static final String CONTENT_CLOUD_STORAGE_TYPE = "sunbird_content_cloud_storage_type"; + public static final String CONTENT_AZURE_STORAGE_CONTAINER = + "sunbird_content_azure_storage_container"; + public static final String CLOUD_FOLDER_CONTENT = "sunbird_cloud_content_folder"; + public static final String TO_URL = "toUrl"; + public static final String TTL = "ttl"; + public static final String TEXTBOOK_TOC_CSV_TTL = "sunbird_texbook_toc_csv_ttl"; + public static final String FILE_TYPE_CSV = "csv"; + + // Texbook TOC + public static final String TEXTBOOK = "textbook"; + public static final String TEXTBOOK_ID = "textbookId"; + public static final String MODE = "mode"; + public static final String MIME_TYPE = "mimeType"; + public static final String METADATA = "metadata"; + public static final String HIERARCHY = "hierarchy"; + public static final String FILE_DATA = "fileData"; + public static final String FRAMEWORK_METADATA = "frameworkCategories"; + public static final String TEXTBOOK_TOC_ALLOWED_MIMETYPE = + "application/vnd.ekstep.content-collection"; + public static final String TEXTBOOK_TOC_ALLOWED_CONTNET_TYPES = + "textbook_toc_allowed_content_types"; + public static final String TEXTBOOK_TOC_MAX_CSV_ROWS = "textbook_toc_max_csv_rows"; + public static final String TEXTBOOK_TOC_INPUT_MAPPING = "textbook_toc_input_mapping"; + public static final String NODES_MODIFIED = "nodesModified"; + public static final String TEXT_TOC_FILE_SUPPRESS_COLUMN_NAMES = + "textbook_toc_file_suppress_column_names"; + public static final String TEXTBOOK_TOC_MANDATORY_FIELDS = "textbook_toc_mandatory_fields"; + public static final String DOWNLOAD = "download"; + public static final String COLLECTION_MIME_TYPE = "application/vnd.ekstep.content-collection"; + public static final String TB_ROOT = "root"; + public static final String TB_IS_NEW = "isNew"; + public static final String KEYWORDS = "keywords"; + public static final String UNIT = "Unit"; + public static final String UPDATE_HIERARCHY_API = "sunbird_update_hierarchy_api"; + public static final String TB_MESSAGES = "messages"; + public static final String TNC_ACCEPTED_ON = "tncAcceptedOn"; + public static final String TNC_ACCEPTED_VERSION = "tncAcceptedVersion"; + public static final String TNC_LATEST_VERSION_URL = "tncLatestVersionUrl"; + public static final String PROMPT_TNC = "promptTnC"; + public static final String TNC_LATEST_VERSION = "tncLatestVersion"; + public static final String BULK_ORG_UPLOAD = "bulkOrgUpload"; + public static final String FRAMEWORKS = "frameworks"; + public static final String LATEST_VERSION = "latestVersion"; + public static final String TNC_CONFIG = "tncConfig"; + public static final String TNC = "tnc"; + public static final String ACCEPT = "accept"; + public static final String ROOT_ORG_NAME = "rootOrgName"; + public static final String SUNBIRD_OTP_EXPIRATION = "sunbird_otp_expiration"; + public static final String SUNBIRD_OTP_LENGTH = "sunbird_otp_length"; + public static final String OTP_EXPIRATION_IN_MINUTES = "otpExpiryInMinutes"; + public static final String SUNBIRD_RATE_LIMIT_ENABLED = "sunbird_rate_limit_enabled"; + public static final String SUNBIRD_USER_MAX_ENCRYPTION_LIMIT = + "sunbird_user_max_encryption_limit"; + public static final String SUNBIRD_USER_MAX_PHONE_LENGTH = "sunbird_user_max_phone_length"; + public static final String RATE_LIMIT = "rate_limit"; + public static final String RATE_LIMIT_UNIT = "unit"; + public static final String RATE = "rate"; + public static final String INSTALLATION_NAME = "installationName"; + public static final String LOCATION_CODES = "locationCodes"; + public static final String BATCH_DETAILS = "batchDetails"; + public static final String USER_LOCATIONS = "userLocations"; + public static final String DIAL_CODES = "dialcodes"; + public static final String DIAL_CODE_REQUIRED = "dialcodeRequired"; + public static final String NO = "No"; + public static final String YES = "Yes"; + public static final String QR_CODE_REQUIRED = "QR Code Required?"; + public static final String QR_CODE = "QR Code"; + public static final String RESERVED_DIAL_CODES = "reservedDialcodes"; + public static final String FRAMEWORK_READ_API_URL = "framework_read_api_url"; + public static final String DIAL_CODE_IDENTIFIER_MAP = "dialCodeIdentifierMap"; + public static final String LINK_DIAL_CODE_API = "sunbird_link_dial_code_api"; + public static final String LINKED_CONTENT = "linkedContent"; + public static final String MAX_ALLOWED_CONTENT_SIZE = "max_allowed_content_size"; + public static final String SUNBIRD_LINKED_CONTENT_BASE_URL = "sunbird_linked_content_base_url"; + public static final String LINKED_CONTENT_COLUMN_KEY = "Linked Content"; + + public static final String BATCHES = "batches"; + public static final String ENROLLED_ON = "enrolledOn"; + public static final String LAST_ACCESSED_ON = "lastAccessedOn"; + public static final String OTHER = "OTHER"; + public static final String TEACHER = "TEACHER"; + public static final String USER_EXTERNAL_ID = "userExternalId"; + public static final String USER_ID_TYPE = "userIdType"; + public static final String USER_PROVIDER = "userProvider"; + public static final String SORTBY = "sortBy"; + public static final String SORT_ORDER = "sortOrder"; + public static final String NUMERIC = "NUMERIC"; + public static final String ASC = "asc"; + public static final String TERM = "term"; + public static final String DESC = "desc"; + public static final String SUNBIRD_TOC_LINKED_CONTENT_COLUMN_NAME = + "sunbird_toc_linked_content_column_name"; + public static final String SUNBIRD_TOC_MAX_FIRST_LEVEL_UNITS = + "sunbird_toc_max_first_level_units"; + public static final String TEXTBOOK_TOC_OUTPUT_MAPPING = "textbook_toc_output_mapping"; + public static final String TEXTBOOK_UNIT = "TextBookUnit"; + public static final String USER_NAME_HEADER = "User Name"; + public static final String ORG_NAME_HEADER = "Org Name"; + public static final String SCHOOL_NAME_HEADER = "School Name"; + public static final String COURSE_ENROLL_DATE_HEADER = "Enrollment Date"; + public static final String PROGRESS_HEADER = "Progress"; + public static final String SUNBIRD_CONTENT_SEARCH_URL = "sunbird_content_search_url"; + public static final String DATE_TIME_HEADER = "Date time stamp"; + public static final String PHONE_HEADER = "Mobile Number"; + public static final String EMAIL_HEADER = "Email Id"; + public static final String COURSE_PROGRESS_MAIL_TEMPLATE = "courseProgressMailTemplate"; + public static final String SUNBIRD_TIMEZONE = "sunbird_time_zone"; + public static final String COURSE_STAT_MAIL_DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + public static final String DATA_SOURCE = "dataSource"; + public static final String SUNBIRD_DIALCODE_SEARCH_API = "sunbird_dialcode_search_api"; + public static final String FROM_BEGINING = "fromBegining"; + public static final String SUNBIRD_KEYCLOAK_USER_FEDERATION_PROVIDER_ID = + "sunbird_keycloak_user_federation_provider_id"; + public static final String DEVICE_ID = "did"; + public static final String SUNBIRD_GZIP_FILTER_ENABLED = "sunbird_gzip_filter_enabled"; + public static final String COMPLETED_PERCENT = "completedPercent"; + public static final String PARTICIPANT_COUNT = "participantCount"; + public static final String BOARD = "board"; + public static final String MEDIUM = "medium"; + public static final String SUNBIRD_GZIP_ENABLE = "sunbird_gzip_enable"; + public static final String SHOW_DOWNLOAD_LINK = "showDownloadLink"; + public static final String SUNBIRD_SYNC_READ_WAIT_TIME = "sunbird_sync_read_wait_time"; + public static final String SUNBIRD_COURSE_METRICS_CONTANER = "sunbird_course_metrics_container"; + public static final String SUNBIRD_COURSE_METRICS_REPORT_FOLDER = + "sunbird_course_metrics_report_folder"; + public static final String SUNBIRD_ASSESSMENT_REPORT_FOLDER = "sunbird_assessment_report_folder"; + public static final String REPORT_UPDATED_ON = "reportUpdatedOn"; + public static final String SUNBIRD_GZIP_SIZE_THRESHOLD = "sunbird_gzip_size_threshold"; + public static final String ANALYTICS_ACCOUNT_NAME = "sunbird_analytics_blob_account_name"; + public static final String ANALYTICS_ACCOUNT_KEY = "sunbird_analytics_blob_account_key"; + public static final String PAGE_MANAGEMENT = "page_management"; + public static final String SUNBIRD_CACHE_ENABLE = "sunbird_cache_enable"; + public static final String MAP_NAME = "mapName"; + public static final String PAGE_ASSEMBLE = "pageAssemble"; + public static final String SIGNUP_TYPE = "signupType"; + public static final String REQUEST_SOURCE = "source"; + + public static final String SUNBIRD_REDIS_CONN_POOL_SIZE = "sunbird_redis_connection_pool_size"; + public static final String RECIPIENT_PHONES = "recipientPhones"; + public static final String TCP = "tcp"; + public static final String REST = "rest"; + public static final String SUNBIRD_AUDIT_EVENT_BATCH_ALLOWED = + "sunbird_audit_event_batch_allowed"; + public static final String ES_OR_OPERATION = "$or"; + public static final String PREV_USED_EMAIL = "prevUsedEmail"; + public static final String PREV_USED_PHONE = "prevUsedPhone"; + public static final String MERGE_USER = "Mergeuser"; + public static final String FROM_ACCOUNT_ID = "fromAccountId"; + public static final String TO_ACCOUNT_ID = "toAccountId"; + public static final String MERGEE_ID = "mergeeId"; + public static final String USER_MERGEE_ACCOUNT = "userMergeeAccount"; + public static final String SEARCH_FUZZY = "fuzzy"; + public static final String SUNBIRD_FUZZY_SEARCH_THRESHOLD = "sunbird_fuzzy_search_threshold"; + public static final String CERT_ID = "certId"; + public static final String ACCESS_CODE = "accessCode"; + public static final String USER_CERT = "user_cert"; + public static final String STORE = "store"; + public static final String JSON = "json"; + public static final String PDF = "pdf"; + public static final String JSON_DATA = "jsonData"; + public static final String PDF_URL = "pdfURL"; + public static final String CREATED_AT = "createdAt"; + public static final String UPDATED_AT = "updatedAt"; + public static final String SIGN_KEYS = "signKeys"; + public static final String ENC_KEYS = "encKeys"; + public static final String SUNBIRD_STATE_IMG_URL = "sunbird_state_img_url"; + public static final String SUNBIRD_DIKSHA_IMG_URL = "sunbird_diksha_img_url"; + public static final String SUNBIRD_CERT_COMPLETION_IMG_URL = "sunbird_cert_completion_img_url"; + public static final String stateImgUrl = "stateImgUrl"; + public static final String dikshaImgUrl = "dikshaImgUrl"; + public static final String certificateImgUrl = "certificateImgUrl"; + public static final String SUNBIRD_RESET_PASS_MAIL_SUBJECT = "sunbird_reset_pass_mail_subject"; + public static final String X_AUTHENTICATED_USER_TOKEN = "x-authenticated-user-token"; + public static final String X_SOURCE_USER_TOKEN = "x-source-user-token"; + public static final String SUNBIRD_SUBDOMAIN_KEYCLOAK_BASE_URL = + "sunbird_subdomain_keycloak_base_url"; + public static final String SUNBIRD_CERT_SERVICE_BASE_URL = "sunbird_cert_service_base_url"; + public static final String SUNBIRD_CERT_DOWNLOAD_URI = "sunbird_cert_download_uri"; + public static final String ACTION = "action"; + public static final String ITERATION = "iteration"; + public static final String TELEMETRY_TARGET_USER_MERGE_TYPE = "MergeUserCoursesAndCert"; + public static final String TELEMETRY_PRODUCER_USER_MERGE_ID = "org.sunbird.platform"; + public static final String TELEMETRY_EDATA_USER_MERGE_ACTION = "merge-user-courses-and-cert"; + public static final String BE_JOB_REQUEST = "BE_JOB_REQUEST"; + public static final String TELEMETRY_ACTOR_USER_MERGE_ID = "Merge User Courses and Cert"; + public static final String SUNBIRD_COURSE_DIALCODES_DB = "sunbird_course_dialcodes_db"; + public static final String SUNBIRD_ACCOUNT_MERGE_BODY = "sunbird_account_merge_body"; + public static final String CERTIFICATE = "Certificate"; + public static final String OLD_CERTIFICATE = "oldCertificate"; + public static final String MERGE_CERT = "Mergecert"; + public static final String RECOVERY_EMAIL = "recoveryEmail"; + public static final String RECOVERY_PHONE = "recoveryPhone"; + public static final String SUPPORTED_COlUMNS = "supportedColumns"; + public static final String INPUT_STATUS = "input status"; + public static final String EXTERNAL_USER_ID = "ext user id"; + public static final String EXTERNAL_ORG_ID = "ext org id"; + public static final String MIGRATION_USER_OBJECT = "MigrationUser"; + public static final String TASK_COUNT = "taskCount"; + public static final String ERROR_VISUALIZATION_THRESHOLD = + "sunbird_user_upload_error_visualization_threshold"; + public static final String NESTED_KEY_FILTER = "nestedFilters"; + public static final String SHADOW_USER = "shadow_user"; + public static final String USER_EXT_ID = "userExtId"; + public static final String ORG_EXT_ID = "orgExtId"; + public static final String STATE_VALIDATED = "stateValidated"; + public static final String FLAGS_VALUE = "flagsValue"; + public static final String USER_STATUS = "userStatus"; + public static final String CLAIM_STATUS = "claimStatus"; + public static final String CLAIMED_ON = "claimedOn"; + public static final String SUNBIRD_MIGRATE_USER_BODY = "sunbird_migrate_user_body"; + public static final String SMS = "sms"; + public static final String SUNBIRD_ACCOUNT_MERGE_SUBJECT = "sunbird_account_merge_subject"; + public static final String CONTEXT_TELEMETRY = "telemetryContext"; + public static final String OLD_ID = "oldId"; + public static final String MAX_ATTEMPT = "maxAttempt"; + public static final String REMAINING_ATTEMPT = "remainingAttempt"; + public static final String IS_SSO_ROOTORG_ENABLED = "isSSOEnabled"; + public static final String USER_FEED_DB = "user_feed"; + public static final String USER_FEED = "userFeed"; + public static final String FEED_DATA = "data"; + public static final String REJECT = "reject"; + public static final String FEED_ID = "feedId"; + public static final String LICENSE = "license"; + public static final String DEFAULT_LICENSE = "defaultLicense"; + public static final String SUNBIRD_PASS_REGEX = "sunbird_pass_regex"; + public static final String NESTED_EXISTS = "nested_exists"; + public static final String NESTED_NOT_EXISTS = "nested_not_exists"; + public static final String PROSPECT_CHANNELS = "prospectChannels"; + public static final String PROSPECT_CHANNELS_IDS = "prospectChannelsIds"; + public static final String CATEGORY = "category"; + public static final String TEMPLATE_ID = "templateId"; + public static final String TEMPLATE_ID_VALUE = "resetPasswordWithOtp"; + public static final String VERSION_3 = "v3"; + public static final String VERSION_4 = "v4"; + public static final String LEARNING_SERVICE_BASE_URL = "learning_service_base_url"; + public static final String CREATOR_DETAILS_FIELDS = "sunbird_user_search_cretordetails_fields"; + public static final String USER_SEARCH_BASE_URL = "sunbird_user_service_api_base_url"; + public static final String SUNBIRD_BATCH_CONTENT_TYPES = "sunbird_batch_content_types"; + public static final String WARD_LOGIN_OTP_TEMPLATE_ID = "wardLoginOTP"; + public static final String OTP_PHONE_WARD_LOGIN_TEMPLATE = "verifyPhoneOtpTemplateWard"; + public static final String OTP_EMAIL_WARD_LOGIN_TEMPLATE = "verifyEmailOtpTemplateWard"; + public static final String LIMIT_MANAGED_USER_CREATION = "limit_managed_user_creation"; + public static final String MANAGED_USER_LIMIT = "managed_user_limit"; + public static final String ACCESS_TOKEN_PUBLICKEY_BASEPATH = "accesstoken.publickey.basepath"; + public static final String ACCESS_TOKEN_PUBLICKEY_KEYPREFIX = "accesstoken.publickey.keyprefix"; + public static final String ACCESS_TOKEN_PUBLICKEY_KEYCOUNT = "accesstoken.publickey.keycount"; + public static final String SHA_256_WITH_RSA = "SHA256withRSA"; + public static final String SUB = "sub"; + public static final String DOT_SEPARATOR = "."; + public static final List USER_UNAUTH_STATES = + Arrays.asList(JsonKey.UNAUTHORIZED, JsonKey.ANONYMOUS); + public static final String EKSTEP_SIGNING_SIGN_PAYLOAD = "ekstep.signing.sign.payload"; + public static final String TS = "ts"; + public static final String EKSTEP_SIGNING_SIGN_PAYLOAD_VER = "ekstep.signing.sign.payload.ver"; + public static final String MSGID= "msgid"; + public static final String ADMINUTIL_BASE_URL = "adminutil_base_url"; + public static final String ADMINUTIL_SIGN_ENDPOINT = "adminutil_sign_endpoint"; + public static final String MANAGED_TOKEN = "managedToken"; + public static final String WITH_TOKENS = "withTokens"; + private JsonKey() {} +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/KeyCloakConnectionProvider.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/KeyCloakConnectionProvider.java new file mode 100644 index 0000000000..d88daae121 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/KeyCloakConnectionProvider.java @@ -0,0 +1,155 @@ +/** */ +package org.sunbird.common.models.util; + +import org.apache.commons.lang3.StringUtils; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.KeycloakBuilder; + +/** + * @author Manzarul This class will connect to key cloak server and provide the connection to do + * other operations. + */ +public class KeyCloakConnectionProvider { + + private static Keycloak keycloak; + private static PropertiesCache cache = PropertiesCache.getInstance(); + public static String SSO_URL = null; + public static String SSO_REALM = null; + public static String CLIENT_ID = null; + + static { + try { + initialiseConnection(); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + registerShutDownHook(); + } + + /** + * Method to initializate the Keycloak connection + * + * @return Keycloak connection + */ + public static Keycloak initialiseConnection() throws Exception { + ProjectLogger.log("key cloak instance is creation started."); + keycloak = initialiseEnvConnection(); + if (keycloak != null) { + return keycloak; + } + KeycloakBuilder keycloakBuilder = + KeycloakBuilder.builder() + .serverUrl(cache.getProperty(JsonKey.SSO_URL)) + .realm(cache.getProperty(JsonKey.SSO_REALM)) + .username(cache.getProperty(JsonKey.SSO_USERNAME)) + .password(cache.getProperty(JsonKey.SSO_PASSWORD)) + .clientId(cache.getProperty(JsonKey.SSO_CLIENT_ID)) + .resteasyClient( + new ResteasyClientBuilder() + .connectionPoolSize(Integer.parseInt(cache.getProperty(JsonKey.SSO_POOL_SIZE))) + .build()); + if (cache.getProperty(JsonKey.SSO_CLIENT_SECRET) != null + && !(cache.getProperty(JsonKey.SSO_CLIENT_SECRET).equals(JsonKey.SSO_CLIENT_SECRET))) { + keycloakBuilder.clientSecret(cache.getProperty(JsonKey.SSO_CLIENT_SECRET)); + } + SSO_URL = cache.getProperty(JsonKey.SSO_URL); + SSO_REALM = cache.getProperty(JsonKey.SSO_REALM); + CLIENT_ID = cache.getProperty(JsonKey.SSO_CLIENT_ID); + keycloak = keycloakBuilder.build(); + + ProjectLogger.log("key cloak instance is created successfully."); + return keycloak; + } + + /** + * This method will provide the keycloak connection from environment variable. if environment + * variable is not set then it will return null. + * + * @return Keycloak + */ + private static Keycloak initialiseEnvConnection() throws Exception { + String url = System.getenv(JsonKey.SUNBIRD_SSO_URL); + String username = System.getenv(JsonKey.SUNBIRD_SSO_USERNAME); + String password = System.getenv(JsonKey.SUNBIRD_SSO_PASSWORD); + String cleintId = System.getenv(JsonKey.SUNBIRD_SSO_CLIENT_ID); + String clientSecret = System.getenv(JsonKey.SUNBIRD_SSO_CLIENT_SECRET); + String relam = System.getenv(JsonKey.SUNBIRD_SSO_RELAM); + if (StringUtils.isBlank(url) + || StringUtils.isBlank(username) + || StringUtils.isBlank(password) + || StringUtils.isBlank(cleintId) + || StringUtils.isBlank(relam)) { + ProjectLogger.log( + "key cloak connection is not provided by Environment variable.", LoggerEnum.INFO.name()); + return null; + } + SSO_URL = url; + ProjectLogger.log("SSO url is==" + SSO_URL, LoggerEnum.INFO.name()); + SSO_REALM = relam; + CLIENT_ID = cleintId; + KeycloakBuilder keycloakBuilder = + KeycloakBuilder.builder() + .serverUrl(url) + .realm(relam) + .username(username) + .password(password) + .clientId(cleintId) + .resteasyClient( + new ResteasyClientBuilder() + .connectionPoolSize(Integer.parseInt(cache.getProperty(JsonKey.SSO_POOL_SIZE))) + .build()); + + if (StringUtils.isNotBlank(clientSecret)) { + keycloakBuilder.clientSecret(clientSecret); + ProjectLogger.log( + "KeyCloakConnectionProvider:initialiseEnvConnection client sceret is provided.", + LoggerEnum.INFO.name()); + } + keycloakBuilder.grantType("client_credentials"); + keycloak = keycloakBuilder.build(); + ProjectLogger.log( + "key cloak instance is created from Environment variable settings .", + LoggerEnum.INFO.name()); + return keycloak; + } + + /** + * This method will provide key cloak connection instance. + * + * @return Keycloak + */ + public static Keycloak getConnection() { + if (keycloak != null) { + return keycloak; + } else { + try { + return initialiseConnection(); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + return null; + } + + /** + * This class will be called by registerShutDownHook to register the call inside jvm , when jvm + * terminate it will call the run method to clean up the resource. + * + * @author Manzarul + */ + static class ResourceCleanUp extends Thread { + public void run() { + ProjectLogger.log("started resource cleanup."); + keycloak.close(); + ProjectLogger.log("completed resource cleanup."); + } + } + + /** Register the hook for resource clean up. this will be called when jvm shut down. */ + public static void registerShutDownHook() { + Runtime runtime = Runtime.getRuntime(); + runtime.addShutdownHook(new ResourceCleanUp()); + ProjectLogger.log("ShutDownHook registered."); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LearnerServiceUrls.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LearnerServiceUrls.java new file mode 100644 index 0000000000..09d5720be7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LearnerServiceUrls.java @@ -0,0 +1,52 @@ +package org.sunbird.common.models.util; + +import java.util.HashMap; +import java.util.Map; + +public class LearnerServiceUrls { + public static final String BASE_URL = "sunbird_learner_service_url"; + + public static final String PREFIX_ORG_SERVICE = "/api/org"; + + public enum Path { + API_GW_PATH_READ_ORG("/v1/read"), + LOCAL_PATH_READ_ORG("/v1/org/read"); + + private final String text; + + Path(final String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + } + + public static String getRequestUrl(String baseUrl, String prefix, Path path) { + String pathEnumName = path.name(); + + if (baseUrl.contains("localhost") || baseUrl.contains("127.0.0.1")) { + prefix = ""; + pathEnumName = pathEnumName.replace("API_GW", "LOCAL"); + } + return String.format("%s%s%s", baseUrl, prefix, Path.valueOf(pathEnumName)); + } + + public static Map getRequestHeaders(Map inputMap) { + Map outputMap = new HashMap<>(); + + for (Map.Entry entry : inputMap.entrySet()) { + if (entry.getKey().toLowerCase().startsWith("x-") + || entry.getKey().equalsIgnoreCase("Authorization")) { + if (entry.getValue() != null) { + outputMap.put(entry.getKey(), entry.getValue()[0]); + } + } + } + + outputMap.put("Content-Type", "application/json"); + return outputMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LocationActorOperation.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LocationActorOperation.java new file mode 100644 index 0000000000..224c89482f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LocationActorOperation.java @@ -0,0 +1,22 @@ +package org.sunbird.common.models.util; + +public enum LocationActorOperation { + CREATE_LOCATION("createLocation"), + UPDATE_LOCATION("updateLocation"), + SEARCH_LOCATION("searchLocation"), + DELETE_LOCATION("deleteLocation"), + GET_RELATED_LOCATION_IDS("getRelatedLocationIds"), + READ_LOCATION_TYPE("readLocationType"), + UPSERT_LOCATION_TO_ES("upsertLocationDataToES"), + DELETE_LOCATION_FROM_ES("deleteLocationDataFromES"); + + private String value; + + LocationActorOperation(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LogEvent.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LogEvent.java new file mode 100644 index 0000000000..9c509ee3f5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LogEvent.java @@ -0,0 +1,104 @@ +package org.sunbird.common.models.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class will log the api request , response , and error message insdie log file .in predefine + * structure. + * + * @author Manzarul + */ +public class LogEvent { + + private String eid; + private long ets; + private String mid; + private String ver; + private Map context; + private Map edata; + + public String getEid() { + return eid; + } + + public void setEid(String eid) { + this.eid = eid; + } + + public long getEts() { + return ets; + } + + public void setEts(long ets) { + this.ets = ets; + } + + public String getMid() { + return mid; + } + + public void setMid(String mid) { + this.mid = mid; + } + + public String getVer() { + return ver; + } + + public void setVer(String ver) { + this.ver = ver; + } + + public Map getContext() { + return context; + } + + public void setContext(Map context) { + this.context = context; + } + + public Map getEdata() { + return edata; + } + + public void setEdata(Map eks) { + this.edata = new HashMap(); + edata.put(JsonKey.EKS, eks); + } + + public void setContext(String id, String ver) { + this.context = new HashMap(); + Map pdata = new HashMap(); + pdata.put(JsonKey.ID, id); + pdata.put(JsonKey.VER, ver); + this.context.put(JsonKey.PDATA, pdata); + } + + /** + * Set the error data with this method + * + * @param level String + * @param className String + * @param method String + * @param data Object + * @param stackTrace Object + * @param exception Object + */ + public void setEdata( + String level, + String className, + String method, + Object data, + Object stackTrace, + Object exception) { + this.edata = new HashMap(); + Map eks = new HashMap(); + eks.put(JsonKey.LEVEL, level); + eks.put(JsonKey.CLASS, className); + eks.put(JsonKey.METHOD, method); + eks.put(JsonKey.DATA, data); + eks.put(JsonKey.STACKTRACE, stackTrace); + edata.put(JsonKey.EKS, eks); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LoggerEnum.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LoggerEnum.java new file mode 100644 index 0000000000..fc78efae5e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/LoggerEnum.java @@ -0,0 +1,11 @@ +package org.sunbird.common.models.util; + +/** @author Manzarul */ +public enum LoggerEnum { + INFO, + WARN, + DEBUG, + ERROR, + BE_LOG, + PERF_LOG; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/MapperUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/MapperUtil.java new file mode 100644 index 0000000000..20797eb7b3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/MapperUtil.java @@ -0,0 +1,23 @@ +package org.sunbird.common.models.util; + +import java.util.Map; + +public class MapperUtil { + public static void put( + Map inMap, String inKey, Map outMap, String outKey) { + String[] inputKeys = inKey.split("\\."); + String lastKey = inputKeys[inputKeys.length - 1]; + + Map map = inMap; + + for (int i = 0; i < (inputKeys.length - 1); i++) { + if (map.containsKey(inputKeys[i])) { + map = (Map) inMap.get(inputKeys[i]); + } + } + + if (map.containsKey(lastKey)) { + outMap.put(outKey, map.get(lastKey)); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/PhoneValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/PhoneValidator.java new file mode 100644 index 0000000000..bfc87a107e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/PhoneValidator.java @@ -0,0 +1,90 @@ +package org.sunbird.common.models.util; + +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.Phonenumber; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * This class will provide helper method to validate phone number and its country code. + * + * @author Amit Kumar + */ +public class PhoneValidator { + + private static final int ERROR_CODE = ResponseCode.CLIENT_ERROR.getResponseCode(); + + private PhoneValidator() {} + + public static boolean validatePhoneNumber(String phone, String countryCode) { + if (phone.contains("+")) { + throw new ProjectCommonException( + ResponseCode.invalidPhoneNumber.getErrorCode(), + ResponseCode.invalidPhoneNumber.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isNotBlank(countryCode)) { + boolean isCountryCodeValid = validateCountryCode(countryCode); + if (!isCountryCodeValid) { + throw new ProjectCommonException( + ResponseCode.invalidCountryCode.getErrorCode(), + ResponseCode.invalidCountryCode.getErrorMessage(), + ERROR_CODE); + } + } + if (validatePhone(phone, countryCode)) { + return true; + } else { + throw new ProjectCommonException( + ResponseCode.phoneNoFormatError.getErrorCode(), + ResponseCode.phoneNoFormatError.getErrorMessage(), + ERROR_CODE); + } + } + + public static boolean validateCountryCode(String countryCode) { + String countryCodePattern = "^(?:[+] ?){0,1}(?:[0-9] ?){1,3}"; + try { + Pattern pattern = Pattern.compile(countryCodePattern); + Matcher matcher = pattern.matcher(countryCode); + return matcher.matches(); + } catch (Exception e) { + return false; + } + } + + public static boolean validatePhone(String phone, String countryCode) { + PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + String code = countryCode; + if (StringUtils.isNotBlank(countryCode) && (countryCode.charAt(0) != '+')) { + code = "+" + countryCode; + } + Phonenumber.PhoneNumber phoneNumber = null; + try { + if (StringUtils.isBlank(countryCode)) { + code = PropertiesCache.getInstance().getProperty("sunbird_default_country_code"); + } + String isoCode = phoneNumberUtil.getRegionCodeForCountryCode(Integer.parseInt(code)); + phoneNumber = phoneNumberUtil.parse(phone, isoCode); + return phoneNumberUtil.isValidNumber(phoneNumber); + } catch (NumberParseException e) { + ProjectLogger.log( + "PhoneValidator:validatePhone: Exception occurred while validating phone number = ", e); + } + return false; + } + + public static boolean validatePhoneNumber(String phoneNumber) { + if (StringUtils.isBlank(phoneNumber)) { + return false; + } + String phonePattern = "([+]?(91)?[-]?[0-9]{10}$)"; + Pattern pattern = Pattern.compile(phonePattern); + Matcher matcher = pattern.matcher(phoneNumber); + return matcher.matches(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ProjectLogger.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ProjectLogger.java new file mode 100644 index 0000000000..370f38286e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ProjectLogger.java @@ -0,0 +1,192 @@ +/** */ +package org.sunbird.common.models.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.telemetry.util.TelemetryEvents; + +/** + * This class will used to log the project message in any level. + * + * @author Manzarul + */ +public class ProjectLogger { + + private static String eVersion = "1.0"; + private static String pVersion = "1.0"; + private static String dataId = "Sunbird"; + private static ObjectMapper mapper = new ObjectMapper(); + private static Logger rootLogger = (Logger) LogManager.getLogger("defaultLogger"); + // private static TelemetryLmaxWriter lmaxWriter = TelemetryLmaxWriter.getInstance(); + + /** To log only message. */ + public static void log(String message) { + log(message, null, LoggerEnum.DEBUG.name()); + } + + public static void log(String message, Throwable e) { + log(message, null, e); + } + + public static void log(String message, Throwable e, Map telemetryInfo) { + log(message, null, e); + telemetryProcess(telemetryInfo, e); + } + + private static void telemetryProcess(Map telemetryInfo, Throwable e) { + + ProjectCommonException projectCommonException = null; + if (e instanceof ProjectCommonException) { + projectCommonException = (ProjectCommonException) e; + } else { + projectCommonException = + new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + ResponseCode.internalError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + Request request = new Request(); + telemetryInfo.put(JsonKey.TELEMETRY_EVENT_TYPE, TelemetryEvents.ERROR.getName()); + + Map params = (Map) telemetryInfo.get(JsonKey.PARAMS); + params.put(JsonKey.ERROR, projectCommonException.getCode()); + params.put(JsonKey.STACKTRACE, generateStackTrace(e.getStackTrace())); + request.setRequest(telemetryInfo); + // lmaxWriter.submitMessage(request); + + } + + private static String generateStackTrace(StackTraceElement[] elements) { + StringBuilder builder = new StringBuilder(""); + for (StackTraceElement element : elements) { + builder.append(element.toString()); + } + return builder.toString(); + } + + public static void log(String message, String logLevel) { + log(message, null, logLevel); + } + + /** To log message, data in used defined log level. */ + public static void log(String message, LoggerEnum logEnum) { + info(message, null, logEnum); + } + + /** To log message, data in used defined log level. */ + public static void log(String message, Object data, String logLevel) { + backendLog(message, data, null, logLevel); + } + + /** To log exception with message and data. */ + public static void log(String message, Object data, Throwable e) { + backendLog(message, data, e, LoggerEnum.ERROR.name()); + } + + /** To log exception with message and data for user specific log level. */ + public static void log(String message, Object data, Throwable e, String logLevel) { + backendLog(message, data, e, logLevel); + } + + private static void info(String message, Object data) { + rootLogger.info(getBELogEvent(LoggerEnum.INFO.name(), message, data)); + } + + private static void info(String message, Object data, LoggerEnum loggerEnum) { + rootLogger.info(getBELogEvent(LoggerEnum.INFO.name(), message, data, loggerEnum)); + } + + private static void debug(String message, Object data) { + rootLogger.debug(getBELogEvent(LoggerEnum.DEBUG.name(), message, data)); + } + + private static void error(String message, Object data, Throwable exception) { + rootLogger.error(getBELogEvent(LoggerEnum.ERROR.name(), message, data, exception)); + } + + private static void warn(String message, Object data, Throwable exception) { + rootLogger.warn(getBELogEvent(LoggerEnum.WARN.name(), message, data, exception)); + } + + private static void backendLog(String message, Object data, Throwable e, String logLevel) { + if (!StringUtils.isBlank(logLevel)) { + + switch (logLevel) { + case "INFO": + info(message, data); + break; + case "DEBUG": + debug(message, data); + break; + case "WARN": + warn(message, data, e); + break; + case "ERROR": + error(message, data, e); + break; + default: + debug(message, data); + break; + } + } + } + + private static String getBELogEvent( + String logLevel, String message, Object data, LoggerEnum logEnum) { + String logData = getBELog(logLevel, message, data, null, logEnum); + return logData; + } + + private static String getBELogEvent(String logLevel, String message, Object data) { + String logData = getBELog(logLevel, message, data, null, null); + return logData; + } + + private static String getBELogEvent(String logLevel, String message, Object data, Throwable e) { + String logData = getBELog(logLevel, message, data, e, null); + return logData; + } + + private static String getBELog( + String logLevel, String message, Object data, Throwable exception, LoggerEnum logEnum) { + String mid = dataId + "." + System.currentTimeMillis() + "." + UUID.randomUUID(); + long unixTime = System.currentTimeMillis(); + LogEvent te = new LogEvent(); + Map eks = new HashMap(); + eks.put(JsonKey.LEVEL, logLevel); + eks.put(JsonKey.MESSAGE, message); + + if (null != data) { + eks.put(JsonKey.DATA, data); + } + if (null != exception) { + eks.put(JsonKey.STACKTRACE, ExceptionUtils.getStackTrace(exception)); + } + if (logEnum != null) { + te.setEid(logEnum.name()); + } else { + te.setEid(LoggerEnum.BE_LOG.name()); + } + te.setEts(unixTime); + te.setMid(mid); + te.setVer(eVersion); + te.setContext(dataId, pVersion); + String jsonMessage = null; + try { + te.setEdata(eks); + jsonMessage = mapper.writeValueAsString(te); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return jsonMessage; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ProjectUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ProjectUtil.java new file mode 100644 index 0000000000..5cf67131eb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/ProjectUtil.java @@ -0,0 +1,1039 @@ +package org.sunbird.common.models.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.Phonenumber; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.validator.UrlValidator; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * This class will contains all the common utility methods. + * + * @author Manzarul + */ +public class ProjectUtil { + + /** format the date in YYYY-MM-DD hh:mm:ss:SSZ */ + private static AtomicInteger atomicInteger = new AtomicInteger(); + + public static Integer DEFAULT_BATCH_SIZE = 10; + public static final long BACKGROUND_ACTOR_WAIT_TIME = 30; + public static final String ELASTIC_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + public static final String YEAR_MONTH_DATE_FORMAT = "yyyy-MM-dd"; + private static final int randomPasswordLength = 9; + + protected static final String FILE_NAME[] = { + "cassandratablecolumn.properties", + "elasticsearch.config.properties", + "cassandra.config.properties", + "dbconfig.properties", + "externalresource.properties", + "sso.properties", + "userencryption.properties", + "profilecompleteness.properties", + "mailTemplates.properties" + }; + public static PropertiesCache propertiesCache; + private static Pattern pattern; + private static final String EMAIL_PATTERN = + "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; + public static final String[] excludes = + new String[] { + JsonKey.COMPLETENESS, + JsonKey.MISSING_FIELDS, + JsonKey.PROFILE_VISIBILITY, + JsonKey.LOGIN_ID, + JsonKey.USER_ID + }; + + public static final String[] defaultPrivateFields = new String[] {JsonKey.EMAIL, JsonKey.PHONE}; + private static final String INDEX_NAME = "telemetry.raw"; + private static String YYYY_MM_DD_FORMATTER = "yyyy-MM-dd"; + private static final String STARTDATE = "startDate"; + private static final String ENDDATE = "endDate"; + private static ObjectMapper mapper = new ObjectMapper(); + + static { + pattern = Pattern.compile(EMAIL_PATTERN); + propertiesCache = PropertiesCache.getInstance(); + } + + /** @author Manzarul */ + public enum Environment { + dev(1), + qa(2), + prod(3); + int value; + + private Environment(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** @author Amit Kumar */ + public enum Status { + ACTIVE(1), + INACTIVE(0); + + private int value; + + Status(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + } + + public enum BulkProcessStatus { + NEW(0), + IN_PROGRESS(1), + INTERRUPT(2), + COMPLETED(3), + FAILED(9); + + private int value; + + BulkProcessStatus(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + } + + public enum OrgStatus { + INACTIVE(0), + ACTIVE(1), + BLOCKED(2), + RETIRED(3); + + private Integer value; + + OrgStatus(Integer value) { + this.value = value; + } + + public Integer getValue() { + return this.value; + } + } + + /** @author Amit Kumar */ + public enum ProgressStatus { + NOT_STARTED(0), + STARTED(1), + COMPLETED(2); + + private int value; + + ProgressStatus(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + } + + /** @author Amit Kumar */ + public enum ActiveStatus { + ACTIVE(true), + INACTIVE(false); + + private boolean value; + + ActiveStatus(boolean value) { + this.value = value; + } + + public boolean getValue() { + return this.value; + } + } + + public enum Action { + YES(1), + NO(0); + + private int value; + + Action(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** @author Amit Kumar */ + public enum CourseMgmtStatus { + DRAFT("draft"), + LIVE("live"), + RETIRED("retired"); + + private String value; + + CourseMgmtStatus(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + } + + /** @author Amit Kumar */ + public enum Source { + WEB("web"), + ANDROID("android"), + IOS("ios"), + APP("app"); + + private String value; + + Source(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + } + + /** @author Amit Kumar */ + public enum UserRole { + PUBLIC("PUBLIC"), + CONTENT_CREATOR("CONTENT_CREATOR"), + CONTENT_REVIEWER("CONTENT_REVIEWER"), + ORG_ADMIN("ORG_ADMIN"), + ORG_MEMBER("ORG_MEMBER"); + + private String value; + + UserRole(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + } + + /** + * This method will check incoming value is null or empty it will do empty check by doing trim + * method. in case of null or empty it will return true else false. + * + * @param value + * @return + */ + public static boolean isStringNullOREmpty(String value) { + return (value == null || "".equals(value.trim())); + } + + /** + * This method will provide formatted date + * + * @return + */ + public static String getFormattedDate() { + return getDateFormatter().format(new Date()); + } + + /** + * This method will provide formatted date + * + * @return + */ + public static String formatDate(Date date) { + if (null != date) return getDateFormatter().format(date); + else return null; + } + /** + * Validate email with regular expression + * + * @param email + * @return true valid email, false invalid email + */ + public static boolean isEmailvalid(final String email) { + if (StringUtils.isBlank(email)) { + return false; + } + Matcher matcher = pattern.matcher(email); + return matcher.matches(); + } + + /** + * This method will generate auth token based on name , source and timestamp + * + * @param name String + * @param source String + * @return String + */ + public static String createAuthToken(String name, String source) { + String data = name + source + System.currentTimeMillis(); + UUID authId = UUID.nameUUIDFromBytes(data.getBytes(StandardCharsets.UTF_8)); + return authId.toString(); + } + + /** + * This method will generate unique id based on current time stamp and some random value mixed up. + * + * @param environmentId int + * @return String + */ + public static String getUniqueIdFromTimestamp(int environmentId) { + Random random = new Random(); + long env = (environmentId + random.nextInt(99999)) / 10000000; + long uid = System.currentTimeMillis() + random.nextInt(999999); + uid = uid << 13; + return env + "" + uid + "" + atomicInteger.getAndIncrement(); + } + + /** + * This method will generate the unique id . + * + * @return + */ + public static synchronized String generateUniqueId() { + return UUID.randomUUID().toString(); + } + + public enum Method { + GET, + POST, + PUT, + DELETE, + PATCH + } + + /** + * Enum to hold the index name for Elastic search. + * + * @author Manzarul + */ + public enum EsIndex { + sunbird("searchindex"), + sunbirdPlugin("sunbirdplugin"), + courseBatchStats("cbatchstats"); + private String indexName; + + private EsIndex(String name) { + this.indexName = name; + } + + public String getIndexName() { + return indexName; + } + } + + /** + * This enum will hold all the ES type name. + * + * @author Manzarul + */ + public enum EsType { + course("cbatch"), + courseBatch("course-batch"), + content("content"), + badgeassociations("badgeassociations"), + user("user"), + organisation("org"), + usercourses("user-courses"), + usernotes("usernotes"), + userprofilevisibility("userprofilevisibility"), + telemetry("telemetry"), + location("location"), + announcementType("announcementtype"), + announcement("announcement"), + metrics("metrics"), + cbatchstats("cbatchstats"), + cbatchassessment("cbatch-assessment"), + userfeed("userfeed"); + + private String typeName; + + private EsType(String name) { + this.typeName = name; + } + + public String getTypeName() { + return typeName; + } + } + + public enum SectionDataType { + course("course"), + content("content"); + private String typeName; + + private SectionDataType(String name) { + this.typeName = name; + } + + public String getTypeName() { + return typeName; + } + } + + public enum AddressType { + permanent("permanent"), + current("current"), + office("office"), + home("home"); + private String typeName; + + private AddressType(String name) { + this.typeName = name; + } + + public String getTypeName() { + return typeName; + } + } + + public enum AssessmentResult { + gradeA("A", "Pass"), + gradeB("B", "Pass"), + gradeC("C", "Pass"), + gradeD("D", "Pass"), + gradeE("E", "Pass"), + gradeF("F", "Fail"); + private String grade; + private String result; + + private AssessmentResult(String grade, String result) { + this.grade = grade; + this.result = result; + } + + public String getGrade() { + return grade; + } + + public String getResult() { + return result; + } + } + + /** + * This method will calculate the percentage + * + * @param score double + * @param maxScore double + * @return double + */ + public static double calculatePercentage(double score, double maxScore) { + double percentage = (score * 100) / (maxScore * 1.0); + return Math.round(percentage); + } + + /** + * This method will calculate grade based on percentage marks. + * + * @param percentage double + * @return AssessmentResult + */ + public static AssessmentResult calcualteAssessmentResult(double percentage) { + switch (Math.round(Float.valueOf(String.valueOf(percentage))) / 10) { + case 10: + return AssessmentResult.gradeA; + case 9: + return AssessmentResult.gradeA; + case 8: + return AssessmentResult.gradeB; + case 7: + return AssessmentResult.gradeC; + case 6: + return AssessmentResult.gradeD; + case 5: + return AssessmentResult.gradeE; + default: + return AssessmentResult.gradeF; + } + } + + public static boolean isNull(Object obj) { + return null == obj ? true : false; + } + + public static boolean isNotNull(Object obj) { + return null != obj ? true : false; + } + + public static String formatMessage(String exceptionMsg, Object... fieldValue) { + return MessageFormat.format(exceptionMsg, fieldValue); + } + + public static SimpleDateFormat getDateFormatter() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSZ"); + simpleDateFormat.setLenient(false); + return simpleDateFormat; + } + + /** @author Manzarul */ + public enum EnrolmentType { + open("open"), + inviteOnly("invite-only"); + private String val; + + EnrolmentType(String val) { + this.val = val; + } + + public String getVal() { + return val; + } + } + + /** @author Manzarul */ + public enum AzureContainer { + userProfileImg("userprofileimg"), + orgImage("orgimg"); + private String name; + + private AzureContainer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + public static VelocityContext getContext(Map map) { + propertiesCache = PropertiesCache.getInstance(); + VelocityContext context = new VelocityContext(); + if (StringUtils.isNotBlank((String) map.get(JsonKey.ACTION_URL))) { + context.put(JsonKey.ACTION_URL, getValue(map, JsonKey.ACTION_URL)); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.NAME))) { + context.put(JsonKey.NAME, getValue(map, JsonKey.NAME)); + } + context.put(JsonKey.BODY, getValue(map, JsonKey.BODY)); + String fromEmail = getFromEmail(map); + if (StringUtils.isNotBlank(fromEmail)) { + context.put(JsonKey.FROM_EMAIL, fromEmail); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.ORG_NAME))) { + context.put(JsonKey.ORG_NAME, getValue(map, JsonKey.ORG_NAME)); + } + String logoUrl = getSunbirdLogoUrl(map); + if (StringUtils.isNotBlank(logoUrl)) { + context.put(JsonKey.ORG_IMAGE_URL, logoUrl); + } + context.put(JsonKey.ACTION_NAME, getValue(map, JsonKey.ACTION_NAME)); + context.put(JsonKey.USERNAME, getValue(map, JsonKey.USERNAME)); + context.put(JsonKey.TEMPORARY_PASSWORD, getValue(map, JsonKey.TEMPORARY_PASSWORD)); + + if (StringUtils.isNotBlank((String) map.get(JsonKey.COURSE_NAME))) { + context.put(JsonKey.COURSE_NAME, map.remove(JsonKey.COURSE_NAME)); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.START_DATE))) { + context.put(JsonKey.BATCH_START_DATE, map.remove(JsonKey.START_DATE)); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.END_DATE))) { + context.put(JsonKey.BATCH_END_DATE, map.remove(JsonKey.END_DATE)); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.BATCH_NAME))) { + context.put(JsonKey.BATCH_NAME, map.remove(JsonKey.BATCH_NAME)); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.FIRST_NAME))) { + context.put(JsonKey.NAME, map.remove(JsonKey.FIRST_NAME)); + } else { + context.put(JsonKey.NAME, ""); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.SIGNATURE))) { + context.put(JsonKey.SIGNATURE, map.remove(JsonKey.SIGNATURE)); + } + if (StringUtils.isNotBlank((String) map.get(JsonKey.COURSE_BATCH_URL))) { + context.put(JsonKey.COURSE_BATCH_URL, map.remove(JsonKey.COURSE_BATCH_URL)); + } + context.put(JsonKey.ALLOWED_LOGIN, propertiesCache.getProperty(JsonKey.SUNBIRD_ALLOWED_LOGIN)); + map = addCertStaticResource(map); + for (Map.Entry entry : map.entrySet()) { + context.put(entry.getKey(), entry.getValue()); + } + return context; + } + + private static String getSunbirdLogoUrl(Map map) { + String logoUrl = (String) getValue(map, JsonKey.ORG_IMAGE_URL); + if (StringUtils.isBlank(logoUrl)) { + logoUrl = getConfigValue(JsonKey.SUNBIRD_ENV_LOGO_URL); + } + ProjectLogger.log("ProjectUtil:getSunbirdLogoUrl: url = " + logoUrl, LoggerEnum.INFO.name()); + return logoUrl; + } + + private static Map addCertStaticResource(Map map) { + map.putIfAbsent( + JsonKey.certificateImgUrl, + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_CERT_COMPLETION_IMG_URL)); + map.putIfAbsent( + JsonKey.dikshaImgUrl, ProjectUtil.getConfigValue(JsonKey.SUNBIRD_DIKSHA_IMG_URL)); + map.putIfAbsent(JsonKey.stateImgUrl, ProjectUtil.getConfigValue(JsonKey.SUNBIRD_STATE_IMG_URL)); + return map; + } + + private static String getFromEmail(Map map) { + String fromEmail = (String) getValue(map, JsonKey.EMAIL_SERVER_FROM); + if (StringUtils.isBlank(fromEmail)) { + fromEmail = getConfigValue(JsonKey.EMAIL_SERVER_FROM); + } + ProjectLogger.log("ProjectUtil:getFromEmail: fromEmail = " + fromEmail, LoggerEnum.INFO.name()); + return fromEmail; + } + + private static Object getValue(Map map, String key) { + Object value = map.get(key); + map.remove(key); + return value; + } + + /** @author Arvind */ + public enum ReportTrackingStatus { + NEW(0), + GENERATING_DATA(1), + UPLOADING_FILE(2), + UPLOADING_FILE_SUCCESS(3), + SENDING_MAIL(4), + SENDING_MAIL_SUCCESS(5), + FAILED(9); + + private int value; + + ReportTrackingStatus(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + } + + public static Map createCheckResponse( + String serviceName, boolean isError, Exception e) { + Map responseMap = new HashMap<>(); + responseMap.put(JsonKey.NAME, serviceName); + if (!isError) { + responseMap.put(JsonKey.Healthy, true); + responseMap.put(JsonKey.ERROR, ""); + responseMap.put(JsonKey.ERRORMSG, ""); + } else { + responseMap.put(JsonKey.Healthy, false); + if (e != null && e instanceof ProjectCommonException) { + ProjectCommonException commonException = (ProjectCommonException) e; + responseMap.put(JsonKey.ERROR, commonException.getResponseCode()); + responseMap.put(JsonKey.ERRORMSG, commonException.getMessage()); + } else { + responseMap.put(JsonKey.ERROR, e != null ? e.getMessage() : "CONNECTION_ERROR"); + responseMap.put(JsonKey.ERRORMSG, e != null ? e.getMessage() : "Connection error"); + } + } + return responseMap; + } + + /** + * This method will make EkStep api call register the tag. + * + * @param tagId String unique tag id. + * @param body String requested body + * @param header Map + * @return String + * @throws IOException + */ + public static String registertag(String tagId, String body, Map header) + throws IOException { + String tagStatus = ""; + try { + ProjectLogger.log("start call for registering the tag ==" + tagId); + String analyticsBaseUrl = getConfigValue(JsonKey.ANALYTICS_API_BASE_URL); + tagStatus = + HttpUtil.sendPostRequest( + analyticsBaseUrl + + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_TAG_API_URL) + + "/" + + tagId, + body, + header); + ProjectLogger.log( + "end call for tag registration id and status ==" + tagId + " " + tagStatus); + } catch (Exception e) { + throw e; + } + return tagStatus; + } + + public enum ObjectTypes { + user("user"), + organisation("organisation"), + batch("batch"); + + private String value; + + private ObjectTypes(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } + + public static String generateRandomPassword() { + String SALTCHARS = "abcdef12345ghijklACDEFGHmnopqrs67IJKLMNOP890tuvQRSTUwxyzVWXYZ"; + StringBuilder salt = new StringBuilder(); + Random rnd = new Random(); + while (salt.length() < randomPasswordLength) { // length of the random string. + int index = (int) (rnd.nextFloat() * SALTCHARS.length()); + salt.append(SALTCHARS.charAt(index)); + } + String saltStr = salt.toString(); + return saltStr; + } + + /** + * This method will do the phone number validation check + * + * @param phone String + * @return boolean + */ + public static boolean validatePhoneNumber(String phone) { + String phoneNo = ""; + phoneNo = phone.replace("+", ""); + if (phoneNo.matches("\\d{10}")) return true; + else if (phoneNo.matches("\\d{3}[-\\.\\s]\\d{3}[-\\.\\s]\\d{4}")) return true; + else if (phoneNo.matches("\\d{3}-\\d{3}-\\d{4}\\s(x|(ext))\\d{3,5}")) return true; + else return (phoneNo.matches("\\(\\d{3}\\)-\\d{3}-\\d{4}")); + } + + public static Map getEkstepHeader() { + Map headerMap = new HashMap<>(); + String header = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(header)) { + header = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } else { + header = JsonKey.BEARER + header; + } + headerMap.put(JsonKey.AUTHORIZATION, header); + headerMap.put("Content-Type", "application/json"); + return headerMap; + } + + public static boolean validatePhone(String phNumber, String countryCode) { + PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + String contryCode = countryCode; + if (!StringUtils.isBlank(countryCode) && (countryCode.charAt(0) != '+')) { + contryCode = "+" + countryCode; + } + Phonenumber.PhoneNumber phoneNumber = null; + try { + if (StringUtils.isBlank(countryCode)) { + contryCode = PropertiesCache.getInstance().getProperty("sunbird_default_country_code"); + } + String isoCode = phoneNumberUtil.getRegionCodeForCountryCode(Integer.parseInt(contryCode)); + phoneNumber = phoneNumberUtil.parse(phNumber, isoCode); + return phoneNumberUtil.isValidNumber(phoneNumber); + } catch (NumberParseException e) { + ProjectLogger.log("Exception occurred while validating phone number : ", e); + ProjectLogger.log(phNumber + "this phone no. is not a valid one."); + } + return false; + } + + public static boolean validateCountryCode(String countryCode) { + String pattern = "^(?:[+] ?){0,1}(?:[0-9] ?){1,3}"; + try { + Pattern patt = Pattern.compile(pattern); + Matcher matcher = patt.matcher(countryCode); + return matcher.matches(); + } catch (RuntimeException e) { + return false; + } + } + + public static boolean validateUUID(String uuidStr) { + try { + UUID.fromString(uuidStr); + return true; + } catch (Exception ex) { + return false; + } + } + + public static String getSMSBody(Map smsTemplate) { + try { + Properties props = new Properties(); + props.put("resource.loader", "class"); + props.put( + "class.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + + VelocityEngine ve = new VelocityEngine(); + ve.init(props); + smsTemplate.put("newline", "\n"); + smsTemplate.put( + "instanceName", + StringUtils.isBlank(smsTemplate.get("instanceName")) + ? "" + : smsTemplate.get("instanceName")); + Template t = ve.getTemplate("/welcomeSmsTemplate.vm"); + VelocityContext context = new VelocityContext(smsTemplate); + StringWriter writer = new StringWriter(); + t.merge(context, writer); + return writer.toString(); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while formating and sending SMS " + ex); + } + return ""; + } + + public static boolean isDateValidFormat(String format, String value) { + Date date = null; + try { + SimpleDateFormat sdf = new SimpleDateFormat(format); + date = sdf.parse(value); + if (!value.equals(sdf.format(date))) { + date = null; + } + } catch (ParseException ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + return date != null; + } + + /** This method will create a new ProjectCommonException of type server Error and throws it. */ + public static void createAndThrowServerError() { + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + /** + * This method will create and return server exception to caller. + * + * @param responseCode ResponseCode + * @return ProjectCommonException + */ + public static ProjectCommonException createServerError(ResponseCode responseCode) { + return new ProjectCommonException( + responseCode.getErrorCode(), + responseCode.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + + /** + * This method will create ProjectCommonException of type invalidUserDate exception and throws it. + */ + public static void createAndThrowInvalidUserDataException() { + throw new ProjectCommonException( + ResponseCode.invalidUsrData.getErrorCode(), + ResponseCode.invalidUsrData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + /** + * Method to verify url is valid or not. + * + * @param url String + * @return boolean + */ + public static boolean isUrlvalid(String url) { + String[] schemes = {"http", "https"}; + UrlValidator urlValidator = new UrlValidator(schemes); + return urlValidator.isValid(url); + } + + public static String getConfigValue(String key) { + if (StringUtils.isNotBlank(System.getenv(key))) { + return System.getenv(key); + } + return propertiesCache.readProperty(key); + } + + /** + * This method will create index for Elastic search as follow "telemetry.raw.yyyy.mm" + * + * @return + */ + public static String createIndex() { + Calendar cal = Calendar.getInstance(); + return new StringBuffer() + .append(INDEX_NAME) + .append("." + cal.get(Calendar.YEAR)) + .append( + "." + + ((cal.get(Calendar.MONTH) + 1) > 9 + ? (cal.get(Calendar.MONTH) + 1) + : "0" + (cal.get(Calendar.MONTH) + 1))) + .toString(); + } + + /** + * This method will check whether Array contains only empty string or not + * + * @param strArray String[] + * @return boolean + */ + public static boolean isNotEmptyStringArray(String[] strArray) { + for (String str : strArray) { + if (StringUtils.isNotEmpty(str)) { + return false; + } + } + return true; + } + + /** + * Method to convert List of map to Json String. + * + * @param mapList List of map. + * @return String List of map converted as Json string. + */ + public static String convertMapToJsonString(List> mapList) { + try { + return mapper.writeValueAsString(mapList); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + return null; + } + + /** + * Method to remove attributes from map. + * + * @param map contains data as key value. + * @param keys list of string that has to be remove from map if presents. + */ + public static void removeUnwantedFields(Map map, String... keys) { + Arrays.stream(keys) + .forEach( + x -> { + map.remove(x); + }); + } + + /** + * Method to convert Json string to Map. + * + * @param jsonString represents json string. + * @return map corresponding to json string. + * @throws IOException + */ + public static Map convertJsonStringToMap(String jsonString) throws IOException { + return mapper.readValue(jsonString, Map.class); + } + + /** + * Method to convert Request object to module specific POJO request. + * + * @param request Represents the incoming request object. + * @param clazz Target POJO class. + * @param Target request object type. + * @return request object of target type. + */ + public static T convertToRequestPojo(Request request, Class clazz) { + return mapper.convertValue(request.getRequest(), clazz); + } + + /** + * This method will take number of days in request and provide date range. Date range is + * calculated as STARTDATE and ENDDATE, start date will be current date minus provided number of + * days and ENDDATE will be current date minus one day. If date is less than equal to zero then it + * will return empty map. + * + * @param numDays Number of days. + * @return Map with STARTDATE and ENDDATE key in YYYY_MM_DD_FORMATTER format. + */ + public static Map getDateRange(int numDays) { + Map map = new HashMap<>(); + if (numDays <= 0) { + return map; + } + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + cal.add(Calendar.DATE, -numDays); + map.put(STARTDATE, new SimpleDateFormat(YYYY_MM_DD_FORMATTER).format(cal.getTime())); + cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + cal.add(Calendar.DATE, -1); + map.put(ENDDATE, new SimpleDateFormat(YYYY_MM_DD_FORMATTER).format(cal.getTime())); + return map; + } + + /** + * This method will be used to create ProjectCommonException for all kind of client error for the + * given response code(enum). + * + * @param : An enum of all the api responses. + * @return ProjectCommonException + */ + public static ProjectCommonException createClientException(ResponseCode responseCode) { + return new ProjectCommonException( + responseCode.getErrorCode(), + responseCode.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + public static String getLmsUserId(String fedUserId) { + String userId = fedUserId; + String prefix = + "f:" + getConfigValue(JsonKey.SUNBIRD_KEYCLOAK_USER_FEDERATION_PROVIDER_ID) + ":"; + if (StringUtils.isNotBlank(fedUserId) && fedUserId.startsWith(prefix)) { + userId = fedUserId.replace(prefix, ""); + } + return userId; + } + + public static String getFirstNCharacterString(String originalText, int noOfChar) { + if (StringUtils.isBlank(originalText)) { + return ""; + } + String firstNChars = ""; + if (originalText.length() > noOfChar) { + firstNChars = originalText.substring(0, noOfChar); + } else { + firstNChars = originalText; + } + return firstNChars; + } + + public enum MigrateAction { + ACCEPT("accept"), + REJECT("reject"); + private String value; + + MigrateAction(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/PropertiesCache.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/PropertiesCache.java new file mode 100644 index 0000000000..4ab67c6fd0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/PropertiesCache.java @@ -0,0 +1,101 @@ +package org.sunbird.common.models.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.commons.lang3.StringUtils; + +/* + * @author Amit Kumar + * + * this class is used for reading properties file + */ +public class PropertiesCache { + + private final String[] fileName = { + "elasticsearch.config.properties", + "cassandra.config.properties", + "dbconfig.properties", + "externalresource.properties", + "sso.properties", + "userencryption.properties", + "profilecompleteness.properties", + "mailTemplates.properties" + }; + private final Properties configProp = new Properties(); + public final Map attributePercentageMap = new ConcurrentHashMap<>(); + private static PropertiesCache propertiesCache = null; + + /** private default constructor */ + private PropertiesCache() { + for (String file : fileName) { + InputStream in = this.getClass().getClassLoader().getResourceAsStream(file); + try { + configProp.load(in); + } catch (IOException e) { + ProjectLogger.log("Error in properties cache", e); + } + } + loadWeighted(); + } + + public static PropertiesCache getInstance() { + + // change the lazy holder implementation to simple singleton implementation ... + if (null == propertiesCache) { + synchronized (PropertiesCache.class) { + if (null == propertiesCache) { + propertiesCache = new PropertiesCache(); + } + } + } + + return propertiesCache; + } + + public void saveConfigProperty(String key, String value) { + configProp.setProperty(key, value); + } + + public String getProperty(String key) { + String value = System.getenv(key); + if (StringUtils.isNotBlank(value)) return value; + return configProp.getProperty(key) != null ? configProp.getProperty(key) : key; + } + + private void loadWeighted() { + String key = configProp.getProperty("user.profile.attribute"); + String value = configProp.getProperty("user.profile.weighted"); + if (StringUtils.isBlank(key)) { + ProjectLogger.log("Profile completeness value is not set==", LoggerEnum.INFO.name()); + } else { + String keys[] = key.split(","); + String values[] = value.split(","); + if (keys.length == value.length()) { + // then take the value from user + ProjectLogger.log("weighted value is provided by user."); + for (int i = 0; i < keys.length; i++) + attributePercentageMap.put(keys[i], new Float(values[i])); + } else { + // equally divide all the provided field. + ProjectLogger.log("weighted value is not provided by user."); + float perc = (float) 100.0 / keys.length; + for (int i = 0; i < keys.length; i++) attributePercentageMap.put(keys[i], perc); + } + } + } + + /** + * Method to read value from resource file . + * + * @param key + * @return + */ + public String readProperty(String key) { + String value = System.getenv(key); + if (StringUtils.isNotBlank(value)) return value; + return configProp.getProperty(key); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/RestUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/RestUtil.java new file mode 100644 index 0000000000..d2086e9e16 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/RestUtil.java @@ -0,0 +1,75 @@ +package org.sunbird.common.models.util; + +import akka.dispatch.Futures; +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.JsonNode; +import com.mashape.unirest.http.Unirest; +import com.mashape.unirest.http.async.Callback; +import com.mashape.unirest.http.exceptions.UnirestException; +import com.mashape.unirest.request.BaseRequest; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; +import scala.concurrent.Future; +import scala.concurrent.Promise; + +/** @author Mahesh Kumar Gangula */ +public class RestUtil { + + static { + String apiKey = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(apiKey)) { + apiKey = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } + Unirest.setDefaultHeader("Content-Type", "application/json"); + Unirest.setDefaultHeader("Authorization", "Bearer " + apiKey); + Unirest.setDefaultHeader("Connection", "Keep-Alive"); + } + + public static Future> executeAsync(BaseRequest request) { + ProjectLogger.log("RestUtil:execute: request url = " + request.getHttpRequest().getUrl()); + Promise> promise = Futures.promise(); + + request.asJsonAsync( + new Callback() { + + @Override + public void failed(UnirestException e) { + promise.failure(e); + } + + @Override + public void completed(HttpResponse response) { + promise.success(response); + } + + @Override + public void cancelled() { + promise.failure(new Exception("cancelled")); + } + }); + + return promise.future(); + } + + public static HttpResponse execute(BaseRequest request) throws Exception { + return request.asJson(); + } + + public static String getFromResponse(HttpResponse resp, String key) throws Exception { + String[] nestedKeys = key.split("\\."); + JSONObject obj = resp.getBody().getObject(); + + for (int i = 0; i < nestedKeys.length - 1; i++) { + String nestedKey = nestedKeys[i]; + if (obj.has(nestedKey)) obj = obj.getJSONObject(nestedKey); + } + + String val = obj.getString(nestedKeys[nestedKeys.length - 1]); + return val; + } + + public static boolean isSuccessful(HttpResponse resp) { + int status = resp.getStatus(); + return (status == 200); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/Slug.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/Slug.java new file mode 100644 index 0000000000..da58937d29 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/Slug.java @@ -0,0 +1,103 @@ +/** */ +package org.sunbird.common.models.util; + +import java.net.URLDecoder; +import java.text.Normalizer; +import java.text.Normalizer.Form; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; +import java.util.regex.Pattern; +import net.sf.junidecode.Junidecode; + +/** + * This class will remove the special character,space from the provided String. + * + * @author Manzarul + */ +public class Slug { + + private static final Pattern NONLATIN = Pattern.compile("[^\\w-\\.]"); + private static final Pattern WHITESPACE = Pattern.compile("[\\s]"); + private static final Pattern DUPDASH = Pattern.compile("-+"); + + public static String makeSlug(String input, boolean transliterate) { + String origInput = input; + String tempInputValue = ""; + // Validate the input + if (input == null) { + ProjectLogger.log("Provided input value is null"); + return input; + } + // Remove extra spaces + tempInputValue = input.trim(); + // Remove URL encoding + tempInputValue = urlDecode(tempInputValue); + // If transliterate is required + if (transliterate) { + // Tranlisterate & cleanup + String transliterated = transliterate(tempInputValue); + tempInputValue = transliterated; + } + // Replace all whitespace with dashes + tempInputValue = WHITESPACE.matcher(tempInputValue).replaceAll("-"); + // Remove all accent chars + tempInputValue = Normalizer.normalize(tempInputValue, Form.NFD); + // Remove all non-latin special characters + tempInputValue = NONLATIN.matcher(tempInputValue).replaceAll(""); + // Remove any consecutive dashes + tempInputValue = normalizeDashes(tempInputValue); + // Validate before returning + validateResult(tempInputValue, origInput); + // Slug is always lowercase + return tempInputValue.toLowerCase(Locale.ENGLISH); + } + + private static void validateResult(String input, String origInput) { + // Check if we are not left with a blank + if (input.length() == 0) { + ProjectLogger.log("Failed to cleanup the input " + origInput); + } + } + + public static String transliterate(String input) { + return Junidecode.unidecode(input); + } + + public static String urlDecode(String input) { + String value = ""; + try { + value = URLDecoder.decode(input, "UTF-8"); + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + return value; + } + + public static String removeDuplicateChars(String text) { + Set set = new LinkedHashSet<>(); + StringBuilder ret = new StringBuilder(text.length()); + if (text.length() == 0) { + return ""; + } + for (int i = 0; i < text.length(); i++) { + set.add(text.charAt(i)); + } + Iterator itr = set.iterator(); + while (itr.hasNext()) { + ret.append(itr.next()); + } + return ret.toString(); + } + + public static String normalizeDashes(String text) { + String clean = DUPDASH.matcher(text).replaceAll("-"); + // Special case that only dashes remain + if ("-".equals(clean) || "--".equals(clean)) return ""; + int startIdx = (clean.startsWith("-") ? 1 : 0); + int endIdx = (clean.endsWith("-") ? 1 : 0); + clean = clean.substring(startIdx, (clean.length() - endIdx)); + return clean; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/StringFormatter.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/StringFormatter.java new file mode 100644 index 0000000000..61d8e18515 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/StringFormatter.java @@ -0,0 +1,56 @@ +package org.sunbird.common.models.util; + +/** + * Helper class for String formatting operations. + * + * @author Amit Kumar + */ +public class StringFormatter { + + public static final String DOT = "."; + public static final String AND = " and "; + public static final String OR = " or "; + public static final String COMMA = ", "; + + private StringFormatter() {} + + /** + * Helper method to construct dot formatted string. + * + * @param params One or more strings to be joined by dot + * @return Dot formatted string + */ + public static String joinByDot(String... params) { + return String.join(DOT, params); + } + + /** + * Helper method to construct or formatted string. + * + * @param params One or more strings to be joined by or + * @return Or formatted string + */ + public static String joinByOr(String... params) { + return String.join(OR, params); + } + + /** + * Helper method to construct and formatted string. + * + * @param params One or more strings to be joined by and + * @return and formatted string + */ + public static String joinByAnd(String... params) { + return String.join(AND, params); + } + + /** + * Helper method to construct and formatted string. + * + * @param params One or more strings to be joined by comma + * @return and formatted string + */ + public static String joinByComma(String... params) { + return String.join(COMMA, params); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/TelemetryEnvKey.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/TelemetryEnvKey.java new file mode 100644 index 0000000000..b4882fa81e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/TelemetryEnvKey.java @@ -0,0 +1,23 @@ +package org.sunbird.common.models.util; + +/** Created by arvind on 9/4/18. */ +public class TelemetryEnvKey { + + public static final String USER = "User"; + public static final String ORGANISATION = "Organisation"; + public static final String BADGE = "Badge"; + public static final String BATCH = "CourseBatch"; + public static final String SKILL = "Skill"; + public static final String GEO_LOCATION = "GeoLocation"; + public static final String BADGE_ISSUER = "BadgeIssuer"; + public static final String BADGE_CLASS = "BadgeClass"; + public static final String BADGE_ASSERTION = "BadgeAssertion"; + public static final String PAGE = "Page"; + public static final String SYSTEM_SETTINGS = "SystemSetting"; + public static final String MASTER_KEY = "MasterKey"; + public static final String OBJECT_STORE = "ObjectStore"; + public static final String LOCATION = "Location"; + public static final String PAGE_SECTION = "PageSection"; + public static final String REQUEST_UPPER_CAMEL = "Request"; + public static final String QR_CODE_DOWNLOAD = "QRCodeDownload"; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureCloudService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureCloudService.java new file mode 100644 index 0000000000..6c9e6d2832 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureCloudService.java @@ -0,0 +1,38 @@ +package org.sunbird.common.models.util.azure; + +import java.io.File; +import java.util.List; + +/** Created by arvind on 24/8/17. */ +public class AzureCloudService implements CloudService { + + @Override + public String uploadFile(String containerName, String fileName, String fileLocation) { + return AzureFileUtility.uploadFile(containerName, fileName, fileLocation); + } + + @Override + public boolean downLoadFile(String containerName, String fileName, String downloadFolder) { + return AzureFileUtility.downloadFile(containerName, fileName, downloadFolder); + } + + @Override + public String uploadFile(String containerName, File file) { + return AzureFileUtility.uploadFile(containerName, file); + } + + @Override + public boolean deleteFile(String containerName, String fileName) { + return AzureFileUtility.deleteFile(containerName, fileName); + } + + @Override + public List listAllFiles(String containerName) { + return AzureFileUtility.listAllBlobbs(containerName); + } + + @Override + public boolean deleteContainer(String containerName) { + return AzureFileUtility.deleteContainer(containerName); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureConnectionManager.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureConnectionManager.java new file mode 100644 index 0000000000..f7ba726bad --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureConnectionManager.java @@ -0,0 +1,130 @@ +/** */ +package org.sunbird.common.models.util.azure; + +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.blob.BlobContainerPermissions; +import com.microsoft.azure.storage.blob.BlobContainerPublicAccessType; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.util.Locale; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +/** + * This class will manage azure connection. + * + * @author Manzarul + */ +public class AzureConnectionManager { + + private static String accountName = ""; + private static String accountKey = ""; + private static String storageAccountString; + private static AzureConnectionManager connectionManager; + + static { + String name = System.getenv(JsonKey.ACCOUNT_NAME); + String key = System.getenv(JsonKey.ACCOUNT_KEY); + if (StringUtils.isBlank(name) || StringUtils.isBlank(key)) { + ProjectLogger.log( + "Azure account name and key is not provided by environment variable." + name + " " + key); + accountName = PropertiesCache.getInstance().getProperty(JsonKey.ACCOUNT_NAME); + accountKey = PropertiesCache.getInstance().getProperty(JsonKey.ACCOUNT_KEY); + storageAccountString = + "DefaultEndpointsProtocol=https;AccountName=" + + accountName + + ";AccountKey=" + + accountKey + + ";EndpointSuffix=core.windows.net"; + } else { + accountName = name; + accountKey = key; + ProjectLogger.log( + "Azure account name and key is provided by environment variable." + name + " " + key); + storageAccountString = + "DefaultEndpointsProtocol=https;AccountName=" + + accountName + + ";AccountKey=" + + accountKey + + ";EndpointSuffix=core.windows.net"; + } + } + + private AzureConnectionManager() throws CloneNotSupportedException { + if (connectionManager != null) throw new CloneNotSupportedException(); + } + + /** + * This method will provide Azure CloudBlobContainer object or in case of error it will provide + * null; + * + * @param containerName String + * @return CloudBlobContainer or null + */ + public static CloudBlobContainer getContainer(String containerName, boolean isPublicAccess) { + + try { + CloudBlobClient cloudBlobClient = getBlobClient(); + // Get a reference to a container , The container name must be lower case + CloudBlobContainer container = + cloudBlobClient.getContainerReference(containerName.toLowerCase(Locale.ENGLISH)); + // Create the container if it does not exist. + boolean response = container.createIfNotExists(); + ProjectLogger.log("container creation done if not exist==" + response); + // Create a permissions object. + if (isPublicAccess) { + BlobContainerPermissions containerPermissions = new BlobContainerPermissions(); + // Include public access in the permissions object. + containerPermissions.setPublicAccess(BlobContainerPublicAccessType.CONTAINER); + // Set the permissions on the container. + container.uploadPermissions(containerPermissions); + } + return container; + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return null; + } + + public static CloudBlobContainer getContainerReference(String containerName) { + + CloudBlobContainer container = null; + try { + // Create the blob client. + CloudBlobClient blobClient = getBlobClient(); + // Retrieve reference to a previously created container. + container = blobClient.getContainerReference(containerName.toLowerCase(Locale.ENGLISH)); + if (container.exists()) { + return container; + } + } catch (URISyntaxException e) { + ProjectLogger.log(e.getMessage(), e); + } catch (StorageException e) { + ProjectLogger.log(e.getMessage(), e); + } + ProjectLogger.log("Container does not exist ==" + containerName); + return null; + } + + private static CloudBlobClient getBlobClient() { + + // Retrieve storage account from connection-string. + CloudStorageAccount storageAccount = null; + CloudBlobClient blobClient = null; + try { + storageAccount = CloudStorageAccount.parse(storageAccountString); + // Create the blob client. + blobClient = storageAccount.createCloudBlobClient(); + } catch (URISyntaxException e) { + ProjectLogger.log(e.getMessage(), e); + } catch (InvalidKeyException e) { + ProjectLogger.log(e.getMessage(), e); + } + return blobClient; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureFileUtility.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureFileUtility.java new file mode 100644 index 0000000000..0d5e1c14ee --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/AzureFileUtility.java @@ -0,0 +1,231 @@ +/** */ +package org.sunbird.common.models.util.azure; + +import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.CloudBlockBlob; +import com.microsoft.azure.storage.blob.ListBlobItem; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.tika.Tika; +import org.sunbird.common.models.util.ProjectLogger; + +/** @author Manzarul */ +public class AzureFileUtility { + + private static final String DEFAULT_CONTAINER = "default"; + + /** + * This method will remove the file from Azure Storage. + * + * @param fileName + * @param containerName + * @return boolean + */ + public static boolean deleteFile(String containerName, String fileName) { + if (fileName == null) { + ProjectLogger.log("File name can not be null"); + return false; + } + if (StringUtils.isBlank(containerName)) { + ProjectLogger.log("Container name can't be null or empty"); + return false; + } + CloudBlobContainer container = AzureConnectionManager.getContainer(containerName, true); + if (container == null) { + ProjectLogger.log("Unable to get Azure contains object"); + return false; + } + try { + // Retrieve reference to a blob named "myimage.jpg". + CloudBlockBlob blob = container.getBlockBlobReference(fileName); + // Delete the blob. + boolean response = blob.deleteIfExists(); + if (!response) { + ProjectLogger.log("Provided file not found to delete."); + } + return true; + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return false; + } + + /** + * This method will remove the container from Azure Storage. + * + * @param containerName + * @return boolean + */ + public static boolean deleteContainer(String containerName) { + if (StringUtils.isBlank(containerName)) { + ProjectLogger.log("Container name can't be null or empty"); + return false; + } + CloudBlobContainer container = AzureConnectionManager.getContainer(containerName, true); + if (container == null) { + ProjectLogger.log("Unable to get Azure contains object"); + return false; + } + try { + boolean response = container.deleteIfExists(); + if (!response) { + ProjectLogger.log("Container not found.."); + } else { + ProjectLogger.log("Container is deleted==="); + } + return true; + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return false; + } + + public static String uploadFile(String containerName, String blobName, String fileName) { + + CloudBlobContainer container = AzureConnectionManager.getContainer(containerName, true); + // Create or overwrite the "myimage.jpg" blob with contents from a local file. + CloudBlockBlob blob = null; + String fileUrl = null; + FileInputStream fis = null; + Tika tika = new Tika(); + try { + blob = container.getBlockBlobReference(blobName); + File source = new File(fileName); + fis = new FileInputStream(source); + String mimeType = tika.detect(source); + ProjectLogger.log("File - " + source.getName() + " mimeType " + mimeType); + blob.getProperties().setContentType(mimeType); + blob.upload(fis, source.length()); + // fileUrl = blob.getStorageUri().getPrimaryUri().getPath(); + fileUrl = blob.getUri().toString(); + } catch (URISyntaxException | IOException e) { + ProjectLogger.log("Unable to upload file :" + fileName, e); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } finally { + if (null != fis) { + try { + fis.close(); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + } + } + + return fileUrl; + } + + public static String uploadFile(String containerName, File source) { + + String containerPath = ""; + String filePath = ""; + Tika tika = new Tika(); + String contrName = containerName; + + if (StringUtils.isBlank(containerName)) { + contrName = DEFAULT_CONTAINER; + } else { + contrName = containerName.toLowerCase(); + } + if (containerName.startsWith("/")) { + contrName = containerName.substring(1); + } + if (contrName.contains("/")) { + String[] arr = contrName.split("/", 2); + containerPath = arr[0]; + if (arr[1].length() > 0 && arr[1].endsWith("/")) { + filePath = arr[1]; + } else if (arr[1].length() > 0) { + filePath = arr[1] + "/"; + } + } else { + containerPath = contrName; + } + + CloudBlobContainer container = AzureConnectionManager.getContainer(containerPath, true); + // Create or overwrite the "myimage.jpg" blob with contents from a local file. + CloudBlockBlob blob = null; + String fileUrl = null; + FileInputStream fis = null; + try { + blob = container.getBlockBlobReference(filePath + source.getName()); + // File source = new File(fileName); + fis = new FileInputStream(source); + String mimeType = tika.detect(source); + ProjectLogger.log("File - " + source.getName() + " mimeType " + mimeType); + blob.getProperties().setContentType(mimeType); + blob.upload(fis, source.length()); + // fileUrl = blob.getStorageUri().getPrimaryUri().getPath(); + fileUrl = blob.getUri().toString(); + } catch (URISyntaxException | IOException e) { + ProjectLogger.log("Unable to upload file :" + source.getName(), e); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } finally { + if (null != fis) { + try { + fis.close(); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + } + } + return fileUrl; + } + + public static boolean downloadFile(String containerName, String blobName, String downloadFolder) { + + String dwnldFolder = ""; + boolean flag = false; + CloudBlobContainer container = AzureConnectionManager.getContainer(containerName, true); + // Create or overwrite blob with contents . + CloudBlockBlob blob = null; + FileOutputStream fos = null; + + try { + blob = container.getBlockBlobReference(blobName); + if (blob.exists()) { + if (!(downloadFolder.endsWith(("/")))) { + dwnldFolder = downloadFolder + "/"; + } + File file = new File(dwnldFolder + blobName); + fos = new FileOutputStream(file); + blob.download(fos); + } + } catch (URISyntaxException | StorageException | FileNotFoundException e) { + ProjectLogger.log("Unable to upload blobfile :" + blobName, e); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } finally { + if (null != fos) { + try { + fos.close(); + } catch (IOException e) { + ProjectLogger.log(e.getMessage(), e); + } + } + } + return flag; + } + + public static List listAllBlobbs(String containerName) { + + List blobsList = new ArrayList<>(); + CloudBlobContainer container = AzureConnectionManager.getContainer(containerName, true); + // Loop over blobs within the container and output the URI to each of them. + if (container != null) { + for (ListBlobItem blobItem : container.listBlobs()) { + blobsList.add(blobItem.getUri().toString()); + } + } + return blobsList; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/CloudService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/CloudService.java new file mode 100644 index 0000000000..a36183057f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/CloudService.java @@ -0,0 +1,20 @@ +package org.sunbird.common.models.util.azure; + +import java.io.File; +import java.util.List; + +/** Created by arvind on 24/8/17. */ +public interface CloudService { + + String uploadFile(String containerName, String filName, String fileLocation); + + boolean downLoadFile(String containerName, String fileName, String downloadFolder); + + String uploadFile(String containerName, File file); + + boolean deleteFile(String containerName, String fileName); + + List listAllFiles(String containerName); + + boolean deleteContainer(String containerName); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/CloudServiceFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/CloudServiceFactory.java new file mode 100644 index 0000000000..936f2a1fd4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/CloudServiceFactory.java @@ -0,0 +1,52 @@ +package org.sunbird.common.models.util.azure; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.sunbird.common.models.util.ProjectUtil; + +/** + * Factory class to store the various upload download services like Azure , Amazon S3 etc... Created + * by arvind on 24/8/17. + */ +public class CloudServiceFactory { + + private static Map factory = new HashMap<>(); + private static List allowedServiceNames = Arrays.asList("Azure", "Amazon S3"); + + private CloudServiceFactory() {} + + /** + * @param serviceName + * @return + */ + public static Object get(String serviceName) { + + if (ProjectUtil.isNotNull(factory.get(serviceName))) { + return factory.get(serviceName); + } else { + // create the service with the given name + return createService(serviceName); + } + } + + /** + * @param serviceName + * @return + */ + private static CloudService createService(String serviceName) { + + if (!(allowedServiceNames.contains(serviceName))) { + return null; + } + + synchronized (CloudServiceFactory.class) { + if (ProjectUtil.isNull(factory.get(serviceName)) && "Azure".equalsIgnoreCase(serviceName)) { + CloudService service = new AzureCloudService(); + factory.put("Azure", service); + } + } + return factory.get(serviceName); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/package-info.java new file mode 100644 index 0000000000..37f0b9c050 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/azure/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.models.util.azure; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/DataMaskingService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/DataMaskingService.java new file mode 100644 index 0000000000..3730eda11f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/DataMaskingService.java @@ -0,0 +1,59 @@ +/** */ +package org.sunbird.common.models.util.datasecurity; + +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; + +/** @author Manzarul */ +public interface DataMaskingService { + + /** + * This method will allow to mask user phone number. + * + * @param phone String + * @return String + */ + String maskPhone(String phone); + + /** + * This method will allow user to mask email. + * + * @param email String + * @return String + */ + String maskEmail(String email); + + /** + * @param data + * @return + */ + default String maskData(String data) { + if (StringUtils.isBlank(data) || data.length() <= 3) { + return data; + } + int lenght = data.length() - 4; + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < data.length(); i++) { + if (i < lenght) { + builder.append(JsonKey.REPLACE_WITH_ASTERISK); + } else { + builder.append(data.charAt(i)); + } + } + return builder.toString(); + } + + /** + * Mask an OTP + * + * @param otp + * @return Depending on the length - 6, 4, masks 1 character + */ + default String maskOTP(String otp) { + if (otp.length() >= 6) { + return otp.replaceAll("(^[^*]{5}|(?!^)\\G)[^*]", "$1*"); + } else { + return otp.replaceAll("(^[^*]{3}|(?!^)\\G)[^*]", "$1*"); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/DecryptionService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/DecryptionService.java new file mode 100644 index 0000000000..0d32b2c13e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/DecryptionService.java @@ -0,0 +1,56 @@ +package org.sunbird.common.models.util.datasecurity; + +import java.util.List; +import java.util.Map; + +/** + * This service will have data decryption methods. decryption logic will differ based on imp + * classes. + * + * @author Manzarul + */ +public interface DecryptionService { + + String ALGORITHM = "AES"; + int ITERATIONS = 3; + byte[] keyValue = + new byte[] {'T', 'h', 'i', 's', 'A', 's', 'I', 'S', 'e', 'r', 'c', 'e', 'K', 't', 'e', 'y'}; + + /** + * This method will take input as key value pair , value can be any primitive or String or both or + * can have another map as values. inner map will also have values as primitive or String or both + * + * @param data Map + * @return Map + * @throws Exception + */ + Map decryptData(Map data); + + /** + * This method will take list of map as an input to decrypt the data, after decryption it will + * return same map with decrypted values. values in side map can have primitive , String or + * another map have primitive , String values. + * + * @param data List> + * @return List> + * @throws Exception + */ + List> decryptData(List> data); + + /** + * Decrypt given data. + * + * @param data Input data + * @return Decrypted data + */ + String decryptData(String data); + + /** + * Decrypt given data. + * + * @param data Input data + * @return Decrypted data + * @throws ProjectCommonException in case of an error during decryption. + */ + String decryptData(String data, boolean throwExceptionOnFailure); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/EncryptionService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/EncryptionService.java new file mode 100644 index 0000000000..33db2d2b61 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/EncryptionService.java @@ -0,0 +1,49 @@ +/** */ +package org.sunbird.common.models.util.datasecurity; + +import java.util.List; +import java.util.Map; + +/** + * This service will have the data encryption logic. these logic will differ based on implementation + * class. + * + * @author Manzarul + */ +public interface EncryptionService { + + String ALGORITHM = "AES"; + int ITERATIONS = 3; + byte[] keyValue = + new byte[] {'T', 'h', 'i', 's', 'A', 's', 'I', 'S', 'e', 'r', 'c', 'e', 'K', 't', 'e', 'y'}; + + /** + * This method will take input as key value pair , value can be any primitive or String or both or + * can have another map as values. inner map will also have values as primitive or String or both + * + * @param data Map + * @return Map + * @throws Exception + */ + Map encryptData(Map data) throws Exception; + + /** + * This method will take list of map as an input to encrypt the data, after encryption it will + * return same map with encrypted values. values in side map can have primitive , String or + * another map have primitive , String values. + * + * @param data List> + * @return List> + * @throws Exception + */ + List> encryptData(List> data) throws Exception; + + /** + * This method will take String as an input and encrypt the String and return back. + * + * @param data String + * @return String + * @throws Exception + */ + String encryptData(String data) throws Exception; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/OneWayHashing.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/OneWayHashing.java new file mode 100644 index 0000000000..6065bbe223 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/OneWayHashing.java @@ -0,0 +1,40 @@ +/** */ +package org.sunbird.common.models.util.datasecurity; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import org.sunbird.common.models.util.ProjectLogger; + +/** + * This class will do one way data hashing. + * + * @author Manzarul + */ +public class OneWayHashing { + + private OneWayHashing() {} + + /** + * This method will encrypt value using SHA-256 . it is one way encryption. + * + * @param val String + * @return String encrypted value or empty in case of exception + */ + public static String encryptVal(String val) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(val.getBytes(StandardCharsets.UTF_8)); + byte byteData[] = md.digest(); + // convert the byte to hex format method 1 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byteData.length; i++) { + sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1)); + } + ProjectLogger.log("encrypted value is==: " + sb.toString()); + return sb.toString(); + } catch (Exception e) { + ProjectLogger.log("Error while encrypting", e); + } + return ""; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultDataMaskServiceImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultDataMaskServiceImpl.java new file mode 100644 index 0000000000..03782cb97d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultDataMaskServiceImpl.java @@ -0,0 +1,48 @@ +/** */ +package org.sunbird.common.models.util.datasecurity.impl; + +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; + +/** @author Manzarul */ +public class DefaultDataMaskServiceImpl implements DataMaskingService { + + @Override + public String maskPhone(String phone) { + if (StringUtils.isBlank(phone) || phone.length() < 10) { + return phone; + } + String tempPhone = ""; + StringBuilder builder = new StringBuilder(); + tempPhone = phone.trim().replace("-", ""); + int length = tempPhone.length(); + for (int i = 0; i < length; i++) { + if (i < length - 4) { + builder.append(JsonKey.REPLACE_WITH_ASTERISK); + } else { + builder.append(tempPhone.charAt(i)); + } + } + return builder.toString(); + } + + @Override + public String maskEmail(String email) { + if ((StringUtils.isBlank(email)) || (!ProjectUtil.isEmailvalid(email))) { + return email; + } + StringBuilder builder = new StringBuilder(); + String[] emails = email.split("@"); + int length = emails[0].length(); + for (int i = 0; i < email.length(); i++) { + if (i < 2 || i >= length) { + builder.append(email.charAt(i)); + } else { + builder.append(JsonKey.REPLACE_WITH_ASTERISK); + } + } + return builder.toString(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultDecryptionServiceImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultDecryptionServiceImpl.java new file mode 100644 index 0000000000..93364c36c8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultDecryptionServiceImpl.java @@ -0,0 +1,122 @@ +package org.sunbird.common.models.util.datasecurity.impl; + +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.responsecode.ResponseCode; + +public class DefaultDecryptionServiceImpl implements DecryptionService { + private static String sunbird_encryption = ""; + + private String sunbirdEncryption = ""; + + private static Cipher c; + + static { + try { + sunbird_encryption = DefaultEncryptionServivceImpl.getSalt(); + Key key = generateKey(); + c = Cipher.getInstance(ALGORITHM); + c.init(Cipher.DECRYPT_MODE, key); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + public DefaultDecryptionServiceImpl() { + sunbirdEncryption = System.getenv(JsonKey.SUNBIRD_ENCRYPTION); + if (StringUtils.isBlank(sunbirdEncryption)) { + sunbirdEncryption = PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_ENCRYPTION); + } + } + + @Override + public Map decryptData(Map data) { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + if (data == null) { + return data; + } + Iterator> itr = data.entrySet().iterator(); + while (itr.hasNext()) { + Entry entry = itr.next(); + if (!(entry.getValue() instanceof Map || entry.getValue() instanceof List) + && null != entry.getValue()) { + data.put(entry.getKey(), decrypt(entry.getValue() + "", false)); + } + } + } + return data; + } + + @Override + public List> decryptData(List> data) { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + if (data == null || data.isEmpty()) { + return data; + } + + for (Map map : data) { + decryptData(map); + } + } + return data; + } + + @Override + public String decryptData(String data) { + return decryptData(data, false); + } + + @Override + public String decryptData(String data, boolean throwExceptionOnFailure) { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + if (StringUtils.isBlank(data)) { + return data; + } else { + return decrypt(data, throwExceptionOnFailure); + } + } else { + return data; + } + } + + public static String decrypt(String value, boolean throwExceptionOnFailure) { + try { + String dValue = null; + String valueToDecrypt = value.trim(); + for (int i = 0; i < ITERATIONS; i++) { + byte[] decordedValue = new sun.misc.BASE64Decoder().decodeBuffer(valueToDecrypt); + byte[] decValue = c.doFinal(decordedValue); + dValue = + new String(decValue, StandardCharsets.UTF_8).substring(sunbird_encryption.length()); + valueToDecrypt = dValue; + } + return dValue; + } catch (Exception ex) { + ProjectLogger.log( + "DefaultDecryptionServiceImpl:decrypt: Exception occurred with error message = " + + ex.getMessage(), + LoggerEnum.ERROR.name()); + if (throwExceptionOnFailure) { + ProjectCommonException.throwClientErrorException(ResponseCode.userDataEncryptionError); + } + } + return value; + } + + private static Key generateKey() { + return new SecretKeySpec(keyValue, ALGORITHM); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultEncryptionServivceImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultEncryptionServivceImpl.java new file mode 100644 index 0000000000..702ca9d469 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/DefaultEncryptionServivceImpl.java @@ -0,0 +1,156 @@ +/** */ +package org.sunbird.common.models.util.datasecurity.impl; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * Default data encryption service + * + * @author Manzarul + */ +public class DefaultEncryptionServivceImpl implements EncryptionService { + + private static String encryption_key = ""; + + private String sunbirdEncryption = ""; + + private static Cipher c; + + static { + try { + encryption_key = getSalt(); + Key key = generateKey(); + c = Cipher.getInstance(ALGORITHM); + c.init(Cipher.ENCRYPT_MODE, key); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + } + + public DefaultEncryptionServivceImpl() { + sunbirdEncryption = System.getenv(JsonKey.SUNBIRD_ENCRYPTION); + if (StringUtils.isBlank(sunbirdEncryption)) { + sunbirdEncryption = PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_ENCRYPTION); + } + } + + @Override + public Map encryptData(Map data) throws Exception { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + if (data == null) { + return data; + } + Iterator> itr = data.entrySet().iterator(); + while (itr.hasNext()) { + Entry entry = itr.next(); + if (!(entry.getValue() instanceof Map || entry.getValue() instanceof List) + && null != entry.getValue()) { + data.put(entry.getKey(), encrypt(entry.getValue() + "")); + } + } + } + return data; + } + + @Override + public List> encryptData(List> data) throws Exception { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + if (data == null || data.isEmpty()) { + return data; + } + for (Map map : data) { + encryptData(map); + } + } + return data; + } + + @Override + public String encryptData(String data) throws Exception { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + if (StringUtils.isBlank(data)) { + return data; + } + if (null != data) { + return encrypt(data); + } else { + return data; + } + } else { + return data; + } + } + + /** + * this method is used to encrypt the password. + * + * @param value String password + * @param encryption_key + * @return encrypted password. + * @throws NoSuchPaddingException + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + * @throws BadPaddingException + * @throws IllegalBlockSizeException + * @throws UnsupportedEncodingException + */ + @SuppressWarnings("restriction") + public static String encrypt(String value) + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, + IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { + String valueToEnc = null; + String eValue = value; + for (int i = 0; i < ITERATIONS; i++) { + valueToEnc = encryption_key + eValue; + byte[] encValue = c.doFinal(valueToEnc.getBytes(StandardCharsets.UTF_8)); + eValue = new sun.misc.BASE64Encoder().encode(encValue); + } + return eValue; + } + + private static Key generateKey() { + return new SecretKeySpec(keyValue, ALGORITHM); + } + + /** @return */ + public static String getSalt() { + if (!StringUtils.isBlank(encryption_key)) { + return encryption_key; + } else { + encryption_key = System.getenv(JsonKey.ENCRYPTION_KEY); + if (StringUtils.isBlank(encryption_key)) { + ProjectLogger.log("Salt value is not provided by Env"); + encryption_key = PropertiesCache.getInstance().getProperty(JsonKey.ENCRYPTION_KEY); + } + } + if (StringUtils.isBlank(encryption_key)) { + ProjectLogger.log("throwing exception for invalid salt==", LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.saltValue.getErrorCode(), + ResponseCode.saltValue.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return encryption_key; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/LogMaskServiceImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/LogMaskServiceImpl.java new file mode 100644 index 0000000000..4a3c51e0d1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/LogMaskServiceImpl.java @@ -0,0 +1,29 @@ +package org.sunbird.common.models.util.datasecurity.impl; + +import org.sunbird.common.models.util.datasecurity.DataMaskingService; + +public class LogMaskServiceImpl implements DataMaskingService { + /** + * Mask an email + * + * @param email + * @return the first 4 or 2 characters in plain and masks the rest. The domain is still in plain + */ + public String maskEmail(String email) { + if (email.indexOf("@") > 4) { + return email.replaceAll("(^[^@]{4}|(?!^)\\G)[^@]", "$1*"); + } else { + return email.replaceAll("(^[^@]{2}|(?!^)\\G)[^@]", "$1*"); + } + } + + /** + * Mask a phone number + * + * @param phone + * @return a string with the last digit masked + */ + public String maskPhone(String phone) { + return phone.replaceAll("(^[^*]{9}|(?!^)\\G)[^*]", "$1*"); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/ServiceFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/ServiceFactory.java new file mode 100644 index 0000000000..91a783c85f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/ServiceFactory.java @@ -0,0 +1,78 @@ +/** */ +package org.sunbird.common.models.util.datasecurity.impl; + +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; + +/** + * This factory will provide encryption service instance and decryption service instance with + * default implementation. + * + * @author Manzarul + */ +public class ServiceFactory { + + private static EncryptionService encryptionService; + private static DecryptionService decryptionService; + private static DataMaskingService maskingService; + + static { + encryptionService = new DefaultEncryptionServivceImpl(); + decryptionService = new DefaultDecryptionServiceImpl(); + maskingService = new DefaultDataMaskServiceImpl(); + } + + /** + * this method will provide encryptionServiceImple instance. by default it will provide + * DefaultEncryptionServiceImpl instance to get a particular service impl instance , need to + * change the object creation and provided logic. + * + * @param val String ( pass null or empty in case of defaultImple object.) + * @return EncryptionService + */ + public static EncryptionService getEncryptionServiceInstance(String val) { + if (StringUtils.isBlank(val)) { + return encryptionService; + } + switch (val) { + case "defaultEncryption": + return encryptionService; + default: + return encryptionService; + } + } + + /** + * this method will provide decryptionServiceImple instance. by default it will provide + * DefaultDecryptionServiceImpl instance to get a particular service impl instance , need to + * change the object creation and provided logic. + * + * @param val String ( pass null or empty in case of defaultImple object.) + * @return DecryptionService + */ + public static DecryptionService getDecryptionServiceInstance(String val) { + if (StringUtils.isBlank(val)) { + return decryptionService; + } + switch (val) { + case "defaultDecryption": + return decryptionService; + default: + return decryptionService; + } + } + + public static DataMaskingService getMaskingServiceInstance(String val) { + if (StringUtils.isBlank(val)) { + return maskingService; + } + switch (val) { + case "defaultMasking": + return maskingService; + default: + return maskingService; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/package-info.java new file mode 100644 index 0000000000..c601093b4a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/impl/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.models.util.datasecurity.impl; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/package-info.java new file mode 100644 index 0000000000..09c3c5704b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/datasecurity/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.models.util.datasecurity; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/fcm/Notification.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/fcm/Notification.java new file mode 100644 index 0000000000..8daea20ae1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/fcm/Notification.java @@ -0,0 +1,61 @@ +/** */ +package org.sunbird.common.models.util.fcm; + +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +/** @author Manzarul */ +public class Notification { + /** FCM_URL URL of FCM server */ + public static final String FCM_URL = PropertiesCache.getInstance().getProperty(JsonKey.FCM_URL); + /** FCM_ACCOUNT_KEY FCM server key. */ + private static final String FCM_ACCOUNT_KEY = System.getenv(JsonKey.SUNBIRD_FCM_ACCOUNT_KEY); + + private static Map headerMap = new HashMap<>(); + private static final String TOPIC_SUFFIX = "/topics/"; + + static { + headerMap.put(JsonKey.AUTHORIZATION, FCM_ACCOUNT_KEY); + headerMap.put("Content-Type", "application/json"); + } + + /** + * This method will send notification to FCM. + * + * @param topic String + * @param data Map + * @param url String + * @return String as Json.{"message_id": 7253391319867149192} + */ + public static String sendNotification(String topic, Map data, String url) { + if (StringUtils.isBlank(FCM_ACCOUNT_KEY) || StringUtils.isBlank(url)) { + ProjectLogger.log( + "FCM account key or URL is not provided===" + FCM_URL, LoggerEnum.INFO.name()); + return JsonKey.FAILURE; + } + String response = null; + try { + JSONObject object1 = new JSONObject(data); + JSONObject object = new JSONObject(); + object.put(JsonKey.DATA, object1); + object.put(JsonKey.TO, TOPIC_SUFFIX + topic); + response = HttpUtil.sendPostRequest(FCM_URL, object.toString(), headerMap); + ProjectLogger.log("FCM Notification response== for topic " + topic + response); + object1 = null; + object1 = new JSONObject(response); + long val = object1.getLong(JsonKey.MESSAGE_Id); + response = val + ""; + } catch (Exception e) { + response = JsonKey.FAILURE; + ProjectLogger.log(e.getMessage(), e); + } + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/fcm/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/fcm/package-info.java new file mode 100644 index 0000000000..676f493d8a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/fcm/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.models.util.fcm; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/GMailAuthenticator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/GMailAuthenticator.java new file mode 100644 index 0000000000..cb65dbb883 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/GMailAuthenticator.java @@ -0,0 +1,29 @@ +/** */ +package org.sunbird.common.models.util.mail; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; + +/** @author Manzarul.Haque */ +public class GMailAuthenticator extends Authenticator { + private String user; + private String pw; + + /** + * this method is used to authenticate gmail user name and password. + * + * @param username + * @param password + */ + public GMailAuthenticator(String username, String password) { + super(); + this.user = username; + this.pw = password; + } + + /** */ + @Override + public PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(this.user, this.pw); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/SendMail.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/SendMail.java new file mode 100644 index 0000000000..70eb39ffd5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/SendMail.java @@ -0,0 +1,298 @@ +package org.sunbird.common.models.util.mail; + +import java.io.StringWriter; +import java.util.Properties; +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.mail.BodyPart; +import javax.mail.Message; +import javax.mail.Message.RecipientType; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import org.apache.commons.lang3.StringUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +/** + * this api is used to sending mail. + * + * @author Manzarul.Haque + */ +public class SendMail { + + private static Properties props = null; + private static String host; + private static String port; + private static String userName; + private static String password; + private static String fromEmail; + + static { + // collecting setup value from ENV + host = System.getenv(JsonKey.EMAIL_SERVER_HOST); + port = System.getenv(JsonKey.EMAIL_SERVER_PORT); + userName = System.getenv(JsonKey.EMAIL_SERVER_USERNAME); + password = System.getenv(JsonKey.EMAIL_SERVER_PASSWORD); + fromEmail = System.getenv(JsonKey.EMAIL_SERVER_FROM); + if (StringUtils.isBlank(host) + || StringUtils.isBlank(port) + || StringUtils.isBlank(userName) + || StringUtils.isBlank(password) + || StringUtils.isBlank(fromEmail)) { + ProjectLogger.log( + "Email setting value is not provided by Env variable==" + + host + + " " + + port + + " " + + fromEmail, + LoggerEnum.INFO.name()); + initialiseFromProperty(); + } + props = System.getProperties(); + props.put("mail.smtp.host", host); + props.put("mail.smtp.socketFactory.port", port); + /* + * props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + */ + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.port", port); + } + + /** This method will initialize values from property files. */ + public static void initialiseFromProperty() { + host = PropertiesCache.getInstance().getProperty(JsonKey.EMAIL_SERVER_HOST); + port = PropertiesCache.getInstance().getProperty(JsonKey.EMAIL_SERVER_PORT); + userName = PropertiesCache.getInstance().getProperty(JsonKey.EMAIL_SERVER_USERNAME); + password = PropertiesCache.getInstance().getProperty(JsonKey.EMAIL_SERVER_PASSWORD); + fromEmail = PropertiesCache.getInstance().getProperty(JsonKey.EMAIL_SERVER_FROM); + } + + /** + * Send email using given template name. + * + * @param emailList List of recipient emails + * @param context Context for Velocity template + * @param templateName Name of email template + * @param subject Subject of email + */ + public static boolean sendMail( + String[] emailList, String subject, VelocityContext context, String templateName) { + VelocityEngine engine = new VelocityEngine(); + Properties p = new Properties(); + p.setProperty("resource.loader", "class"); + p.setProperty( + "class.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + StringWriter writer = null; + try { + engine.init(p); + Template template = engine.getTemplate(templateName); + writer = new StringWriter(); + template.merge(context, writer); + } catch (Exception e) { + ProjectLogger.log( + "SendMail:sendMail : Exception occurred with message = " + e.getMessage(), e); + } + + return sendEmail(emailList, subject, context, writer); + } + + /** + * Send email using given template body. + * + * @param emailList List of recipient emails + * @param context Context for Velocity template + * @param templateBody Email template body + * @param subject Subject of email + */ + public static boolean sendMailWithBody( + String[] emailList, String subject, VelocityContext context, String templateBody) { + StringWriter writer = null; + try { + Velocity.init(); + writer = new StringWriter(); + Velocity.evaluate(context, writer, "SimpleVelocity", templateBody); + } catch (Exception e) { + ProjectLogger.log( + "SendMail:sendMailWithBody : Exception occurred with message =" + e.getMessage(), e); + } + return sendEmail(emailList, subject, context, writer); + } + + /** + * Send email (with Cc) using given template name. + * + * @param emailList List of recipient emails + * @param context Context for Velocity template + * @param templateName Name of email template + * @param subject Subject of email + * @param ccEmailList List of Cc emails + */ + public static void sendMail( + String[] emailList, + String subject, + VelocityContext context, + String templateName, + String[] ccEmailList) { + ProjectLogger.log("Mail Template name - " + templateName, LoggerEnum.INFO.name()); + Transport transport = null; + try { + Session session = Session.getInstance(props, new GMailAuthenticator(userName, password)); + MimeMessage message = new MimeMessage(session); + message.setFrom(new InternetAddress(fromEmail)); + int size = emailList.length; + int i = 0; + while (size > 0) { + message.addRecipient(Message.RecipientType.TO, new InternetAddress(emailList[i])); + i++; + size--; + } + size = ccEmailList.length; + i = 0; + while (size > 0) { + message.addRecipient(Message.RecipientType.CC, new InternetAddress(ccEmailList[i])); + i++; + size--; + } + message.setSubject(subject); + VelocityEngine engine = new VelocityEngine(); + Properties p = new Properties(); + p.setProperty("resource.loader", "class"); + p.setProperty( + "class.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + engine.init(p); + Template template = engine.getTemplate(templateName); + StringWriter writer = new StringWriter(); + template.merge(context, writer); + message.setContent(writer.toString(), "text/html; charset=utf-8"); + transport = session.getTransport("smtp"); + transport.connect(host, userName, password); + transport.sendMessage(message, message.getAllRecipients()); + transport.close(); + } catch (Exception e) { + ProjectLogger.log(e.toString(), e); + } finally { + if (transport != null) { + try { + transport.close(); + } catch (MessagingException e) { + ProjectLogger.log(e.toString(), e); + } + } + } + } + + /** + * Send email (with attachment) and given body. + * + * @param emailList List of recipient emails + * @param emailBody Text of email body + * @param subject Subject of email + * @param filePath Path of attachment file + */ + public static void sendAttachment( + String[] emailList, String emailBody, String subject, String filePath) { + Transport transport = null; + try { + Session session = Session.getInstance(props, new GMailAuthenticator(userName, password)); + MimeMessage message = new MimeMessage(session); + message.setFrom(new InternetAddress(fromEmail)); + int size = emailList.length; + int i = 0; + while (size > 0) { + message.addRecipient(Message.RecipientType.TO, new InternetAddress(emailList[i])); + i++; + size--; + } + message.setSubject(subject); + BodyPart messageBodyPart = new MimeBodyPart(); + messageBodyPart.setContent(emailBody, "text/html; charset=utf-8"); + // messageBodyPart.setText(mail); + // Create a multipar message + Multipart multipart = new MimeMultipart(); + multipart.addBodyPart(messageBodyPart); + DataSource source = new FileDataSource(filePath); + messageBodyPart = null; + messageBodyPart = new MimeBodyPart(); + messageBodyPart.setDataHandler(new DataHandler(source)); + messageBodyPart.setFileName(filePath); + multipart.addBodyPart(messageBodyPart); + message.setSubject(subject); + message.setContent(multipart); + transport = session.getTransport("smtp"); + transport.connect(host, userName, password); + transport.sendMessage(message, message.getAllRecipients()); + transport.close(); + } catch (Exception e) { + ProjectLogger.log(e.toString(), e); + } finally { + if (transport != null) { + try { + transport.close(); + } catch (MessagingException e) { + ProjectLogger.log(e.toString(), e); + } + } + } + } + + private static boolean sendEmail( + String[] emailList, String subject, VelocityContext context, StringWriter writer) { + Transport transport = null; + boolean sentStatus = true; + try { + if (context != null) { + context.put(JsonKey.FROM_EMAIL, fromEmail); + } + Session session = Session.getInstance(props, new GMailAuthenticator(userName, password)); + MimeMessage message = new MimeMessage(session); + message.setFrom(new InternetAddress(fromEmail)); + RecipientType recipientType = null; + if (emailList.length > 1) { + recipientType = Message.RecipientType.BCC; + } else { + recipientType = Message.RecipientType.TO; + } + for (String email : emailList) { + message.addRecipient(recipientType, new InternetAddress(email)); + } + if (recipientType == Message.RecipientType.BCC) + message.addRecipient(Message.RecipientType.TO, new InternetAddress(fromEmail)); + message.setSubject(subject); + message.setContent(writer.toString(), "text/html; charset=utf-8"); + transport = session.getTransport("smtp"); + transport.connect(host, userName, password); + transport.sendMessage(message, message.getAllRecipients()); + transport.close(); + } catch (Exception e) { + + sentStatus = false; + ProjectLogger.log( + "SendMail:sendMail: Exception occurred with message = " + e.getMessage(), e); + } finally { + if (transport != null) { + try { + transport.close(); + } catch (MessagingException e) { + ProjectLogger.log(e.toString(), e); + } + } + } + return sentStatus; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/package-info.java new file mode 100644 index 0000000000..812922d935 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/mail/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.models.util.mail; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/package-info.java new file mode 100644 index 0000000000..be4d48c503 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.models.util; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/url/URLShortner.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/url/URLShortner.java new file mode 100644 index 0000000000..823d7e51d4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/url/URLShortner.java @@ -0,0 +1,6 @@ +package org.sunbird.common.models.util.url; + +public interface URLShortner { + + public String shortUrl(String url); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/url/URLShortnerImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/url/URLShortnerImpl.java new file mode 100644 index 0000000000..a7d74903d8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/models/util/url/URLShortnerImpl.java @@ -0,0 +1,70 @@ +package org.sunbird.common.models.util.url; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; + +/** @author Amit Kumar */ +public class URLShortnerImpl implements URLShortner { + + private static String resUrl = null; + private static final String SUNBIRD_WEB_URL = "sunbird_web_url"; + + @Override + public String shortUrl(String url) { + boolean flag = false; + try { + flag = Boolean.parseBoolean(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_URL_SHORTNER_ENABLE)); + } catch (Exception ex) { + ProjectLogger.log( + "URLShortnerImpl:shortUrl : Exception occurred while parsing sunbird_url_shortner_enable key"); + } + if (flag) { + String baseUrl = PropertiesCache.getInstance().getProperty("sunbird_url_shortner_base_url"); + String accessToken = System.getenv("url_shortner_access_token"); + if (StringUtils.isBlank(accessToken)) { + accessToken = + PropertiesCache.getInstance().getProperty("sunbird_url_shortner_access_token"); + } + String requestURL = baseUrl + accessToken + "&longUrl=" + url; + String response = ""; + try { + response = HttpUtil.sendGetRequest(requestURL, null); + } catch (IOException e) { + ProjectLogger.log("Exception occurred while sending request for URL shortening", e); + } + ObjectMapper mapper = new ObjectMapper(); + Map map = null; + if (!StringUtils.isBlank(response)) { + try { + map = mapper.readValue(response, HashMap.class); + Map dataMap = (Map) map.get("data"); + return dataMap.get("url"); + } catch (IOException | ClassCastException e) { + ProjectLogger.log(e.getMessage(), e); + } + } + } + return url; + } + + /** @return the url */ + public String getUrl() { + if (StringUtils.isBlank(resUrl)) { + String webUrl = System.getenv(SUNBIRD_WEB_URL); + if (StringUtils.isBlank(webUrl)) { + webUrl = PropertiesCache.getInstance().getProperty(SUNBIRD_WEB_URL); + } + return shortUrl(webUrl); + } else { + return resUrl; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/AddressRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/AddressRequestValidator.java new file mode 100644 index 0000000000..615bf6e6d7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/AddressRequestValidator.java @@ -0,0 +1,58 @@ +package org.sunbird.common.request; + +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.ProjectUtil.AddressType; +import org.sunbird.common.responsecode.ResponseCode; + +public class AddressRequestValidator extends BaseRequestValidator { + + private static final int ERROR_CODE = ResponseCode.CLIENT_ERROR.getResponseCode(); + + public void validateAddress(Map address, String type) { + if (StringUtils.isBlank((String) address.get(JsonKey.ADDRESS_LINE1))) { + throw new ProjectCommonException( + ResponseCode.addressError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.addressError.getErrorMessage(), type, JsonKey.ADDRESS_LINE1), + ERROR_CODE); + } + if (StringUtils.isBlank((String) address.get(JsonKey.CITY))) { + throw new ProjectCommonException( + ResponseCode.addressError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.addressError.getErrorMessage(), type, JsonKey.CITY), + ERROR_CODE); + } + if (address.containsKey(JsonKey.ADD_TYPE)) { + + if (StringUtils.isBlank((String) address.get(JsonKey.ADD_TYPE))) { + throw new ProjectCommonException( + ResponseCode.addressError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.addressError.getErrorMessage(), JsonKey.ADDRESS, JsonKey.TYPE), + ERROR_CODE); + } + + if (!StringUtils.isBlank((String) address.get(JsonKey.ADD_TYPE)) + && !checkAddressType((String) address.get(JsonKey.ADD_TYPE))) { + throw new ProjectCommonException( + ResponseCode.addressTypeError.getErrorCode(), + ResponseCode.addressTypeError.getErrorMessage(), + ERROR_CODE); + } + } + } + + private static boolean checkAddressType(String addrType) { + for (AddressType type : AddressType.values()) { + if (type.getTypeName().equals(addrType)) { + return true; + } + } + return false; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/BaseRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/BaseRequestValidator.java new file mode 100644 index 0000000000..2dd730e69a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/BaseRequestValidator.java @@ -0,0 +1,498 @@ +package org.sunbird.common.request; + +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.EmailValidator; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.StringFormatter; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * Base request validator class to house common validation methods. + * + * @author B Vinaya Kumar + */ +public class BaseRequestValidator { + + /** + * Helper method which throws an exception if given parameter value is blank (null or empty). + * + * @param value Request parameter value. + * @param error Error to be thrown in case of validation error. + */ + public void validateParam(String value, ResponseCode error) { + if (StringUtils.isBlank(value)) { + throw new ProjectCommonException( + error.getErrorCode(), + error.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * Helper method which throws an exception if given parameter value is blank (null or empty). + * + * @param value Request parameter value. + * @param error Error to be thrown in case of validation error. + * @param errorMsgArgument Argument for error message. + */ + public void validateParam(String value, ResponseCode error, String errorMsgArgument) { + if (StringUtils.isBlank(value)) { + throw new ProjectCommonException( + error.getErrorCode(), + MessageFormat.format(error.getErrorMessage(), errorMsgArgument), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + /** + * Helper method which throws an exception if the given parameter list size exceeds the expected + * size + * + * @param paramName Configuration parameter name + * @param key Request parameter name + * @param listValue Request parameter value + */ + public void validateListParamSize(String paramName, String key, List listValue) { + int maximumSizeAllowed = 0; + try { + maximumSizeAllowed = Integer.valueOf(ProjectUtil.getConfigValue(paramName).trim()); + } catch (NumberFormatException e) { + ProjectCommonException.throwServerErrorException( + ResponseCode.errorInvalidConfigParamValue, + MessageFormat.format( + ResponseCode.errorInvalidConfigParamValue.getErrorMessage(), + ProjectUtil.getConfigValue(key).trim(), + key)); + } + if (listValue.size() > maximumSizeAllowed) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorMaxSizeExceeded, + MessageFormat.format( + ResponseCode.errorMaxSizeExceeded.getErrorMessage(), + key, + String.valueOf(maximumSizeAllowed))); + } + } + + /** + * This method will create the ProjectCommonException by reading ResponseCode and errorCode. + * incase ResponseCode is null then it will throw invalidData error. + * + * @param code Error response code + * @param errorCode (Http error code) + * @return custom project exception + */ + public ProjectCommonException createExceptionByResponseCode(ResponseCode code, int errorCode) { + if (code == null) { + ProjectLogger.log("ResponseCode object is coming as null", LoggerEnum.INFO.name()); + return new ProjectCommonException( + ResponseCode.invalidData.getErrorCode(), + ResponseCode.invalidData.getErrorMessage(), + errorCode); + } + return new ProjectCommonException(code.getErrorCode(), code.getErrorMessage(), errorCode); + } + + /** + * This method will create the ProjectCommonException by reading ResponseCode and errorCode. + * incase ResponseCode is null then it will throw invalidData error. + * + * @param code Error response code + * @param errorCode (Http error code) + * @return custom project exception + */ + public ProjectCommonException createExceptionByResponseCode( + ResponseCode code, int errorCode, String errorMsgArgument) { + if (code == null) { + ProjectLogger.log("ResponseCode object is coming as null", LoggerEnum.INFO.name()); + return new ProjectCommonException( + ResponseCode.invalidData.getErrorCode(), + ResponseCode.invalidData.getErrorMessage(), + errorCode); + } + return new ProjectCommonException( + code.getErrorCode(), + MessageFormat.format(code.getErrorMessage(), errorMsgArgument), + errorCode); + } + + /** + * Method to check whether given mandatory fields is in given map or not. + * + * @param data Map contains the key value, + * @param keys List of string represents the mandatory fields. + */ + public void checkMandatoryFieldsPresent(Map data, String... keys) { + if (MapUtils.isEmpty(data)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Arrays.stream(keys) + .forEach( + key -> { + if (StringUtils.isEmpty((String) data.get(key))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + key); + } + }); + } + /** + * Method to check whether given mandatory fields is in given map or not. also check the instance + * of request attributes + * + * @param data Map contains the key value, + * @param mandatoryParamsList List of string represents the mandatory fields. + */ + public void checkMandatoryFieldsPresent( + Map data, List mandatoryParamsList) { + if (MapUtils.isEmpty(data)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + mandatoryParamsList.forEach( + key -> { + if (StringUtils.isEmpty((String) data.get(key))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + key); + } + if (!(data.get(key) instanceof String)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + MessageFormat.format(ResponseCode.dataTypeError.getErrorMessage(), key, "String"), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + } + + /** + * Method to check whether given mandatory fields is in given map or not . + * + * @param data Map contains the key value + * @param keys List of string represents the mandatory fields + * @param exceptionMsg Exception message + */ + public void checkMandatoryParamsPresent( + Map data, String exceptionMsg, String... keys) { + if (MapUtils.isEmpty(data)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Arrays.stream(keys) + .forEach( + key -> { + if (StringUtils.isEmpty((String) data.get(key))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), exceptionMsg), + ResponseCode.CLIENT_ERROR.getResponseCode(), + key); + } + }); + } + + /** + * Method to check whether given fields is in given map or not .If it is there throw exception. + * because in some update request cases we don't want to update some props to , if it is there in + * request , throw exception. + * + * @param data Map contains the key value + * @param keys List of string represents the must not present fields. + */ + public void checkReadOnlyAttributesAbsent(Map data, String... keys) { + + if (MapUtils.isEmpty(data)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Arrays.stream(keys) + .forEach( + key -> { + if (data.containsKey(key)) { + throw new ProjectCommonException( + ResponseCode.unupdatableField.getErrorCode(), + ResponseCode.unupdatableField.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + key); + } + }); + } + + /** + * Method to check whether given header fields present or not. + * + * @param data List of strings representing the header names in received request. + * @param keys List of string represents the headers fields. + */ + public void checkMandatoryHeadersPresent(Map data, String... keys) { + if (MapUtils.isEmpty(data)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + Arrays.stream(keys) + .forEach( + key -> { + if (ArrayUtils.isEmpty(data.get(key))) { + throw new ProjectCommonException( + ResponseCode.mandatoryHeadersMissing.getErrorCode(), + ResponseCode.mandatoryHeadersMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + key); + } + }); + } + + /** + * Ensures not allowed fields are absent in given request. + * + * @param requestMap Request information + * @param fields List of not allowed fields + */ + public void checkForFieldsNotAllowed(Map requestMap, List fields) { + fields + .stream() + .forEach( + field -> { + if (requestMap.containsKey(field)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidRequestParameter.getErrorMessage(), field), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + } + + /** + * Helper method which throws an exception if each field is not of type List. + * + * @param requestMap Request information + * @param fieldPrefix Field prefix + * @param fields List of fields + */ + public void validateListParamWithPrefix( + Map requestMap, String fieldPrefix, String... fields) { + Arrays.stream(fields) + .forEach( + field -> { + if (requestMap.containsKey(field) + && null != requestMap.get(field) + && !(requestMap.get(field) instanceof List)) { + + String fieldWithPrefix = + fieldPrefix != null ? StringFormatter.joinByDot(fieldPrefix, field) : field; + + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), + fieldWithPrefix, + JsonKey.LIST), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + } + + /** + * Helper method which throws an exception if each field is not of type List. + * + * @param requestMap Request information + * @param fields List of fields + */ + public void validateListParam(Map requestMap, String... fields) { + validateListParamWithPrefix(requestMap, null, fields); + } + + /** + * Helper method which throws an exception if given date is not in YYYY-MM-DD format. + * + * @param dob Date of birth. + */ + public void validateDateParam(String dob) { + if (StringUtils.isNotBlank(dob)) { + boolean isValidDate = ProjectUtil.isDateValidFormat(ProjectUtil.YEAR_MONTH_DATE_FORMAT, dob); + if (!isValidDate) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } + + /** + * Helper method which throws an exception if given parameter value is blank (null or empty). + * + * @param error Error to be thrown in case of validation error. + * @param errorMsg Error message. + */ + public void validateParamValue(String value, ResponseCode error, String errorMsg) { + if (StringUtils.isBlank(value)) { + throw new ProjectCommonException( + error.getErrorCode(), + MessageFormat.format(error.getErrorMessage(), errorMsg), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + /** + * Helper method which throws an exception if user ID in request is not same as that in user + * token. + * + * @param request API request + * @param userIdKey Attribute name for user ID in API request + */ + public static void validateUserId(Request request, String userIdKey) { + if (!(request + .getRequest() + .get(userIdKey) + .equals(request.getContext().get(JsonKey.REQUESTED_BY)))) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ResponseCode.invalidParameterValue.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + (String) request.getRequest().get(JsonKey.USER_ID), + JsonKey.USER_ID); + } + } + + public void validateSearchRequest(Request request) { + if (null == request.getRequest().get(JsonKey.FILTERS)) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.FILTERS), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (request.getRequest().containsKey(JsonKey.FILTERS) + && (!(request.getRequest().get(JsonKey.FILTERS) instanceof Map))) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.FILTERS, "Map"), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + validateSearchRequestFiltersValues(request); + validateSearchRequestFieldsValues(request); + } + + private void validateSearchRequestFieldsValues(Request request) { + if (request.getRequest().containsKey(JsonKey.FIELDS) + && (!(request.getRequest().get(JsonKey.FIELDS) instanceof List))) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.FIELDS, "List"), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (request.getRequest().containsKey(JsonKey.FIELDS) + && (request.getRequest().get(JsonKey.FIELDS) instanceof List)) { + for (Object obj : (List) request.getRequest().get(JsonKey.FIELDS)) { + if (!(obj instanceof String)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.FIELDS, "List of String"), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } + } + + private void validateSearchRequestFiltersValues(Request request) { + if (request.getRequest().containsKey(JsonKey.FILTERS) + && ((request.getRequest().get(JsonKey.FILTERS) instanceof Map))) { + Map map = (Map) request.getRequest().get(JsonKey.FILTERS); + + map.forEach( + (key, val) -> { + if (key == null) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), key, JsonKey.FILTERS), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (val instanceof List) { + validateListValues((List) val, key); + } else if (val instanceof Map) { + validateMapValues((Map) val); + } else if (val == null) + if (StringUtils.isEmpty((String) val)) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), val, key), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + } + } + + private void validateMapValues(Map val) { + val.forEach( + (k, v) -> { + if (k == null || v == null) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + MessageFormat.format(ResponseCode.invalidParameterValue.getErrorMessage(), v, k), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + } + + private void validateListValues(List val, String key) { + val.forEach( + v -> { + if (v == null) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + MessageFormat.format(ResponseCode.invalidParameterValue.getErrorMessage(), v, key), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + }); + } + + public void validateEmail(String email) { + if (!EmailValidator.isEmailValid(email)) { + throw new ProjectCommonException( + ResponseCode.emailFormatError.getErrorCode(), + ResponseCode.emailFormatError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + public void validatePhone(String phone) { + if (!ProjectUtil.validatePhone(phone, null)) { + throw new ProjectCommonException( + ResponseCode.phoneNoFormatError.getErrorCode(), + ResponseCode.phoneNoFormatError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/ExecutionContext.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/ExecutionContext.java new file mode 100644 index 0000000000..c85050b02f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/ExecutionContext.java @@ -0,0 +1,147 @@ +package org.sunbird.common.request; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.PropertiesCache; + +/** @author Manzarul */ +public class ExecutionContext { + + public static final String USER_ID = "userId"; + public static final String USER_ROLE = "userRole"; + private Stack serviceCallStack = new Stack<>(); + + private Map> contextStackValues = new HashMap<>(); + private Map globalContext = new HashMap<>(); + private Map requestContext = new HashMap<>(); + + public Map getRequestContext() { + return requestContext; + } + + public void setRequestContext(Map requestContext) { + this.requestContext = requestContext; + initializeGlobalContext(ExecutionContext.getCurrent()); + } + + private static ThreadLocal context = + new ThreadLocal() { + + @Override + protected ExecutionContext initialValue() { + ExecutionContext context = new ExecutionContext(); + return context; + } + }; + + private static void initializeGlobalContext(ExecutionContext context) { + context.getGlobalContext().put(JsonKey.PDATA_ID, getContextValue(JsonKey.PDATA_ID)); + context.getGlobalContext().put(JsonKey.PDATA_PID, getContextValue(JsonKey.PDATA_PID)); + context.getGlobalContext().put(JsonKey.PDATA_VERSION, getContextValue(JsonKey.PDATA_VERSION)); + } + + private static String getContextValue(String key) { + String value = System.getenv(key); + if (StringUtils.isBlank(value)) { + value = PropertiesCache.getInstance().getProperty(key); + } + return value; + } + + public static ExecutionContext getCurrent() { + return context.get(); + } + + public static void setRequestId(String requestId) { + ExecutionContext.getCurrent() + .getGlobalContext() + .put(HeaderParam.REQUEST_ID.getParamName(), requestId); + } + + public static String getRequestId() { + return (String) + ExecutionContext.getCurrent().getGlobalContext().get(HeaderParam.REQUEST_ID.getParamName()); + } + + public Map getContextValues() { + String serviceCallStack = getServiceCallStack(); + Map contextValues = contextStackValues.get(serviceCallStack); + if (contextValues == null) { + contextValues = new HashMap<>(); + setContextValues(contextValues, serviceCallStack); + } + + return contextStackValues.get(serviceCallStack); + } + + public void setContextValues(Map currentContextValues) { + this.contextStackValues.put( + getServiceCallStack(), new HashMap(currentContextValues)); + } + + public void setContextValues(Map currentContextValues, String serviceCallStack) { + this.contextStackValues.put( + serviceCallStack, new HashMap(currentContextValues)); + } + + public void removeContext() { + this.contextStackValues.remove(getServiceCallStack()); + } + + public void cleanup() { + removeContext(); + pop(); + if (serviceCallStack.size() == 0) { + this.globalContext.remove(HeaderParam.REQUEST_ST_ED_PATH.getParamName()); + } + } + + // TODO move Response out of context + public Response getResponse() { + Response contextResponse = + (Response) ExecutionContext.getCurrent().getContextValues().get("RESPONSE"); + if (contextResponse == null) { + contextResponse = new Response(); + ExecutionContext.getCurrent().getContextValues().put("RESPONSE", contextResponse); + } + return contextResponse; + } + + public void push(String methodName) { + serviceCallStack.push(methodName); + } + + public String pop() { + return serviceCallStack.pop(); + } + + public String peek() { + return serviceCallStack.peek(); + } + + public String getServiceCallStack() { + String serviceCallPath = ""; + for (String value : serviceCallStack) { + if ("".equals(serviceCallPath)) serviceCallPath = value; + else serviceCallPath = serviceCallPath + "/" + value; + } + + if ("".equals(serviceCallPath)) { + serviceCallStack.push("default"); + return "default"; + } + return serviceCallPath; + } + + public Map getGlobalContext() { + return globalContext; + } + + public void setGlobalContext(Map globalContext) { + this.globalContext = globalContext; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/HeaderParam.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/HeaderParam.java new file mode 100644 index 0000000000..9d3fc6ec3f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/HeaderParam.java @@ -0,0 +1,69 @@ +package org.sunbird.common.request; + +/** + * The keys of the Execution Context Values. + * + * @author Manzarul + */ +public enum HeaderParam { + REQUEST_ID, + REQUEST_PATH, + REQUEST_ST_ED_PATH, + CURRENT_INVOCATION_PATH, + USER_DATA, + USER_LOCALE, + SYSTEM_LOCALE, + USER_ID, + PROXY_USER_ID, + USER_NAME, + PROXY_USER_NAME, + SCOPE_ID, + X_Consumer_ID("x-consumer-id"), + X_Session_ID("x-session-id"), + X_Device_ID("x-device-id"), + X_Authenticated_Userid("x-authenticated-userid"), + ts("ts"), + Content_Type("content-type"), + X_Authenticated_User_Token("x-authenticated-user-token"), + X_Authenticated_For("x-authenticated-for"), + X_Authenticated_Client_Token("x-authenticated-client-token"), + X_Authenticated_Client_Id("x-authenticated-client-id"), + X_APP_ID("x-app-id"), + CHANNEL_ID("x-channel-id"), + X_Response_Length("x-response-length"); + /** name of the parameter */ + private String name; + + /** + * 1-arg constructor + * + * @param name String + */ + private HeaderParam(String name) { + this.name = name; + } + + /** + * this will return parameter default name + * + * @return + */ + public String getParamName() { + return this.name(); + } + + private HeaderParam() {} + + /** + * This will provide name of one argument enum + * + * @return String + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/Request.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/Request.java new file mode 100644 index 0000000000..22f25cfbac --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/Request.java @@ -0,0 +1,169 @@ +package org.sunbird.common.request; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Map; +import java.util.WeakHashMap; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Request implements Serializable { + + private static final long serialVersionUID = -2362783406031347676L; + private static final Integer MIN_TIMEOUT = 0; + private static final Integer MAX_TIMEOUT = 30; + private static final int WAIT_TIME_VALUE = 30; + + protected Map context; + + private String id; + private String ver; + private String ts; + private RequestParams params; + + private Map request = new WeakHashMap<>(); + + private String managerName; + private String operation; + private String requestId; + private int env; + + private Integer timeout; // in seconds + + public Request() { + this.context = new WeakHashMap<>(); + this.params = new RequestParams(); + } + + public void toLower() { + Arrays.asList( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_API_REQUEST_LOWER_CASE_FIELDS).split(",")) + .stream() + .forEach( + field -> { + if (StringUtils.isNotBlank((String) this.getRequest().get(field))) { + this.getRequest().put(field, ((String) this.getRequest().get(field)).toLowerCase()); + } + }); + } + + public String getRequestId() { + return requestId; + } + + public Map getContext() { + return context; + } + + public void setContext(Map context) { + this.context = context; + } + + /** @return the requestValueObjects */ + public Map getRequest() { + return request; + } + + public void setRequest(Map request) { + this.request = request; + } + + public Object get(String key) { + return request.get(key); + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public void put(String key, Object vo) { + request.put(key, vo); + } + + public String getManagerName() { + return managerName; + } + + public void setManagerName(String managerName) { + this.managerName = managerName; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + @Override + public String toString() { + return "Request [" + + (context != null ? "context=" + context + ", " : "") + + (request != null ? "requestValueObjects=" + request : "") + + "]"; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getVer() { + return ver; + } + + public void setVer(String ver) { + this.ver = ver; + } + + public String getTs() { + return ts; + } + + public void setTs(String ts) { + this.ts = ts; + } + + public RequestParams getParams() { + return params; + } + + public void setParams(RequestParams params) { + this.params = params; + if (this.params.getMsgid() == null && requestId != null) this.params.setMsgid(requestId); + } + + /** @return the env */ + public int getEnv() { + return env; + } + + /** @param env the env to set */ + public void setEnv(int env) { + this.env = env; + } + + public Integer getTimeout() { + return timeout == null ? WAIT_TIME_VALUE : timeout; + } + + public void setTimeout(Integer timeout) { + if (timeout < MIN_TIMEOUT && timeout > MAX_TIMEOUT) { + ProjectCommonException.throwServerErrorException( + ResponseCode.invalidRequestTimeout, + MessageFormat.format(ResponseCode.invalidRequestTimeout.getErrorMessage(), timeout)); + } + this.timeout = timeout; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/RequestParams.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/RequestParams.java new file mode 100644 index 0000000000..92ff599a86 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/RequestParams.java @@ -0,0 +1,77 @@ +package org.sunbird.common.request; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; + +/** @author rayulu */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class RequestParams implements Serializable { + + private static final long serialVersionUID = -759588115950763188L; + + private String did; + private String key; + private String msgid; + private String uid; + private String cid; + private String sid; + private String authToken; + + /** @return the authToken */ + public String getAuthToken() { + return authToken; + } + + /** @param authToken the authToken to set */ + public void setAuthToken(String authToken) { + this.authToken = authToken; + } + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getDid() { + return did; + } + + public void setDid(String did) { + this.did = did; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getMsgid() { + return msgid; + } + + public void setMsgid(String msgid) { + this.msgid = msgid; + } + + public String getCid() { + return cid; + } + + public void setCid(String cid) { + this.cid = cid; + } + + public String getSid() { + return sid; + } + + public void setSid(String sid) { + this.sid = sid; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/RequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/RequestValidator.java new file mode 100644 index 0000000000..78801efea0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/RequestValidator.java @@ -0,0 +1,985 @@ +package org.sunbird.common.request; + +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.ProjectUtil.ProgressStatus; +import org.sunbird.common.models.util.ProjectUtil.Source; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.StringFormatter; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; + +/** + * This call will do validation for all incoming request data. + * + * @author Manzarul + */ +public final class RequestValidator { + private static final int ERROR_CODE = ResponseCode.CLIENT_ERROR.getResponseCode(); + + private RequestValidator() {} + + /** + * This method will do content state request data validation. if all mandatory data is coming then + * it won't do any thing if any mandatory data is missing then it will throw exception. + * + * @param contentRequestDto Request + */ + @SuppressWarnings("unchecked") + public static void validateUpdateContent(Request contentRequestDto) { + List> list = + (List>) (contentRequestDto.getRequest().get(JsonKey.CONTENTS)); + if (CollectionUtils.isNotEmpty(list)) { + for (Map map : list) { + if (null != map.get(JsonKey.LAST_UPDATED_TIME)) { + boolean bool = + ProjectUtil.isDateValidFormat( + "yyyy-MM-dd HH:mm:ss:SSSZ", (String) map.get(JsonKey.LAST_UPDATED_TIME)); + if (!bool) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ERROR_CODE); + } + } + if (null != map.get(JsonKey.LAST_COMPLETED_TIME)) { + boolean bool = + ProjectUtil.isDateValidFormat( + "yyyy-MM-dd HH:mm:ss:SSSZ", (String) map.get(JsonKey.LAST_COMPLETED_TIME)); + if (!bool) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ERROR_CODE); + } + } + if (map.containsKey(JsonKey.CONTENT_ID)) { + + if (null == map.get(JsonKey.CONTENT_ID)) { + throw new ProjectCommonException( + ResponseCode.contentIdRequired.getErrorCode(), + ResponseCode.contentIdRequiredError.getErrorMessage(), + ERROR_CODE); + } + if (ProjectUtil.isNull(map.get(JsonKey.STATUS))) { + throw new ProjectCommonException( + ResponseCode.contentStatusRequired.getErrorCode(), + ResponseCode.contentStatusRequired.getErrorMessage(), + ERROR_CODE); + } + + } else { + throw new ProjectCommonException( + ResponseCode.contentIdRequired.getErrorCode(), + ResponseCode.contentIdRequiredError.getErrorMessage(), + ERROR_CODE); + } + } + } + List> assessmentData = + (List>) contentRequestDto.getRequest().get(JsonKey.ASSESSMENT_EVENTS); + if (!CollectionUtils.isEmpty(assessmentData)) { + for (Map map : assessmentData) { + if (!map.containsKey(JsonKey.ASSESSMENT_TS)) { + throw new ProjectCommonException( + ResponseCode.assessmentAttemptDateRequired.getErrorCode(), + ResponseCode.assessmentAttemptDateRequired.getErrorMessage(), + ERROR_CODE); + } + + if (!map.containsKey(JsonKey.COURSE_ID) + || StringUtils.isBlank((String) map.get(JsonKey.COURSE_ID))) { + throw new ProjectCommonException( + ResponseCode.courseIdRequired.getErrorCode(), + ResponseCode.courseIdRequiredError.getErrorMessage(), + ERROR_CODE); + } + + if (!map.containsKey(JsonKey.CONTENT_ID) + || StringUtils.isBlank((String) map.get(JsonKey.CONTENT_ID))) { + throw new ProjectCommonException( + ResponseCode.contentIdRequired.getErrorCode(), + ResponseCode.contentIdRequiredError.getErrorMessage(), + ERROR_CODE); + } + + if (!map.containsKey(JsonKey.BATCH_ID) + || StringUtils.isBlank((String) map.get(JsonKey.BATCH_ID))) { + throw new ProjectCommonException( + ResponseCode.courseBatchIdRequired.getErrorCode(), + ResponseCode.courseBatchIdRequired.getErrorMessage(), + ERROR_CODE); + } + + if (!map.containsKey(JsonKey.USER_ID) + || StringUtils.isBlank((String) map.get(JsonKey.USER_ID))) { + throw new ProjectCommonException( + ResponseCode.userIdRequired.getErrorCode(), + ResponseCode.userIdRequired.getErrorMessage(), + ERROR_CODE); + } + + if (!map.containsKey(JsonKey.ATTEMPT_ID) + || StringUtils.isBlank((String) map.get(JsonKey.ATTEMPT_ID))) { + throw new ProjectCommonException( + ResponseCode.attemptIdRequired.getErrorCode(), + ResponseCode.attemptIdRequired.getErrorMessage(), + ERROR_CODE); + } + + if (!map.containsKey(JsonKey.EVENTS)) { + throw new ProjectCommonException( + ResponseCode.eventsRequired.getErrorCode(), + ResponseCode.eventsRequired.getErrorMessage(), + ERROR_CODE); + } + } + } + } + + /** + * This method will validate get page data api. + * + * @param request Request + */ + public static void validateGetPageData(Request request) { + if (request == null || (StringUtils.isBlank((String) request.get(JsonKey.SOURCE)))) { + throw new ProjectCommonException( + ResponseCode.sourceRequired.getErrorCode(), + ResponseCode.sourceRequired.getErrorMessage(), + ERROR_CODE); + } + if (!validPageSourceType((String) request.get(JsonKey.SOURCE))) { + throw new ProjectCommonException( + ResponseCode.invalidPageSource.getErrorCode(), + ResponseCode.invalidPageSource.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank((String) request.get(JsonKey.PAGE_NAME))) { + throw new ProjectCommonException( + ResponseCode.pageNameRequired.getErrorCode(), + ResponseCode.pageNameRequired.getErrorMessage(), + ERROR_CODE); + } + } + + private static boolean validPageSourceType(String source) { + + Boolean isValidSource = false; + for (Source src : ProjectUtil.Source.values()) { + if (src.getValue().equalsIgnoreCase(source)) { + isValidSource = true; + break; + } + } + return isValidSource; + } + + /** + * This method will validate add course request data. + * + * @param courseRequest Request + */ + public static void validateAddBatchCourse(Request courseRequest) { + + if (courseRequest.getRequest().get(JsonKey.BATCH_ID) == null) { + throw new ProjectCommonException( + ResponseCode.courseBatchIdRequired.getErrorCode(), + ResponseCode.courseBatchIdRequired.getErrorMessage(), + ERROR_CODE); + } + if (courseRequest.getRequest().get(JsonKey.USER_IDs) == null) { + throw new ProjectCommonException( + ResponseCode.userIdRequired.getErrorCode(), + ResponseCode.userIdRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate add course request data. + * + * @param courseRequest Request + */ + public static void validateGetBatchCourse(Request courseRequest) { + + if (courseRequest.getRequest().get(JsonKey.BATCH_ID) == null) { + throw new ProjectCommonException( + ResponseCode.courseBatchIdRequired.getErrorCode(), + ResponseCode.courseBatchIdRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate update course request data. + * + * @param request Request + */ + public static void validateUpdateCourse(Request request) { + + if (request.getRequest().get(JsonKey.COURSE_ID) == null) { + throw new ProjectCommonException( + ResponseCode.courseIdRequired.getErrorCode(), + ResponseCode.courseIdRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate published course request data. + * + * @param request Request + */ + public static void validatePublishCourse(Request request) { + if (request.getRequest().get(JsonKey.COURSE_ID) == null) { + throw new ProjectCommonException( + ResponseCode.courseIdRequiredError.getErrorCode(), + ResponseCode.courseIdRequiredError.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate Delete course request data. + * + * @param request Request + */ + public static void validateDeleteCourse(Request request) { + if (request.getRequest().get(JsonKey.COURSE_ID) == null) { + throw new ProjectCommonException( + ResponseCode.courseIdRequiredError.getErrorCode(), + ResponseCode.courseIdRequiredError.getErrorMessage(), + ERROR_CODE); + } + } + + /* + * This method will validate create section data + * + * @param userRequest Request + */ + public static void validateCreateSection(Request request) { + if (StringUtils.isBlank( + (String) + (request.getRequest().get(JsonKey.SECTION_NAME) != null + ? request.getRequest().get(JsonKey.SECTION_NAME) + : ""))) { + throw new ProjectCommonException( + ResponseCode.sectionNameRequired.getErrorCode(), + ResponseCode.sectionNameRequired.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank( + (String) + (request.getRequest().get(JsonKey.SECTION_DATA_TYPE) != null + ? request.getRequest().get(JsonKey.SECTION_DATA_TYPE) + : ""))) { + throw new ProjectCommonException( + ResponseCode.sectionDataTypeRequired.getErrorCode(), + ResponseCode.sectionDataTypeRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate update section request data + * + * @param request Request + */ + public static void validateUpdateSection(Request request) { + if (request.getRequest().containsKey(JsonKey.SECTION_NAME) + && StringUtils.isBlank( + (String) + (request.getRequest().get(JsonKey.SECTION_NAME) != null + ? request.getRequest().get(JsonKey.SECTION_NAME) + : ""))) { + throw new ProjectCommonException( + ResponseCode.sectionNameRequired.getErrorCode(), + ResponseCode.sectionNameRequired.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank( + (String) + (request.getRequest().get(JsonKey.ID) != null + ? request.getRequest().get(JsonKey.ID) + : ""))) { + throw new ProjectCommonException( + ResponseCode.sectionIdRequired.getErrorCode(), + ResponseCode.sectionIdRequired.getErrorMessage(), + ERROR_CODE); + } + if (request.getRequest().containsKey(JsonKey.SECTION_DATA_TYPE) + && StringUtils.isBlank( + (String) + (request.getRequest().get(JsonKey.SECTION_DATA_TYPE) != null + ? request.getRequest().get(JsonKey.SECTION_DATA_TYPE) + : ""))) { + throw new ProjectCommonException( + ResponseCode.sectionDataTypeRequired.getErrorCode(), + ResponseCode.sectionDataTypeRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate create page data + * + * @param request Request + */ + public static void validateCreatePage(Request request) { + if (StringUtils.isEmpty( + (String) + (request.getRequest().get(JsonKey.PAGE_NAME) != null + ? request.getRequest().get(JsonKey.PAGE_NAME) + : ""))) { + throw new ProjectCommonException( + ResponseCode.pageNameRequired.getErrorCode(), + ResponseCode.pageNameRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate update page request data + * + * @param request Request + */ + public static void validateUpdatepage(Request request) { + if (request.getRequest().containsKey(JsonKey.PAGE_NAME) + && StringUtils.isEmpty( + (String) + (request.getRequest().get(JsonKey.PAGE_NAME) != null + ? request.getRequest().get(JsonKey.PAGE_NAME) + : ""))) { + throw new ProjectCommonException( + ResponseCode.pageNameRequired.getErrorCode(), + ResponseCode.pageNameRequired.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank( + (String) + (request.getRequest().get(JsonKey.ID) != null + ? request.getRequest().get(JsonKey.ID) + : ""))) { + throw new ProjectCommonException( + ResponseCode.pageIdRequired.getErrorCode(), + ResponseCode.pageIdRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate bulk user upload requested data. + * + * @param reqObj Request + */ + public static void validateUploadUser(Map reqObj) { + if (StringUtils.isBlank((String) reqObj.get(JsonKey.ORGANISATION_ID)) + && (StringUtils.isBlank((String) reqObj.get(JsonKey.ORG_EXTERNAL_ID)) + || StringUtils.isBlank((String) reqObj.get(JsonKey.ORG_PROVIDER)))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + (ProjectUtil.formatMessage( + ResponseMessage.Message.OR_FORMAT, + JsonKey.ORGANISATION_ID, + ProjectUtil.formatMessage( + ResponseMessage.Message.AND_FORMAT, + JsonKey.ORG_EXTERNAL_ID, + JsonKey.ORG_PROVIDER)))), + ERROR_CODE); + } + if (null == reqObj.get(JsonKey.FILE)) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.FILE), + ERROR_CODE); + } + } + + /** + * courseId : Should be a valid courseId under EKStep. name : should not be null or empty + * enrolmentType: can have only following two values {"open","invite-only"} startDate : In + * yyyy-MM-DD format , and must be >= today date. endDate : In yyyy-MM-DD format and must be > + * startDate createdFor : List of valid organisation ids. this filed will be used in case of + * "invite-only" enrolmentType. for open type if createdFor values is coming then system will just + * save that value. mentors : List of user ids , who will work as a mentor. + * + * @param request + */ + public static void validateCreateBatchReq(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.COURSE_ID))) { + throw new ProjectCommonException( + ResponseCode.invalidCourseId.getErrorCode(), + ResponseCode.invalidCourseId.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.NAME))) { + throw new ProjectCommonException( + ResponseCode.courseNameRequired.getErrorCode(), + ResponseCode.courseNameRequired.getErrorMessage(), + ERROR_CODE); + } + String enrolmentType = (String) request.getRequest().get(JsonKey.ENROLLMENT_TYPE); + validateEnrolmentType(enrolmentType); + String startDate = (String) request.getRequest().get(JsonKey.START_DATE); + String endDate = (String) request.getRequest().get(JsonKey.END_DATE); + validateStartDate(startDate); + validateEndDate(startDate, endDate); + + if (request.getRequest().containsKey(JsonKey.COURSE_CREATED_FOR) + && !(request.getRequest().get(JsonKey.COURSE_CREATED_FOR) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ResponseCode.dataTypeError.getErrorMessage(), + ERROR_CODE); + } + } + + private static boolean checkProgressStatus(int status) { + for (ProgressStatus pstatus : ProgressStatus.values()) { + if (pstatus.getValue() == status) { + return true; + } + } + return false; + } + + public static void validateUpdateCourseBatchReq(Request request) { + + if (null != request.getRequest().get(JsonKey.STATUS)) { + boolean status = validateBatchStatus(request); + if (!status) { + throw new ProjectCommonException( + ResponseCode.progressStatusError.getErrorCode(), + ResponseCode.progressStatusError.getErrorMessage(), + ERROR_CODE); + } + } + if (request.getRequest().containsKey(JsonKey.NAME) + && StringUtils.isEmpty((String) request.getRequest().get(JsonKey.NAME))) { + throw new ProjectCommonException( + ResponseCode.courseNameRequired.getErrorCode(), + ResponseCode.courseNameRequired.getErrorMessage(), + ERROR_CODE); + } + if (request.getRequest().containsKey(JsonKey.ENROLLMENT_TYPE)) { + String enrolmentType = (String) request.getRequest().get(JsonKey.ENROLLMENT_TYPE); + validateEnrolmentType(enrolmentType); + } + String startDate = (String) request.getRequest().get(JsonKey.START_DATE); + String endDate = (String) request.getRequest().get(JsonKey.END_DATE); + + validateUpdateBatchStartDate(startDate); + validateEndDate(startDate, endDate); + + boolean bool = validateDateWithTodayDate(endDate); + if (!bool) { + throw new ProjectCommonException( + ResponseCode.invalidBatchEndDateError.getErrorCode(), + ResponseCode.invalidBatchEndDateError.getErrorMessage(), + ERROR_CODE); + } + + validateUpdateBatchEndDate(request); + if (request.getRequest().containsKey(JsonKey.COURSE_CREATED_FOR) + && !(request.getRequest().get(JsonKey.COURSE_CREATED_FOR) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ResponseCode.dataTypeError.getErrorMessage(), + ERROR_CODE); + } + + if (request.getRequest().containsKey(JsonKey.MENTORS) + && !(request.getRequest().get(JsonKey.MENTORS) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ResponseCode.dataTypeError.getErrorMessage(), + ERROR_CODE); + } + } + + private static void validateUpdateBatchStartDate(String startDate) { + if (StringUtils.isNotBlank(startDate)) { + try { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + format.parse(startDate); + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ERROR_CODE); + } + } else { + throw new ProjectCommonException( + ResponseCode.courseBatchStartDateRequired.getErrorCode(), + ResponseCode.courseBatchStartDateRequired.getErrorMessage(), + ERROR_CODE); + } + } + + private static boolean validateBatchStatus(Request request) { + boolean status = false; + try { + status = checkProgressStatus(Integer.parseInt("" + request.getRequest().get(JsonKey.STATUS))); + + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return status; + } + + private static void validateUpdateBatchEndDate(Request request) { + + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + String startDate = (String) request.getRequest().get(JsonKey.START_DATE); + String endDate = (String) request.getRequest().get(JsonKey.END_DATE); + format.setLenient(false); + if (StringUtils.isNotBlank(endDate) && StringUtils.isNotBlank(startDate)) { + Date batchStartDate = null; + Date batchEndDate = null; + try { + batchStartDate = format.parse(startDate); + batchEndDate = format.parse(endDate); + Calendar cal1 = Calendar.getInstance(); + Calendar cal2 = Calendar.getInstance(); + cal1.setTime(batchStartDate); + cal2.setTime(batchEndDate); + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ERROR_CODE); + } + if (batchEndDate.before(batchStartDate)) { + throw new ProjectCommonException( + ResponseCode.invalidBatchEndDateError.getErrorCode(), + ResponseCode.invalidBatchEndDateError.getErrorMessage(), + ERROR_CODE); + } + } + } + + private static boolean validateDateWithTodayDate(String date) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + format.setLenient(false); + try { + if (StringUtils.isNotEmpty(date)) { + Date reqDate = format.parse(date); + Date todayDate = format.parse(format.format(new Date())); + Calendar cal1 = Calendar.getInstance(); + Calendar cal2 = Calendar.getInstance(); + cal1.setTime(reqDate); + cal2.setTime(todayDate); + if (reqDate.before(todayDate)) { + return false; + } + } + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ERROR_CODE); + } + return true; + } + + /** @param enrolmentType */ + public static void validateEnrolmentType(String enrolmentType) { + if (StringUtils.isBlank(enrolmentType)) { + throw new ProjectCommonException( + ResponseCode.enrolmentTypeRequired.getErrorCode(), + ResponseCode.enrolmentTypeRequired.getErrorMessage(), + ERROR_CODE); + } + if (!(ProjectUtil.EnrolmentType.open.getVal().equalsIgnoreCase(enrolmentType) + || ProjectUtil.EnrolmentType.inviteOnly.getVal().equalsIgnoreCase(enrolmentType))) { + throw new ProjectCommonException( + ResponseCode.enrolmentIncorrectValue.getErrorCode(), + ResponseCode.enrolmentIncorrectValue.getErrorMessage(), + ERROR_CODE); + } + } + + /** @param startDate */ + private static void validateStartDate(String startDate) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + format.setLenient(false); + if (StringUtils.isBlank(startDate)) { + throw new ProjectCommonException( + ResponseCode.courseBatchStartDateRequired.getErrorCode(), + ResponseCode.courseBatchStartDateRequired.getErrorMessage(), + ERROR_CODE); + } + try { + Date batchStartDate = format.parse(startDate); + Date todayDate = format.parse(format.format(new Date())); + Calendar cal1 = Calendar.getInstance(); + Calendar cal2 = Calendar.getInstance(); + cal1.setTime(batchStartDate); + cal2.setTime(todayDate); + if (batchStartDate.before(todayDate)) { + throw new ProjectCommonException( + ResponseCode.courseBatchStartDateError.getErrorCode(), + ResponseCode.courseBatchStartDateError.getErrorMessage(), + ERROR_CODE); + } + } catch (ProjectCommonException e) { + throw e; + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ERROR_CODE); + } + } + + private static void validateEndDate(String startDate, String endDate) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + format.setLenient(false); + Date batchEndDate = null; + Date batchStartDate = null; + try { + if (StringUtils.isNotEmpty(endDate)) { + batchEndDate = format.parse(endDate); + batchStartDate = format.parse(startDate); + } + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.dateFormatError.getErrorCode(), + ResponseCode.dateFormatError.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isNotEmpty(endDate) && batchStartDate.getTime() >= batchEndDate.getTime()) { + throw new ProjectCommonException( + ResponseCode.endDateError.getErrorCode(), + ResponseCode.endDateError.getErrorMessage(), + ERROR_CODE); + } + } + + public static void validateSyncRequest(Request request) { + String operation = (String) request.getRequest().get(JsonKey.OPERATION_FOR); + if ((null != operation) && (!operation.equalsIgnoreCase("keycloak"))) { + if (request.getRequest().get(JsonKey.OBJECT_TYPE) == null) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ResponseCode.dataTypeError.getErrorMessage(), + ERROR_CODE); + } + List list = + new ArrayList<>( + Arrays.asList( + new String[] { + JsonKey.USER, JsonKey.ORGANISATION, JsonKey.BATCH, JsonKey.USER_COURSE + })); + if (!list.contains(request.getRequest().get(JsonKey.OBJECT_TYPE))) { + throw new ProjectCommonException( + ResponseCode.invalidObjectType.getErrorCode(), + ResponseCode.invalidObjectType.getErrorMessage(), + ERROR_CODE); + } + } + } + + public static void validateUpdateSystemSettingsRequest(Request request) { + List list = + new ArrayList<>( + Arrays.asList( + PropertiesCache.getInstance() + .getProperty("system_settings_properties") + .split(","))); + for (String str : request.getRequest().keySet()) { + if (!list.contains(str)) { + throw new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + MessageFormat.format(ResponseCode.invalidPropertyError.getErrorMessage(), str), + ERROR_CODE); + } + } + } + + public static void validateSendMail(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.SUBJECT))) { + throw new ProjectCommonException( + ResponseCode.emailSubjectError.getErrorCode(), + ResponseCode.emailSubjectError.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.BODY))) { + throw new ProjectCommonException( + ResponseCode.emailBodyError.getErrorCode(), + ResponseCode.emailBodyError.getErrorMessage(), + ERROR_CODE); + } + if (CollectionUtils.isEmpty((List) (request.getRequest().get(JsonKey.RECIPIENT_EMAILS))) + && CollectionUtils.isEmpty( + (List) (request.getRequest().get(JsonKey.RECIPIENT_USERIDS))) + && MapUtils.isEmpty( + (Map) (request.getRequest().get(JsonKey.RECIPIENT_SEARCH_QUERY))) + && CollectionUtils.isEmpty( + (List) (request.getRequest().get(JsonKey.RECIPIENT_PHONES)))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + StringFormatter.joinByOr( + StringFormatter.joinByComma( + JsonKey.RECIPIENT_EMAILS, + JsonKey.RECIPIENT_USERIDS, + JsonKey.RECIPIENT_PHONES), + JsonKey.RECIPIENT_SEARCH_QUERY)), + ERROR_CODE); + } + } + + public static void validateFileUpload(Request reqObj) { + + if (StringUtils.isBlank((String) reqObj.get(JsonKey.CONTAINER))) { + throw new ProjectCommonException( + ResponseCode.storageContainerNameMandatory.getErrorCode(), + ResponseCode.storageContainerNameMandatory.getErrorMessage(), + ERROR_CODE); + } + } + + /** @param reqObj */ + public static void validateCreateOrgType(Request reqObj) { + if (StringUtils.isBlank((String) reqObj.getRequest().get(JsonKey.NAME))) { + throw createExceptionInstance(ResponseCode.orgTypeMandatory.getErrorCode()); + } + } + + /** @param reqObj */ + public static void validateUpdateOrgType(Request reqObj) { + if (StringUtils.isBlank((String) reqObj.getRequest().get(JsonKey.NAME))) { + throw createExceptionInstance(ResponseCode.orgTypeMandatory.getErrorCode()); + } + if (StringUtils.isBlank((String) reqObj.getRequest().get(JsonKey.ID))) { + throw createExceptionInstance(ResponseCode.orgTypeIdRequired.getErrorCode()); + } + } + + /** + * Method to validate not for userId, title, note, courseId, contentId and tags + * + * @param request + */ + @SuppressWarnings("rawtypes") + public static void validateNote(Request request) { + if (StringUtils.isBlank((String) request.get(JsonKey.USER_ID))) { + throw new ProjectCommonException( + ResponseCode.userIdRequired.getErrorCode(), + ResponseCode.userIdRequired.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank((String) request.get(JsonKey.TITLE))) { + throw new ProjectCommonException( + ResponseCode.titleRequired.getErrorCode(), + ResponseCode.titleRequired.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank((String) request.get(JsonKey.NOTE))) { + throw new ProjectCommonException( + ResponseCode.noteRequired.getErrorCode(), + ResponseCode.noteRequired.getErrorMessage(), + ERROR_CODE); + } + if (StringUtils.isBlank((String) request.get(JsonKey.CONTENT_ID)) + && StringUtils.isBlank((String) request.get(JsonKey.COURSE_ID))) { + throw new ProjectCommonException( + ResponseCode.contentIdError.getErrorCode(), + ResponseCode.contentIdError.getErrorMessage(), + ERROR_CODE); + } + if (request.getRequest().containsKey(JsonKey.TAGS) + && ((request.getRequest().get(JsonKey.TAGS) instanceof List) + && ((List) request.getRequest().get(JsonKey.TAGS)).isEmpty())) { + throw new ProjectCommonException( + ResponseCode.invalidTags.getErrorCode(), + ResponseCode.invalidTags.getErrorMessage(), + ERROR_CODE); + } else if (request.getRequest().get(JsonKey.TAGS) instanceof String) { + throw new ProjectCommonException( + ResponseCode.invalidTags.getErrorCode(), + ResponseCode.invalidTags.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * Method to validate noteId + * + * @param noteId + */ + public static void validateNoteId(String noteId) { + if (StringUtils.isBlank(noteId)) { + throw createExceptionInstance(ResponseCode.invalidNoteId.getErrorCode()); + } + } + + /** + * Method to validate + * + * @param request + */ + public static void validateRegisterClient(Request request) { + + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.CLIENT_NAME))) { + throw createExceptionInstance(ResponseCode.invalidClientName.getErrorCode()); + } + } + + /** + * Method to validate the request for updating the client key + * + * @param clientId + * @param masterAccessToken + */ + public static void validateUpdateClientKey(String clientId, String masterAccessToken) { + validateClientId(clientId); + if (StringUtils.isBlank(masterAccessToken)) { + throw createExceptionInstance(ResponseCode.invalidRequestData.getErrorCode()); + } + } + + /** + * Method to validate the request for updating the client key + * + * @param id + * @param type + */ + public static void validateGetClientKey(String id, String type) { + validateClientId(id); + if (StringUtils.isBlank(type)) { + throw createExceptionInstance(ResponseCode.invalidRequestData.getErrorCode()); + } + } + + /** + * Method to validate clientId. + * + * @param clientId + */ + public static void validateClientId(String clientId) { + if (StringUtils.isBlank(clientId)) { + throw createExceptionInstance(ResponseCode.invalidClientId.getErrorCode()); + } + } + + /** + * Method to validate notification request data. + * + * @param request Request + */ + @SuppressWarnings("unchecked") + public static void validateSendNotification(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.TO))) { + throw createExceptionInstance(ResponseCode.invalidTopic.getErrorCode()); + } + if (request.getRequest().get(JsonKey.DATA) == null + || !(request.getRequest().get(JsonKey.DATA) instanceof Map) + || ((Map) request.getRequest().get(JsonKey.DATA)).size() == 0) { + throw createExceptionInstance(ResponseCode.invalidTopicData.getErrorCode()); + } + + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.TYPE))) { + throw createExceptionInstance(ResponseCode.invalidNotificationType.getErrorCode()); + } + if (!(JsonKey.FCM.equalsIgnoreCase((String) request.getRequest().get(JsonKey.TYPE)))) { + throw createExceptionInstance(ResponseCode.notificationTypeSupport.getErrorCode()); + } + } + + @SuppressWarnings("rawtypes") + public static void validateGetUserCount(Request request) { + if (!validateListType(request, JsonKey.LOCATION_IDS)) { + throw createDataTypeException( + ResponseCode.dataTypeError.getErrorCode(), JsonKey.LOCATION_IDS, JsonKey.LIST); + } + if (null == request.getRequest().get(JsonKey.LOCATION_IDS) + && ((List) request.getRequest().get(JsonKey.LOCATION_IDS)).isEmpty()) { + throw createExceptionInstance(ResponseCode.locationIdRequired.getErrorCode()); + } + + if (!validateBooleanType(request, JsonKey.USER_LIST_REQ)) { + throw createDataTypeException( + ResponseCode.dataTypeError.getErrorCode(), JsonKey.USER_LIST_REQ, "Boolean"); + } + + if (null != request.getRequest().get(JsonKey.USER_LIST_REQ) + && (Boolean) request.getRequest().get(JsonKey.USER_LIST_REQ)) { + throw createExceptionInstance(ResponseCode.functionalityMissing.getErrorCode()); + } + + if (!validateBooleanType(request, JsonKey.ESTIMATED_COUNT_REQ)) { + throw createDataTypeException( + ResponseCode.dataTypeError.getErrorCode(), JsonKey.ESTIMATED_COUNT_REQ, "Boolean"); + } + + if (null != request.getRequest().get(JsonKey.ESTIMATED_COUNT_REQ) + && (Boolean) request.getRequest().get(JsonKey.ESTIMATED_COUNT_REQ)) { + throw createExceptionInstance(ResponseCode.functionalityMissing.getErrorCode()); + } + } + + /** + * if the request contains that key and key is not instance of List then it will return false. + * other cases it will return true. + * + * @param request Request + * @param key String + * @return boolean + */ + private static boolean validateListType(Request request, String key) { + return !(request.getRequest().containsKey(key) + && null != request.getRequest().get(key) + && !(request.getRequest().get(key) instanceof List)); + } + + /** + * If the request contains the key and key value is not Boolean type then it will return false , + * for any other case it will return true. + * + * @param request Request + * @param key String + * @return boolean + */ + private static boolean validateBooleanType(Request request, String key) { + return !(request.getRequest().containsKey(key) + && null != request.getRequest().get(key) + && !(request.getRequest().get(key) instanceof Boolean)); + } + + private static ProjectCommonException createDataTypeException( + String errorCode, String key1, String key2) { + return new ProjectCommonException( + ResponseCode.getResponse(errorCode).getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.getResponse(errorCode).getErrorMessage(), key1, key2), + ERROR_CODE); + } + + private static ProjectCommonException createExceptionInstance(String errorCode) { + return new ProjectCommonException( + ResponseCode.getResponse(errorCode).getErrorCode(), + ResponseCode.getResponse(errorCode).getErrorMessage(), + ERROR_CODE); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/TelemetryV3Request.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/TelemetryV3Request.java new file mode 100644 index 0000000000..5360274a3a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/TelemetryV3Request.java @@ -0,0 +1,92 @@ +package org.sunbird.common.request; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** Created by arvind on 23/3/18. */ +public class TelemetryV3Request implements Serializable { + + private String id; + private String ver; + private Long ets; + private Params params; + + private List> events = new ArrayList<>(); + + public TelemetryV3Request() { + params = new Params(); + } + + class Params implements Serializable { + + private String did; + private String key; + private String msgid; + + public String getDid() { + return did; + } + + public void setDid(String did) { + this.did = did; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getMsgid() { + return msgid; + } + + public void setMsgid(String msgid) { + this.msgid = msgid; + } + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getVer() { + return ver; + } + + public void setVer(String ver) { + this.ver = ver; + } + + public Long getEts() { + return ets; + } + + public void setEts(Long ets) { + this.ets = ets; + } + + public Params getParams() { + return params; + } + + public void setParams(Params params) { + this.params = params; + } + + public List> getEvents() { + return events; + } + + public void setEvents(List> events) { + this.events = events; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserFreeUpRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserFreeUpRequestValidator.java new file mode 100644 index 0000000000..da7ec35e97 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserFreeUpRequestValidator.java @@ -0,0 +1,93 @@ +package org.sunbird.common.request; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; + +public class UserFreeUpRequestValidator extends BaseRequestValidator { + + private Request request; + private static List identifiers = new ArrayList<>(); + + static { + identifiers.add(JsonKey.EMAIL); + identifiers.add(JsonKey.PHONE); + } + + private static final int ERROR_CODE = ResponseCode.CLIENT_ERROR.getResponseCode(); + + /** + * this method is used to get the instance to UserFreeUpRequestValidator class + * + * @param request + * @return + */ + public static UserFreeUpRequestValidator getInstance(Request request) { + return new UserFreeUpRequestValidator(request); + } + + private UserFreeUpRequestValidator(Request request) { + this.request = request; + } + + /** this is the method we need to call to validate the IdentifierFreeUpUser request. */ + public void validate() { + validateIdPresence(); + validateIdentifier(); + } + + private void validateIdPresence() { + validateParam( + (String) request.getRequest().get(JsonKey.ID), + ResponseCode.mandatoryParamsMissing, + JsonKey.ID); + } + + private void validateIdentifier() { + validatePresence(); + validateObject(); + validateSubset(); + } + + private void validatePresence() { + if (!request.getRequest().containsKey(JsonKey.IDENTIFIER)) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.IDENTIFIER), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private void validateObject() { + Object identifierType = request.getRequest().get(JsonKey.IDENTIFIER); + if (!(identifierType instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.IDENTIFIER, JsonKey.LIST), + ERROR_CODE); + } + } + + private void validateSubset() { + List identifierVal = (List) request.getRequest().get(JsonKey.IDENTIFIER); + if (!identifiers.containsAll(identifierVal)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + String.format( + "%s %s", + ResponseCode.invalidIdentifier.getErrorMessage(), + Arrays.toString(identifiers.toArray())), + JsonKey.IDENTIFIER, + JsonKey.DATA), + ERROR_CODE); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserProfileRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserProfileRequestValidator.java new file mode 100644 index 0000000000..3ae7f5241a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserProfileRequestValidator.java @@ -0,0 +1,47 @@ +package org.sunbird.common.request; + +import java.util.List; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +public class UserProfileRequestValidator extends BaseRequestValidator { + + @SuppressWarnings("unchecked") + public void validateProfileVisibility(Request request) { + validateParam( + (String) request.getRequest().get(JsonKey.USER_ID), + ResponseCode.mandatoryParamsMissing, + JsonKey.USER_ID); + validateUserId(request, JsonKey.USER_ID); + validatePublicAndPrivateFields(request); + } + + private void validatePublicAndPrivateFields(Request request) { + List publicList = (List) request.getRequest().get(JsonKey.PUBLIC); + List privateList = (List) request.getRequest().get(JsonKey.PRIVATE); + + if (publicList == null && privateList == null) { + throw new ProjectCommonException( + ResponseCode.invalidData.getErrorCode(), + ResponseCode.invalidData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + validateListElementsAreDisjoint(publicList, privateList); + } + + private void validateListElementsAreDisjoint(List list1, List list2) { + if (list1 == null || list2 == null) { + return; + } + for (String field : list2) { + if (list1.contains(field)) { + throw new ProjectCommonException( + ResponseCode.visibilityInvalid.getErrorCode(), + ResponseCode.visibilityInvalid.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserRequestValidator.java new file mode 100644 index 0000000000..2c1545b8ac --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserRequestValidator.java @@ -0,0 +1,1120 @@ +package org.sunbird.common.request; + +import java.text.MessageFormat; +import java.util.*; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.StringFormatter; +import org.sunbird.common.responsecode.ResponseCode; + +public class UserRequestValidator extends BaseRequestValidator { + + private static final int ERROR_CODE = ResponseCode.CLIENT_ERROR.getResponseCode(); + + public void validateCreateUserRequest(Request userRequest) { + externalIdsValidation(userRequest, JsonKey.CREATE); + fieldsNotAllowed( + Arrays.asList( + JsonKey.REGISTERED_ORG_ID, + JsonKey.ROOT_ORG_ID, + JsonKey.PROVIDER, + JsonKey.EXTERNAL_ID, + JsonKey.EXTERNAL_ID_PROVIDER, + JsonKey.EXTERNAL_ID_TYPE, + JsonKey.ID_TYPE), + userRequest); + createUserBasicValidation(userRequest); + validateUserType(userRequest); + phoneValidation(userRequest); + addressValidation(userRequest); + educationValidation(userRequest); + jobProfileValidation(userRequest); + validateWebPages(userRequest); + validateLocationCodes(userRequest); + validatePassword((String) userRequest.getRequest().get(JsonKey.PASSWORD)); + } + + public static boolean isGoodPassword(String password) { + return password.matches(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_PASS_REGEX)); + } + + private static void validatePassword(String password) { + if (StringUtils.isNotBlank(password)) { + boolean response = isGoodPassword(password); + if (!response) { + throw new ProjectCommonException( + ResponseCode.passwordValidation.getErrorCode(), + ResponseCode.passwordValidation.getErrorMessage(), + ERROR_CODE); + } + } + } + + private void validateLocationCodes(Request userRequest) { + Object locationCodes = userRequest.getRequest().get(JsonKey.LOCATION_CODES); + if ((locationCodes != null) && !(locationCodes instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.LOCATION_CODES, JsonKey.LIST), + ERROR_CODE); + } + if (locationCodes != null) { + List set = new ArrayList(new HashSet<>((List) locationCodes)); + userRequest.getRequest().put(JsonKey.LOCATION_CODES, set); + } + } + + private void validateUserName(Request userRequest) { + validateParam( + (String) userRequest.getRequest().get(JsonKey.USERNAME), + ResponseCode.mandatoryParamsMissing, + JsonKey.USERNAME); + } + + public void validateUserCreateV3(Request userRequest) { + validateParam( + (String) userRequest.getRequest().get(JsonKey.FIRST_NAME), + ResponseCode.mandatoryParamsMissing, + JsonKey.FIRST_NAME); + if (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EMAIL)) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.PHONE)) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.MANAGED_BY))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.emailorPhoneorManagedByRequired); + } + + if ((StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.EMAIL)) + || StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.PHONE))) + && StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.MANAGED_BY))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.OnlyEmailorPhoneorManagedByRequired); + } + + if (StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.MANAGED_BY))) { + userRequest.getRequest().put(JsonKey.EMAIL_VERIFIED, null); + userRequest.getRequest().put(JsonKey.PHONE_VERIFIED, null); + } + phoneVerifiedValidation(userRequest); + emailVerifiedValidation(userRequest); + validatePassword((String) userRequest.getRequest().get(JsonKey.PASSWORD)); + if (StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.EMAIL))) { + validateEmail((String) userRequest.getRequest().get(JsonKey.EMAIL)); + } + if (StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.PHONE))) { + validatePhone((String) userRequest.getRequest().get(JsonKey.PHONE)); + } + } + + public void validateCreateUserV3Request(Request userRequest) { + validateCreateUserRequest(userRequest); + } + + public void validateUserCreateV4(Request userRequest) { + validateUserCreateV3(userRequest); + validateLocationCodes(userRequest); + validateFrameworkDetails(userRequest); + } + + public void validateCreateUserV1Request(Request userRequest) { + validateUserName(userRequest); + validateCreateUserV3Request(userRequest); + } + + public void validateCreateUserV2Request(Request userRequest) { + validateCreateUserRequest(userRequest); + } + + public void fieldsNotAllowed(List fields, Request userRequest) { + for (String field : fields) { + if (((userRequest.getRequest().get(field) instanceof String) + && StringUtils.isNotBlank((String) userRequest.getRequest().get(field))) + || (null != userRequest.getRequest().get(field))) { + throw new ProjectCommonException( + ResponseCode.invalidRequestParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidRequestParameter.getErrorMessage(), field), + ERROR_CODE); + } + } + } + + public void phoneValidation(Request userRequest) { + if (!StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.COUNTRY_CODE))) { + boolean bool = + ProjectUtil.validateCountryCode( + (String) userRequest.getRequest().get(JsonKey.COUNTRY_CODE)); + if (!bool) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidCountryCode); + } + } + if (StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.PHONE))) { + validatePhoneNo( + (String) userRequest.getRequest().get(JsonKey.PHONE), + (String) userRequest.getRequest().get(JsonKey.COUNTRY_CODE)); + } + phoneVerifiedValidation(userRequest); + } + + private void phoneVerifiedValidation(Request userRequest) { + if (!StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.PHONE))) { + if (null != userRequest.getRequest().get(JsonKey.PHONE_VERIFIED)) { + if (userRequest.getRequest().get(JsonKey.PHONE_VERIFIED) instanceof Boolean) { + if (!((boolean) userRequest.getRequest().get(JsonKey.PHONE_VERIFIED))) { + ProjectCommonException.throwClientErrorException(ResponseCode.phoneVerifiedError); + } + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.phoneVerifiedError); + } + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.phoneVerifiedError); + } + } + } + + /** + * This method will do basic validation for user request object. + * + * @param userRequest + */ + public void createUserBasicValidation(Request userRequest) { + + createUserBasicProfileFieldsValidation(userRequest); + if (userRequest.getRequest().containsKey(JsonKey.ROLES) + && null != userRequest.getRequest().get(JsonKey.ROLES) + && !(userRequest.getRequest().get(JsonKey.ROLES) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.ROLES, JsonKey.LIST), + ERROR_CODE); + } + if (userRequest.getRequest().containsKey(JsonKey.LANGUAGE) + && null != userRequest.getRequest().get(JsonKey.LANGUAGE) + && !(userRequest.getRequest().get(JsonKey.LANGUAGE) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.LANGUAGE, JsonKey.LIST), + ERROR_CODE); + } + } + + private void createUserBasicProfileFieldsValidation(Request userRequest) { + validateParam( + (String) userRequest.getRequest().get(JsonKey.FIRST_NAME), + ResponseCode.mandatoryParamsMissing, + JsonKey.FIRST_NAME); + if (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EMAIL)) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.PHONE)) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.MANAGED_BY))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.emailorPhoneorManagedByRequired); + } + + if ((StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.EMAIL)) + || StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.PHONE))) + && StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.MANAGED_BY))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.OnlyEmailorPhoneorManagedByRequired); + } + + if (StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.MANAGED_BY))) { + userRequest.getRequest().put(JsonKey.EMAIL_VERIFIED, null); + userRequest.getRequest().put(JsonKey.PHONE_VERIFIED, null); + } + + if (null != userRequest.getRequest().get(JsonKey.DOB)) { + boolean bool = + ProjectUtil.isDateValidFormat( + ProjectUtil.YEAR_MONTH_DATE_FORMAT, + (String) userRequest.getRequest().get(JsonKey.DOB)); + if (!bool) { + ProjectCommonException.throwClientErrorException(ResponseCode.dateFormatError); + } + } + + if (!StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EMAIL)) + && !ProjectUtil.isEmailvalid((String) userRequest.getRequest().get(JsonKey.EMAIL))) { + ProjectCommonException.throwClientErrorException(ResponseCode.emailFormatError); + } else { + emailVerifiedValidation(userRequest); + } + } + + private void emailVerifiedValidation(Request userRequest) { + if (!StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EMAIL))) { + if (null != userRequest.getRequest().get(JsonKey.EMAIL_VERIFIED)) { + if (userRequest.getRequest().get(JsonKey.EMAIL_VERIFIED) instanceof Boolean) { + if (!((boolean) userRequest.getRequest().get(JsonKey.EMAIL_VERIFIED))) { + ProjectCommonException.throwClientErrorException(ResponseCode.emailVerifiedError); + } + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.emailVerifiedError); + } + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.emailVerifiedError); + } + } + } + + /** + * Method to validate Address + * + * @param userRequest + */ + @SuppressWarnings("unchecked") + private void addressValidation(Request userRequest) { + Map addrReqMap; + if (userRequest.getRequest().containsKey(JsonKey.ADDRESS) + && null != userRequest.getRequest().get(JsonKey.ADDRESS)) { + if (!(userRequest.getRequest().get(JsonKey.ADDRESS) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.ADDRESS, JsonKey.LIST), + ERROR_CODE); + } else if (userRequest.getRequest().get(JsonKey.ADDRESS) instanceof List) { + List> reqList = + (List>) userRequest.get(JsonKey.ADDRESS); + for (int i = 0; i < reqList.size(); i++) { + addrReqMap = reqList.get(i); + new AddressRequestValidator().validateAddress(addrReqMap, JsonKey.ADDRESS); + } + } + } + } + + /** + * Method to validate educational details of the user + * + * @param userRequest + */ + @SuppressWarnings("unchecked") + private void educationValidation(Request userRequest) { + Map addrReqMap; + Map reqMap; + if (userRequest.getRequest().containsKey(JsonKey.EDUCATION) + && null != userRequest.getRequest().get(JsonKey.EDUCATION)) { + if (!(userRequest.getRequest().get(JsonKey.EDUCATION) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.EDUCATION, JsonKey.LIST), + ERROR_CODE); + } else if (userRequest.getRequest().get(JsonKey.EDUCATION) instanceof List) { + List> reqList = + (List>) userRequest.get(JsonKey.EDUCATION); + for (int i = 0; i < reqList.size(); i++) { + reqMap = reqList.get(i); + if (StringUtils.isBlank((String) reqMap.get(JsonKey.NAME))) { + ProjectCommonException.throwClientErrorException(ResponseCode.educationNameError); + } + if (StringUtils.isBlank((String) reqMap.get(JsonKey.DEGREE))) { + ProjectCommonException.throwClientErrorException(ResponseCode.educationDegreeError); + } + if (reqMap.containsKey(JsonKey.ADDRESS) && null != reqMap.get(JsonKey.ADDRESS)) { + addrReqMap = (Map) reqMap.get(JsonKey.ADDRESS); + new AddressRequestValidator().validateAddress(addrReqMap, JsonKey.EDUCATION); + } + } + } + } + } + + /** + * Method to validate jobProfile of a user + * + * @param userRequest + */ + private void jobProfileValidation(Request userRequest) { + if (userRequest.getRequest().containsKey(JsonKey.JOB_PROFILE) + && null != userRequest.getRequest().get(JsonKey.JOB_PROFILE)) { + if (!(userRequest.getRequest().get(JsonKey.JOB_PROFILE) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.JOB_PROFILE, JsonKey.LIST), + ERROR_CODE); + } else if (userRequest.getRequest().get(JsonKey.JOB_PROFILE) instanceof List) { + validateJob(userRequest); + } + } + } + + private void validateJob(Request userRequest) { + + Map reqMap = null; + List> reqList = + (List>) userRequest.get(JsonKey.JOB_PROFILE); + for (int i = 0; i < reqList.size(); i++) { + reqMap = reqList.get(i); + validateJoinEndDate(reqMap); + validateJobOrgNameAndAddress(reqMap); + } + } + + private void validateJoinEndDate(Map reqMap) { + if (null != reqMap.get(JsonKey.JOINING_DATE)) { + boolean bool = + ProjectUtil.isDateValidFormat( + ProjectUtil.YEAR_MONTH_DATE_FORMAT, (String) reqMap.get(JsonKey.JOINING_DATE)); + if (!bool) { + ProjectCommonException.throwClientErrorException(ResponseCode.dateFormatError); + } + } + if (null != reqMap.get(JsonKey.END_DATE)) { + boolean bool = + ProjectUtil.isDateValidFormat( + ProjectUtil.YEAR_MONTH_DATE_FORMAT, (String) reqMap.get(JsonKey.END_DATE)); + if (!bool) { + ProjectCommonException.throwClientErrorException(ResponseCode.dateFormatError); + } + } + } + + private void validateJobOrgNameAndAddress(Map reqMap) { + Map addrReqMap = null; + if (StringUtils.isBlank((String) reqMap.get(JsonKey.JOB_NAME))) { + ProjectCommonException.throwClientErrorException(ResponseCode.jobNameError); + } + if (StringUtils.isBlank((String) reqMap.get(JsonKey.ORG_NAME))) { + ProjectCommonException.throwClientErrorException(ResponseCode.organisationNameError); + } + if (reqMap.containsKey(JsonKey.ADDRESS) && null != reqMap.get(JsonKey.ADDRESS)) { + addrReqMap = (Map) reqMap.get(JsonKey.ADDRESS); + new AddressRequestValidator().validateAddress(addrReqMap, JsonKey.JOB_PROFILE); + } + } + + @SuppressWarnings("unchecked") + public void validateWebPages(Request request) { + if (request.getRequest().containsKey(JsonKey.WEB_PAGES)) { + List> data = + (List>) request.getRequest().get(JsonKey.WEB_PAGES); + if (null == data || data.isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidWebPageData); + } + } + } + + private boolean validatePhoneNo(String phone, String countryCode) { + if (phone.contains("+")) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidPhoneNumber); + } + if (ProjectUtil.validatePhone(phone, countryCode)) { + return true; + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.phoneNoFormatError); + } + return false; + } + + /** + * This method will validate update user data. + * + * @param userRequest Request + */ + public void validateUpdateUserRequest(Request userRequest) { + if (userRequest.getRequest().containsKey(JsonKey.MANAGED_BY)) { + ProjectCommonException.throwClientErrorException(ResponseCode.managedByNotAllowed); + } + externalIdsValidation(userRequest, JsonKey.UPDATE); + phoneValidation(userRequest); + updateUserBasicValidation(userRequest); + validateAddressField(userRequest); + validateJobProfileField(userRequest); + validateEducationField(userRequest); + validateUserType(userRequest); + validateUserOrgField(userRequest); + + if (userRequest.getRequest().containsKey(JsonKey.ROOT_ORG_ID) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.ROOT_ORG_ID))) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidRootOrganisationId); + } + validateLocationCodes(userRequest); + validateExtIdTypeAndProvider(userRequest); + validateFrameworkDetails(userRequest); + validateRecoveryEmailOrPhone(userRequest); + } + + private void validateUserOrgField(Request userRequest) { + Map request = userRequest.getRequest(); + boolean isPrivate = + BooleanUtils.isTrue((Boolean) userRequest.getContext().get(JsonKey.PRIVATE)); + if (isPrivate + && StringUtils.isBlank((String) request.get(JsonKey.USER_ID)) + && request.containsKey(JsonKey.ORGANISATIONS)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.USER_ID)); + } + + if (!isPrivate && request.containsKey(JsonKey.ORGANISATIONS)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorUnsupportedField, + ProjectUtil.formatMessage( + ResponseCode.errorUnsupportedField.getErrorMessage(), JsonKey.ORGANISATIONS)); + } + + if (isPrivate + && request.containsKey(JsonKey.ORGANISATIONS) + && !(request.get(JsonKey.ORGANISATIONS) instanceof List)) { + throwInvalidUserOrgData(); + } + + if (isPrivate && request.containsKey(JsonKey.ORGANISATIONS)) { + List list = (List) request.get(JsonKey.ORGANISATIONS); + for (Object map : list) { + if (!(map instanceof Map)) { + throwInvalidUserOrgData(); + } else { + validRolesDataType((Map) map); + } + } + } + } + + private void validRolesDataType(Map map) { + String organisationId = (String) map.get(JsonKey.ORGANISATION_ID); + if (StringUtils.isBlank(organisationId)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.ORGANISATION_ID)); + } + if (map.containsKey(JsonKey.ROLES)) { + if (!(map.get(JsonKey.ROLES) instanceof List)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.dataTypeError, + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.ROLES, JsonKey.LIST)); + } else if (CollectionUtils.isEmpty((List) map.get(JsonKey.ROLES))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.emptyRolesProvided, ResponseCode.emptyRolesProvided.getErrorMessage()); + } + } + } + + private void throwInvalidUserOrgData() { + ProjectCommonException.throwClientErrorException( + ResponseCode.dataTypeError, + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), + JsonKey.ORGANISATIONS, + String.join(" ", JsonKey.LIST, " of ", JsonKey.MAP))); + } + + private void validateAddressField(Request userRequest) { + if (userRequest.getRequest().get(JsonKey.ADDRESS) != null + && ((List) userRequest.getRequest().get(JsonKey.ADDRESS)).isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.addressRequired); + } + + if (userRequest.getRequest().get(JsonKey.ADDRESS) != null + && (!((List) userRequest.getRequest().get(JsonKey.ADDRESS)).isEmpty())) { + validateUpdateUserAddress(userRequest); + } + } + + private void validateJobProfileField(Request userRequest) { + if (userRequest.getRequest().get(JsonKey.JOB_PROFILE) != null + && ((List) userRequest.getRequest().get(JsonKey.JOB_PROFILE)).isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.jobDetailsRequired); + } + + if (userRequest.getRequest().get(JsonKey.JOB_PROFILE) != null + && (!((List) userRequest.getRequest().get(JsonKey.JOB_PROFILE)).isEmpty())) { + validateUpdateUserJobProfile(userRequest); + } + } + + private void validateEducationField(Request userRequest) { + if (userRequest.getRequest().get(JsonKey.EDUCATION) != null + && ((List) userRequest.getRequest().get(JsonKey.EDUCATION)).isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.educationRequired); + } + + if (userRequest.getRequest().get(JsonKey.EDUCATION) != null + && (!((List) userRequest.getRequest().get(JsonKey.EDUCATION)).isEmpty())) { + validateUpdateUserEducation(userRequest); + } + } + + public void externalIdsValidation(Request userRequest, String operation) { + if (userRequest.getRequest().containsKey(JsonKey.EXTERNAL_IDS) + && (null != userRequest.getRequest().get(JsonKey.EXTERNAL_IDS))) { + if (!(userRequest.getRequest().get(JsonKey.EXTERNAL_IDS) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.EXTERNAL_IDS, JsonKey.LIST), + ERROR_CODE); + } + List> externalIds = + (List>) userRequest.getRequest().get(JsonKey.EXTERNAL_IDS); + validateIndividualExternalId(operation, externalIds); + if (operation.equalsIgnoreCase(JsonKey.CREATE)) { + checkForDuplicateExternalId(externalIds); + } + } + } + + private void validateIndividualExternalId( + String operation, List> externalIds) { + // valid operation type for externalIds in user api. + List operationTypeList = Arrays.asList(JsonKey.ADD, JsonKey.REMOVE, JsonKey.EDIT); + externalIds + .stream() + .forEach( + identity -> { + // check for invalid operation type + if (StringUtils.isNotBlank(identity.get(JsonKey.OPERATION)) + && (!operationTypeList.contains( + (identity.get(JsonKey.OPERATION)).toLowerCase()))) { + throw new ProjectCommonException( + ResponseCode.invalidValue.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidValue.getErrorMessage(), + StringFormatter.joinByDot(JsonKey.EXTERNAL_IDS, JsonKey.OPERATION), + identity.get(JsonKey.OPERATION), + String.join(StringFormatter.COMMA, operationTypeList)), + ERROR_CODE); + } + // throw exception for invalid operation if other operation type is coming in + // request + // other than add or null for create user api + if (JsonKey.CREATE.equalsIgnoreCase(operation) + && StringUtils.isNotBlank(identity.get(JsonKey.OPERATION)) + && (!JsonKey.ADD.equalsIgnoreCase(((identity.get(JsonKey.OPERATION)))))) { + throw new ProjectCommonException( + ResponseCode.invalidValue.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidValue.getErrorMessage(), + StringFormatter.joinByDot(JsonKey.EXTERNAL_IDS, JsonKey.OPERATION), + identity.get(JsonKey.OPERATION), + JsonKey.ADD), + ERROR_CODE); + } + validateExternalIdMandatoryParam(JsonKey.ID, identity.get(JsonKey.ID)); + validateExternalIdMandatoryParam(JsonKey.PROVIDER, identity.get(JsonKey.PROVIDER)); + validateExternalIdMandatoryParam(JsonKey.ID_TYPE, identity.get(JsonKey.ID_TYPE)); + }); + } + + private void validateExternalIdMandatoryParam(String param, String paramValue) { + if (StringUtils.isBlank(paramValue)) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + StringFormatter.joinByDot(JsonKey.EXTERNAL_IDS, param)), + ERROR_CODE); + } + } + + private void validateUpdateUserEducation(Request userRequest) { + List> reqList = + (List>) userRequest.get(JsonKey.EDUCATION); + for (int i = 0; i < reqList.size(); i++) { + Map reqMap = reqList.get(i); + if (reqMap.containsKey(JsonKey.IS_DELETED) + && null != reqMap.get(JsonKey.IS_DELETED) + && ((boolean) reqMap.get(JsonKey.IS_DELETED)) + && StringUtils.isBlank((String) reqMap.get(JsonKey.ID))) { + ProjectCommonException.throwClientErrorException(ResponseCode.idRequired); + } + if (!reqMap.containsKey(JsonKey.IS_DELETED) + || (reqMap.containsKey(JsonKey.IS_DELETED) + && (null == reqMap.get(JsonKey.IS_DELETED) + || !(boolean) reqMap.get(JsonKey.IS_DELETED)))) { + educationValidation(userRequest); + } + } + } + + private void validateUpdateUserJobProfile(Request userRequest) { + List> reqList = + (List>) userRequest.get(JsonKey.JOB_PROFILE); + for (int i = 0; i < reqList.size(); i++) { + Map reqMap = reqList.get(i); + if (reqMap.containsKey(JsonKey.IS_DELETED) + && null != reqMap.get(JsonKey.IS_DELETED) + && ((boolean) reqMap.get(JsonKey.IS_DELETED)) + && StringUtils.isBlank((String) reqMap.get(JsonKey.ID))) { + ProjectCommonException.throwClientErrorException(ResponseCode.idRequired); + } + if (!reqMap.containsKey(JsonKey.IS_DELETED) + || (reqMap.containsKey(JsonKey.IS_DELETED) + && (null == reqMap.get(JsonKey.IS_DELETED) + || !(boolean) reqMap.get(JsonKey.IS_DELETED)))) { + jobProfileValidation(userRequest); + } + } + } + + private void validateUpdateUserAddress(Request userRequest) { + List> reqList = + (List>) userRequest.get(JsonKey.ADDRESS); + for (int i = 0; i < reqList.size(); i++) { + Map reqMap = reqList.get(i); + + if (reqMap.containsKey(JsonKey.IS_DELETED) + && null != reqMap.get(JsonKey.IS_DELETED) + && ((boolean) reqMap.get(JsonKey.IS_DELETED)) + && StringUtils.isBlank((String) reqMap.get(JsonKey.ID))) { + ProjectCommonException.throwClientErrorException(ResponseCode.idRequired); + } + if (!reqMap.containsKey(JsonKey.IS_DELETED) + || (reqMap.containsKey(JsonKey.IS_DELETED) + && (null == reqMap.get(JsonKey.IS_DELETED) + || !(boolean) reqMap.get(JsonKey.IS_DELETED)))) { + new AddressRequestValidator().validateAddress(reqMap, JsonKey.ADDRESS); + } + } + } + + @SuppressWarnings("rawtypes") + private void updateUserBasicValidation(Request userRequest) { + fieldsNotAllowed( + Arrays.asList( + JsonKey.REGISTERED_ORG_ID, + JsonKey.ROOT_ORG_ID, + JsonKey.CHANNEL, + JsonKey.USERNAME, + JsonKey.PROVIDER, + JsonKey.ID_TYPE), + userRequest); + validateUserIdOrExternalId(userRequest); + if (userRequest.getRequest().containsKey(JsonKey.FIRST_NAME) + && (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.FIRST_NAME)))) { + ProjectCommonException.throwClientErrorException(ResponseCode.firstNameRequired); + } + + if ((userRequest.getRequest().containsKey(JsonKey.EMAIL) + && userRequest.getRequest().get(JsonKey.EMAIL) != null) + && !ProjectUtil.isEmailvalid((String) userRequest.getRequest().get(JsonKey.EMAIL))) { + ProjectCommonException.throwClientErrorException(ResponseCode.emailFormatError); + } + + if (userRequest.getRequest().containsKey(JsonKey.ROLES) + && null != userRequest.getRequest().get(JsonKey.ROLES)) { + if (userRequest.getRequest().get(JsonKey.ROLES) instanceof List + && ((List) userRequest.getRequest().get(JsonKey.ROLES)).isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.rolesRequired); + } else if (!(userRequest.getRequest().get(JsonKey.ROLES) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.ROLES, JsonKey.LIST), + ERROR_CODE); + } + } + validateLangaugeFields(userRequest); + } + + private void validateUserIdOrExternalId(Request userRequest) { + if ((StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.USER_ID)) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.ID))) + && (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID)) + || StringUtils.isBlank( + (String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_PROVIDER)) + || StringUtils.isBlank( + (String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_TYPE)))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + (StringFormatter.joinByOr( + JsonKey.USER_ID, + StringFormatter.joinByAnd( + StringFormatter.joinByComma(JsonKey.EXTERNAL_ID, JsonKey.EXTERNAL_ID_TYPE), + JsonKey.EXTERNAL_ID_PROVIDER)))), + ERROR_CODE); + } + } + + private void validateLangaugeFields(Request userRequest) { + if (userRequest.getRequest().containsKey(JsonKey.LANGUAGE) + && null != userRequest.getRequest().get(JsonKey.LANGUAGE)) { + if (userRequest.getRequest().get(JsonKey.LANGUAGE) instanceof List + && ((List) userRequest.getRequest().get(JsonKey.LANGUAGE)).isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.languageRequired); + } else if (!(userRequest.getRequest().get(JsonKey.LANGUAGE) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.LANGUAGE, JsonKey.LIST), + ERROR_CODE); + } + } + } + + /** + * This method will validate change password requested data. + * + * @param userRequest Request + */ + public void validateChangePassword(Request userRequest) { + if (userRequest.getRequest().get(JsonKey.PASSWORD) == null + || (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.PASSWORD)))) { + ProjectCommonException.throwClientErrorException(ResponseCode.passwordRequired); + } + if (userRequest.getRequest().get(JsonKey.NEW_PASSWORD) == null) { + ProjectCommonException.throwClientErrorException(ResponseCode.newPasswordRequired); + } + if (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.NEW_PASSWORD))) { + ProjectCommonException.throwClientErrorException(ResponseCode.newPasswordEmpty); + } + } + + /** + * This method will validate verifyUser requested data. + * + * @param userRequest Request + */ + public void validateVerifyUser(Request userRequest) { + if (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.LOGIN_ID))) { + ProjectCommonException.throwClientErrorException(ResponseCode.loginIdRequired); + } + } + + /** + * Either user will send UserId or (provider and externalId). + * + * @param request + */ + public void validateAssignRole(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.USER_ID))) { + ProjectCommonException.throwClientErrorException(ResponseCode.userIdRequired); + } + + if (request.getRequest().get(JsonKey.ROLES) == null + || !(request.getRequest().get(JsonKey.ROLES) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.ROLES, JsonKey.LIST), + ERROR_CODE); + } + + String organisationId = (String) request.getRequest().get(JsonKey.ORGANISATION_ID); + String externalId = (String) request.getRequest().get(JsonKey.EXTERNAL_ID); + String provider = (String) request.getRequest().get(JsonKey.PROVIDER); + if (StringUtils.isBlank(organisationId) + && (StringUtils.isBlank(externalId) || StringUtils.isBlank(provider))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + (StringFormatter.joinByOr( + JsonKey.ORGANISATION_ID, + StringFormatter.joinByAnd(JsonKey.EXTERNAL_ID, JsonKey.PROVIDER)))), + ERROR_CODE); + } + } + + /** @param request */ + public void validateForgotPassword(Request request) { + if (request.getRequest().get(JsonKey.USERNAME) == null + || StringUtils.isBlank((String) request.getRequest().get(JsonKey.USERNAME))) { + throw new ProjectCommonException( + ResponseCode.userNameRequired.getErrorCode(), + ResponseCode.userNameRequired.getErrorMessage(), + ERROR_CODE); + } + } + + /** + * This method will validate bulk api user data. + * + * @param userRequest Request + */ + public void validateBulkUserData(Request userRequest) { + externalIdsValidation(userRequest, JsonKey.BULK_USER_UPLOAD); + createUserBasicValidation(userRequest); + phoneValidation(userRequest); + validateWebPages(userRequest); + validateExtIdTypeAndProvider(userRequest); + if (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.USERNAME)) + && (StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_PROVIDER)) + || StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID)) + || StringUtils.isBlank( + (String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_TYPE)))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + (StringFormatter.joinByOr( + JsonKey.USERNAME, + StringFormatter.joinByAnd( + StringFormatter.joinByComma(JsonKey.EXTERNAL_ID, JsonKey.EXTERNAL_ID_TYPE), + JsonKey.EXTERNAL_ID_PROVIDER)))), + ERROR_CODE); + } + } + + private void validateExtIdTypeAndProvider(Request userRequest) { + if ((StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_PROVIDER)) + && StringUtils.isNotBlank((String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID)) + && StringUtils.isNotBlank( + (String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_TYPE)))) { + return; + } else if (StringUtils.isBlank( + (String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_PROVIDER)) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID)) + && StringUtils.isBlank((String) userRequest.getRequest().get(JsonKey.EXTERNAL_ID_TYPE))) { + return; + } else { + throw new ProjectCommonException( + ResponseCode.dependentParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.dependentParamsMissing.getErrorMessage(), + StringFormatter.joinByComma( + JsonKey.EXTERNAL_ID, JsonKey.EXTERNAL_ID_TYPE, JsonKey.EXTERNAL_ID_PROVIDER)), + ERROR_CODE); + } + } + + private void checkForDuplicateExternalId(List> list) { + List> checkedList = new ArrayList<>(); + for (Map externalId : list) { + for (Map checkedExternalId : checkedList) { + String provider = checkedExternalId.get(JsonKey.PROVIDER); + String idType = checkedExternalId.get(JsonKey.ID_TYPE); + if (provider.equalsIgnoreCase(externalId.get(JsonKey.PROVIDER)) + && idType.equalsIgnoreCase(externalId.get(JsonKey.ID_TYPE))) { + String exceptionMsg = + MessageFormat.format( + ResponseCode.duplicateExternalIds.getErrorMessage(), idType, provider); + ProjectCommonException.throwClientErrorException( + ResponseCode.duplicateExternalIds, exceptionMsg); + } + } + checkedList.add(externalId); + } + } + + @SuppressWarnings("unchecked") + private void validateFrameworkDetails(Request request) { + if (request.getRequest().containsKey(JsonKey.FRAMEWORK) + && (!(request.getRequest().get(JsonKey.FRAMEWORK) instanceof Map))) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ResponseCode.dataTypeError.getErrorMessage(), + ERROR_CODE, + JsonKey.FRAMEWORK, + JsonKey.MAP); + } else { + Map framework = + (Map) request.getRequest().get(JsonKey.FRAMEWORK); + if (!MapUtils.isEmpty(framework)) { + if (framework.get(JsonKey.ID) instanceof List) { + List frameworkId = (List) framework.get(JsonKey.ID); + if (CollectionUtils.isEmpty(frameworkId)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + StringFormatter.joinByDot(JsonKey.FRAMEWORK, JsonKey.ID))); + } else if (frameworkId.size() > 1) { + throw new ProjectCommonException( + ResponseCode.errorInvalidParameterSize.getErrorCode(), + ResponseCode.errorInvalidParameterSize.getErrorMessage(), + ERROR_CODE, + StringFormatter.joinByDot(JsonKey.FRAMEWORK, JsonKey.ID), + "1", + String.valueOf(frameworkId.size())); + } + } else if (framework.get(JsonKey.ID) instanceof String) { + String frameworkId = (String) framework.get(JsonKey.ID); + if (StringUtils.isBlank(frameworkId)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + StringFormatter.joinByDot(JsonKey.FRAMEWORK, JsonKey.ID))); + } + } + } + } + } + + @SuppressWarnings("unchecked") + public void validateMandatoryFrameworkFields( + Map userMap, + List frameworkFields, + List frameworkMandatoryFields) { + if (userMap.containsKey(JsonKey.FRAMEWORK)) { + Map frameworkRequest = (Map) userMap.get(JsonKey.FRAMEWORK); + for (String field : frameworkFields) { + if (CollectionUtils.isNotEmpty(frameworkMandatoryFields) + && frameworkMandatoryFields.contains(field)) { + if (!frameworkRequest.containsKey(field)) { + validateParam(null, ResponseCode.mandatoryParamsMissing, field); + } + validateListParamWithPrefix(frameworkRequest, JsonKey.FRAMEWORK, field); + List fieldValue = (List) frameworkRequest.get(field); + if (fieldValue.isEmpty()) { + throw new ProjectCommonException( + ResponseCode.errorMandatoryParamsEmpty.getErrorCode(), + ResponseCode.errorMandatoryParamsEmpty.getErrorMessage(), + ERROR_CODE, + StringFormatter.joinByDot(JsonKey.FRAMEWORK, field)); + } + } else { + if (frameworkRequest.containsKey(field) + && frameworkRequest.get(field) != null + && !(frameworkRequest.get(field) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + ResponseCode.dataTypeError.getErrorMessage(), + ERROR_CODE, + field, + JsonKey.LIST); + } + } + } + List frameworkRequestFieldList = + frameworkRequest.keySet().stream().collect(Collectors.toList()); + for (String frameworkRequestField : frameworkRequestFieldList) { + if (!frameworkFields.contains(frameworkRequestField)) { + throw new ProjectCommonException( + ResponseCode.errorUnsupportedField.getErrorCode(), + ResponseCode.errorUnsupportedField.getErrorMessage(), + ERROR_CODE, + StringFormatter.joinByDot(JsonKey.FRAMEWORK, frameworkRequestField)); + } + } + } + } + + @SuppressWarnings("unchecked") + public void validateFrameworkCategoryValues( + Map userMap, Map>> frameworkMap) { + Map> fwRequest = + (Map>) userMap.get(JsonKey.FRAMEWORK); + for (Map.Entry> fwRequestFieldEntry : fwRequest.entrySet()) { + if (!fwRequestFieldEntry.getValue().isEmpty()) { + List allowedFieldValues = + getKeyValueFromFrameWork(fwRequestFieldEntry.getKey(), frameworkMap) + .stream() + .map(fieldMap -> fieldMap.get(JsonKey.NAME)) + .collect(Collectors.toList()); + + List fwRequestFieldList = fwRequestFieldEntry.getValue(); + + for (String fwRequestField : fwRequestFieldList) { + if (!allowedFieldValues.contains(fwRequestField)) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ResponseCode.invalidParameterValue.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + fwRequestField, + StringFormatter.joinByDot(JsonKey.FRAMEWORK, fwRequestFieldEntry.getKey())); + } + } + } + } + } + + private List> getKeyValueFromFrameWork( + String key, Map>> frameworkMap) { + if (frameworkMap.get(key) == null) { + throw new ProjectCommonException( + ResponseCode.errorUnsupportedField.getErrorCode(), + MessageFormat.format( + ResponseCode.errorUnsupportedField.getErrorMessage(), + key + " in " + JsonKey.FRAMEWORK), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return frameworkMap.get(key); + } + + private void validateUserType(Request userRequest) { + String userType = (String) userRequest.getRequest().get(JsonKey.USER_TYPE); + + if (userType != null + && (!JsonKey.OTHER.equalsIgnoreCase(userType)) + && (!JsonKey.TEACHER.equalsIgnoreCase(userType))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + new String[] {userType, JsonKey.USER_TYPE})); + } + } + + public void validateUserMergeRequest( + Request request, String authUserToken, String sourceUserToken) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.FROM_ACCOUNT_ID))) { + throw new ProjectCommonException( + ResponseCode.fromAccountIdRequired.getErrorCode(), + ResponseCode.fromAccountIdRequired.getErrorMessage(), + ERROR_CODE); + } + + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.TO_ACCOUNT_ID))) { + throw new ProjectCommonException( + ResponseCode.toAccountIdRequired.getErrorCode(), + ResponseCode.toAccountIdRequired.getErrorMessage(), + ERROR_CODE); + } + + if (StringUtils.isBlank(authUserToken)) { + createClientError( + ResponseCode.mandatoryHeaderParamsMissing, JsonKey.X_AUTHENTICATED_USER_TOKEN); + } + + if (StringUtils.isBlank(authUserToken)) { + createClientError( + ResponseCode.mandatoryHeaderParamsMissing, JsonKey.X_AUTHENTICATED_USER_TOKEN); + } + if (StringUtils.isBlank(sourceUserToken)) { + createClientError(ResponseCode.mandatoryHeaderParamsMissing, JsonKey.X_SOURCE_USER_TOKEN); + } + } + + public void validateCertValidationRequest(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.CERT_ID))) { + createClientError(ResponseCode.mandatoryParamsMissing, JsonKey.CERT_ID); + } + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.ACCESS_CODE))) { + createClientError(ResponseCode.mandatoryParamsMissing, JsonKey.ACCESS_CODE); + } + } + + private void createClientError(ResponseCode responseCode, String field) { + throw new ProjectCommonException( + responseCode.getErrorCode(), + ProjectUtil.formatMessage(responseCode.getErrorMessage(), field), + ERROR_CODE); + } + + private void validateRecoveryEmailOrPhone(Request userRequest) { + if (StringUtils.isNotBlank((String) userRequest.get(JsonKey.RECOVERY_EMAIL))) { + validateEmail((String) userRequest.get(JsonKey.RECOVERY_EMAIL)); + } + if (StringUtils.isNotBlank((String) userRequest.get(JsonKey.RECOVERY_PHONE))) { + validatePhone((String) userRequest.get(JsonKey.RECOVERY_PHONE)); + } + } + + /** + * This method will validate uuid. + * + * @param uuid String + */ + public void validateUserId(String uuid) { + if (StringUtils.isNotEmpty(uuid) && !ProjectUtil.validateUUID(uuid)) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidRequestParameter); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserTenantMigrationRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserTenantMigrationRequestValidator.java new file mode 100644 index 0000000000..23c6e57d81 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/UserTenantMigrationRequestValidator.java @@ -0,0 +1,27 @@ +package org.sunbird.common.request; + +import java.util.Map; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * Request validator class for user tenant migration request. + * + * @author Amit Kumar + */ +public class UserTenantMigrationRequestValidator extends UserRequestValidator { + + /** + * This method will validate the user migration request. + * + * @param request user migration request body + */ + public void validateUserTenantMigrateRequest(Request request) { + Map req = request.getRequest(); + validateParam( + (String) req.get(JsonKey.CHANNEL), ResponseCode.mandatoryParamsMissing, JsonKey.CHANNEL); + validateParam( + (String) req.get(JsonKey.USER_ID), ResponseCode.mandatoryParamsMissing, JsonKey.USER_ID); + externalIdsValidation(request, JsonKey.CREATE); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/certificatevalidator/CertAddRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/certificatevalidator/CertAddRequestValidator.java new file mode 100644 index 0000000000..ae69ed1017 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/certificatevalidator/CertAddRequestValidator.java @@ -0,0 +1,80 @@ +package org.sunbird.common.request.certificatevalidator; + +import com.google.common.collect.Lists; +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.BaseRequestValidator; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * this class is responsible to validate the certificate add request + * + * @author anmolgupta + */ +public class CertAddRequestValidator extends BaseRequestValidator { + public static final String PDF_URL = "pdfUrl"; + + private Request request; + static List mandatoryParamsList = + Lists.newArrayList(JsonKey.ID, JsonKey.ACCESS_CODE, JsonKey.PDF_URL, JsonKey.USER_ID); + + private CertAddRequestValidator(Request request) { + this.request = request; + } + + /** + * this method we should use to get the instance of the validator class + * + * @param request + * @return + */ + public static CertAddRequestValidator getInstance(Request request) { + return new CertAddRequestValidator(request); + } + + /** this method should be call to validate the request */ + public void validate() { + checkMandatoryFieldsPresent(request.getRequest(), mandatoryParamsList); + validateMandatoryJsonData(); + } + + private void validateMandatoryJsonData() { + validatePresence(); + validateDataType(); + } + + private void validateDataType() { + if (!(request.get(JsonKey.JSON_DATA) instanceof Map)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.JSON_DATA, "MAP"), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private void validatePresence() { + if (null == request.get(JsonKey.JSON_DATA)) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + JsonKey.JSON_DATA); + } + } + + public void validateDownlaodFileData() { + if (StringUtils.isBlank((String) request.getRequest().get(PDF_URL))) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + PDF_URL); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/BaseOrgRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/BaseOrgRequestValidator.java new file mode 100644 index 0000000000..376622fb8d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/BaseOrgRequestValidator.java @@ -0,0 +1,35 @@ +package org.sunbird.common.request.orgvalidator; + +import java.text.MessageFormat; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.BaseRequestValidator; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +public class BaseOrgRequestValidator extends BaseRequestValidator { + + public static final int ERROR_CODE = ResponseCode.CLIENT_ERROR.getResponseCode(); + + public void validateOrgReference(Request request) { + validateParam( + (String) request.getRequest().get(JsonKey.ORGANISATION_ID), + ResponseCode.mandatoryParamsMissing, + JsonKey.ORGANISATION_ID); + } + + public void validateRootOrgChannel(Request request) { + if ((null != request.getRequest().get(JsonKey.IS_ROOT_ORG) + && (Boolean) request.getRequest().get(JsonKey.IS_ROOT_ORG)) + && StringUtils.isEmpty((String) request.getRequest().get(JsonKey.CHANNEL))) { + throw new ProjectCommonException( + ResponseCode.dependentParameterMissing.getErrorCode(), + MessageFormat.format( + ResponseCode.dependentParameterMissing.getErrorMessage(), + JsonKey.CHANNEL, + JsonKey.IS_ROOT_ORG), + ERROR_CODE); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/KeyManagementValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/KeyManagementValidator.java new file mode 100644 index 0000000000..29b4a006f2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/KeyManagementValidator.java @@ -0,0 +1,88 @@ +package org.sunbird.common.request.orgvalidator; + +import java.text.MessageFormat; +import java.util.List; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.BaseRequestValidator; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * this class is used to validate the request of the OrgAssignKeys Controller + * + * @author anmolgupta + */ +public class KeyManagementValidator extends BaseRequestValidator { + + private Request request; + + private KeyManagementValidator(Request request) { + this.request = request; + } + + /** + * this method should be used to get the instance of the class + * + * @param request + * @return + */ + public static KeyManagementValidator getInstance(Request request) { + return new KeyManagementValidator(request); + } + + /** this method should be used to validate the OrgAssignKeysController request. */ + public void validate() { + id(); + signKeys(); + encKeys(); + } + + private void id() { + validateParam( + (String) request.getRequest().get(JsonKey.ID), + ResponseCode.mandatoryParamsMissing, + JsonKey.ID); + } + + private void signKeys() { + validateKeyPresence(JsonKey.SIGN_KEYS); + validateListTypeObject(JsonKey.SIGN_KEYS); + validateSize(JsonKey.SIGN_KEYS); + } + + private void encKeys() { + validateKeyPresence(JsonKey.ENC_KEYS); + validateListTypeObject(JsonKey.ENC_KEYS); + validateSize(JsonKey.ENC_KEYS); + } + + private void validateListTypeObject(String key) { + if (!(request.get(key) instanceof List)) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + MessageFormat.format(ResponseCode.dataTypeError.getErrorMessage(), key, "List"), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private void validateKeyPresence(String key) { + if (!request.getRequest().containsKey(key)) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ResponseCode.mandatoryParamsMissing.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + key); + } + } + + private void validateSize(String key) { + if (((List) request.get(key)).size() == 0) { + throw new ProjectCommonException( + ResponseCode.errorMandatoryParamsEmpty.getErrorCode(), + ResponseCode.errorMandatoryParamsEmpty.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode(), + key); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgMemberRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgMemberRequestValidator.java new file mode 100644 index 0000000000..21e9b93568 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgMemberRequestValidator.java @@ -0,0 +1,74 @@ +package org.sunbird.common.request.orgvalidator; + +import java.text.MessageFormat; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +public class OrgMemberRequestValidator extends BaseOrgRequestValidator { + + public void validateAddMemberRequest(Request request) { + validateCommonParams(request); + if (request.getRequest().containsKey(JsonKey.ROLES) + && (!(request.getRequest().get(JsonKey.ROLES) instanceof List))) { + throw new ProjectCommonException( + ResponseCode.dataTypeError.getErrorCode(), + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.ROLES, JsonKey.LIST), + ERROR_CODE); + } + } + + private void validateCommonParams(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.USER_ID))) { + ProjectLogger.log( + "OrgMemberRequestValidator : validateCommonParams : UserId is missing. Validating userExternalId"); + validateCommonUserParams(request); + } + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.ORGANISATION_ID))) { + ProjectLogger.log( + "OrgMemberRequestValidator : validateCommonParams : OrganizationId is missing. Validating ExternalId"); + validateCommonOrgParams(request); + } + } + + private void validateCommonOrgParams(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.EXTERNAL_ID))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + " Please provide organizationId or ExternalId,Provider "); + } + validateParam( + (String) request.getRequest().get(JsonKey.PROVIDER), + ResponseCode.mandatoryParamsMissing, + JsonKey.PROVIDER); + } + + private void validateCommonUserParams(Request request) { + if (StringUtils.isBlank((String) request.getRequest().get(JsonKey.USER_EXTERNAL_ID))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + " Please provide userId or userExternalId,userProvider,userIdType "); + } + validateParam( + (String) request.getRequest().get(JsonKey.USER_PROVIDER), + ResponseCode.mandatoryParamsMissing, + JsonKey.USER_PROVIDER); + validateParam( + (String) request.getRequest().get(JsonKey.USER_ID_TYPE), + ResponseCode.mandatoryParamsMissing, + JsonKey.USER_ID_TYPE); + } + + public void validateCommon(Request request) { + validateOrgReference(request); + validateParam( + (String) request.getRequest().get(JsonKey.USER_ID), + ResponseCode.mandatoryParamsMissing, + JsonKey.USER_ID); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgRequestValidator.java new file mode 100644 index 0000000000..06456dd02f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgRequestValidator.java @@ -0,0 +1,105 @@ +package org.sunbird.common.request.orgvalidator; + +import java.text.MessageFormat; +import java.util.Map; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.AddressRequestValidator; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +public class OrgRequestValidator extends BaseOrgRequestValidator { + + private static final int ERROR_CODE = ResponseCode.CLIENT_ERROR.getResponseCode(); + + public void validateCreateOrgRequest(Request orgRequest) { + + validateParam( + (String) orgRequest.getRequest().get(JsonKey.ORG_NAME), + ResponseCode.mandatoryParamsMissing, + JsonKey.ORG_NAME); + validateRootOrgChannel(orgRequest); + validateLicense(orgRequest); + + Map address = + (Map) orgRequest.getRequest().get(JsonKey.ADDRESS); + if (MapUtils.isNotEmpty(address)) { + new AddressRequestValidator().validateAddress(address, JsonKey.ORGANISATION); + } + validateLocationIdOrCode(orgRequest); + } + + private void validateLicense(Request orgRequest) { + if (orgRequest.getRequest().containsKey(JsonKey.IS_ROOT_ORG) + && (boolean) orgRequest.getRequest().get(JsonKey.IS_ROOT_ORG) + && orgRequest.getRequest().containsKey(JsonKey.LICENSE) + && StringUtils.isBlank((String) orgRequest.getRequest().get(JsonKey.LICENSE))) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + (String) orgRequest.getRequest().get(JsonKey.LICENSE), + JsonKey.LICENSE), + ERROR_CODE); + } + } + + public void validateUpdateOrgRequest(Request request) { + validateOrgReference(request); + if (request.getRequest().containsKey(JsonKey.ROOT_ORG_ID) + && StringUtils.isEmpty((String) request.getRequest().get(JsonKey.ROOT_ORG_ID))) { + throw new ProjectCommonException( + ResponseCode.invalidRootOrganisationId.getErrorCode(), + ResponseCode.invalidRootOrganisationId.getErrorMessage(), + ERROR_CODE); + } + if (request.getRequest().get(JsonKey.STATUS) != null) { + throw new ProjectCommonException( + ResponseCode.invalidRequestParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidRequestParameter.getErrorMessage(), JsonKey.STATUS), + ERROR_CODE); + } + + validateRootOrgChannel(request); + validateLocationIdOrCode(request); + Map address = (Map) request.getRequest().get(JsonKey.ADDRESS); + if (MapUtils.isNotEmpty(address)) { + new AddressRequestValidator().validateAddress(address, JsonKey.ORGANISATION); + } + } + + public void validateUpdateOrgStatusRequest(Request request) { + validateOrgReference(request); + + if (!request.getRequest().containsKey(JsonKey.STATUS)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ERROR_CODE); + } + + if (!(request.getRequest().get(JsonKey.STATUS) instanceof Integer)) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ERROR_CODE); + } + } + + private void validateLocationIdOrCode(Request orgRequest) { + validateListParam(orgRequest.getRequest(), JsonKey.LOCATION_IDS, JsonKey.LOCATION_CODE); + if (orgRequest.getRequest().get(JsonKey.LOCATION_IDS) != null + && orgRequest.getRequest().get(JsonKey.LOCATION_CODE) != null) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorAttributeConflict, + MessageFormat.format( + ResponseCode.errorAttributeConflict.getErrorMessage(), + JsonKey.LOCATION_CODE, + JsonKey.LOCATION_IDS)); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgTypeRequestValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgTypeRequestValidator.java new file mode 100644 index 0000000000..ad16b3884c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/orgvalidator/OrgTypeRequestValidator.java @@ -0,0 +1,23 @@ +package org.sunbird.common.request.orgvalidator; + +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +public class OrgTypeRequestValidator extends BaseOrgRequestValidator { + + public void validateUpdateOrgTypeRequest(Request request) { + validateCreateOrgTypeRequest(request); + validateParam( + (String) request.getRequest().get(JsonKey.ID), + ResponseCode.mandatoryParamsMissing, + JsonKey.ID); + } + + public void validateCreateOrgTypeRequest(Request request) { + validateParam( + (String) request.getRequest().get(JsonKey.NAME), + ResponseCode.mandatoryParamsMissing, + JsonKey.NAME); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/package-info.java new file mode 100644 index 0000000000..af17271ba5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/request/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.request; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/ResponseCode.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/ResponseCode.java new file mode 100644 index 0000000000..a51e789906 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/ResponseCode.java @@ -0,0 +1,1003 @@ +package org.sunbird.common.responsecode; + +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; + +/** @author Manzarul */ +public enum ResponseCode { + unAuthorized(ResponseMessage.Key.UNAUTHORIZED_USER, ResponseMessage.Message.UNAUTHORIZED_USER), + invalidUserCredentials( + ResponseMessage.Key.INVALID_USER_CREDENTIALS, + ResponseMessage.Message.INVALID_USER_CREDENTIALS), + operationTimeout( + ResponseMessage.Key.OPERATION_TIMEOUT, ResponseMessage.Message.OPERATION_TIMEOUT), + invalidOperationName( + ResponseMessage.Key.INVALID_OPERATION_NAME, ResponseMessage.Message.INVALID_OPERATION_NAME), + invalidRequestData( + ResponseMessage.Key.INVALID_REQUESTED_DATA, ResponseMessage.Message.INVALID_REQUESTED_DATA), + invalidCustomerId( + ResponseMessage.Key.CONSUMER_ID_MISSING_ERROR, + ResponseMessage.Message.CONSUMER_ID_MISSING_ERROR), + customerIdRequired( + ResponseMessage.Key.CONSUMER_ID_INVALID_ERROR, + ResponseMessage.Message.CONSUMER_ID_INVALID_ERROR), + deviceIdRequired( + ResponseMessage.Key.DEVICE_ID_MISSING_ERROR, ResponseMessage.Message.DEVICE_ID_MISSING_ERROR), + invalidContentId( + ResponseMessage.Key.CONTENT_ID_INVALID_ERROR, + ResponseMessage.Message.CONTENT_ID_INVALID_ERROR), + courseIdRequired( + ResponseMessage.Key.COURSE_ID_MISSING_ERROR, ResponseMessage.Message.COURSE_ID_MISSING_ERROR), + contentIdRequired( + ResponseMessage.Key.CONTENT_ID_MISSING_ERROR, + ResponseMessage.Message.CONTENT_ID_MISSING_ERROR), + errorInvalidConfigParamValue( + ResponseMessage.Key.ERROR_INVALID_CONFIG_PARAM_VALUE, + ResponseMessage.Message.ERROR_INVALID_CONFIG_PARAM_VALUE), + errorMaxSizeExceeded( + ResponseMessage.Key.ERROR_MAX_SIZE_EXCEEDED, ResponseMessage.Message.ERROR_MAX_SIZE_EXCEEDED), + apiKeyRequired( + ResponseMessage.Key.API_KEY_MISSING_ERROR, ResponseMessage.Message.API_KEY_MISSING_ERROR), + invalidApiKey( + ResponseMessage.Key.API_KEY_INVALID_ERROR, ResponseMessage.Message.API_KEY_INVALID_ERROR), + internalError(ResponseMessage.Key.INTERNAL_ERROR, ResponseMessage.Message.INTERNAL_ERROR), + dbInsertionError( + ResponseMessage.Key.DB_INSERTION_FAIL, ResponseMessage.Message.DB_INSERTION_FAIL), + dbUpdateError(ResponseMessage.Key.DB_UPDATE_FAIL, ResponseMessage.Message.DB_UPDATE_FAIL), + courseNameRequired( + ResponseMessage.Key.COURSE_NAME_MISSING, ResponseMessage.Message.COURSE_NAME_MISSING), + success(ResponseMessage.Key.SUCCESS_MESSAGE, ResponseMessage.Message.SUCCESS_MESSAGE), + sessionIdRequiredError( + ResponseMessage.Key.SESSION_ID_MISSING, ResponseMessage.Message.SESSION_ID_MISSING), + courseIdRequiredError( + ResponseMessage.Key.COURSE_ID_MISSING, ResponseMessage.Message.COURSE_ID_MISSING), + contentIdRequiredError( + ResponseMessage.Key.CONTENT_ID_MISSING, ResponseMessage.Message.CONTENT_ID_MISSING), + versionRequiredError( + ResponseMessage.Key.VERSION_MISSING, ResponseMessage.Message.VERSION_MISSING), + courseVersionRequiredError( + ResponseMessage.Key.COURSE_VERSION_MISSING, ResponseMessage.Message.COURSE_VERSION_MISSING), + contentVersionRequiredError( + ResponseMessage.Key.CONTENT_VERSION_MISSING, ResponseMessage.Message.CONTENT_VERSION_MISSING), + courseDescriptionError( + ResponseMessage.Key.COURSE_DESCRIPTION_MISSING, + ResponseMessage.Message.COURSE_DESCRIPTION_MISSING), + courseTocUrlError( + ResponseMessage.Key.COURSE_TOCURL_MISSING, ResponseMessage.Message.COURSE_TOCURL_MISSING), + emailRequired(ResponseMessage.Key.EMAIL_MISSING, ResponseMessage.Message.EMAIL_MISSING), + emailFormatError(ResponseMessage.Key.EMAIL_FORMAT, ResponseMessage.Message.EMAIL_FORMAT), + urlFormatError(ResponseMessage.Key.URL_FORMAT_ERROR, ResponseMessage.Message.URL_FORMAT_ERROR), + firstNameRequired( + ResponseMessage.Key.FIRST_NAME_MISSING, ResponseMessage.Message.FIRST_NAME_MISSING), + languageRequired(ResponseMessage.Key.LANGUAGE_MISSING, ResponseMessage.Message.LANGUAGE_MISSING), + passwordRequired(ResponseMessage.Key.PASSWORD_MISSING, ResponseMessage.Message.PASSWORD_MISSING), + passwordMinLengthError( + ResponseMessage.Key.PASSWORD_MIN_LENGHT, ResponseMessage.Message.PASSWORD_MIN_LENGHT), + passwordMaxLengthError( + ResponseMessage.Key.PASSWORD_MAX_LENGHT, ResponseMessage.Message.PASSWORD_MAX_LENGHT), + organisationIdRequiredError( + ResponseMessage.Key.ORGANISATION_ID_MISSING, ResponseMessage.Message.ORGANISATION_ID_MISSING), + sourceAndExternalIdValidationError( + ResponseMessage.Key.REQUIRED_DATA_ORG_MISSING, + ResponseMessage.Message.REQUIRED_DATA_ORG_MISSING), + organisationNameRequired( + ResponseMessage.Key.ORGANISATION_NAME_MISSING, + ResponseMessage.Message.ORGANISATION_NAME_MISSING), + channelUniquenessInvalid( + ResponseMessage.Key.CHANNEL_SHOULD_BE_UNIQUE, + ResponseMessage.Message.CHANNEL_SHOULD_BE_UNIQUE), + errorDuplicateEntry( + ResponseMessage.Key.ERROR_DUPLICATE_ENTRY, ResponseMessage.Message.ERROR_DUPLICATE_ENTRY), + unableToConnect( + ResponseMessage.Key.UNABLE_TO_CONNECT_TO_EKSTEP, + ResponseMessage.Message.UNABLE_TO_CONNECT_TO_EKSTEP), + unableToConnectToES( + ResponseMessage.Key.UNABLE_TO_CONNECT_TO_ES, ResponseMessage.Message.UNABLE_TO_CONNECT_TO_ES), + unableToParseData( + ResponseMessage.Key.UNABLE_TO_PARSE_DATA, ResponseMessage.Message.UNABLE_TO_PARSE_DATA), + invalidJsonData(ResponseMessage.Key.INVALID_JSON, ResponseMessage.Message.INVALID_JSON), + invalidOrgData(ResponseMessage.Key.INVALID_ORG_DATA, ResponseMessage.Message.INVALID_ORG_DATA), + invalidRootOrganisationId( + ResponseMessage.Key.INVALID_ROOT_ORGANIZATION, + ResponseMessage.Message.INVALID_ROOT_ORGANIZATION), + invalidParentId( + ResponseMessage.Key.INVALID_PARENT_ORGANIZATION_ID, + ResponseMessage.Message.INVALID_PARENT_ORGANIZATION_ID), + cyclicValidationError( + ResponseMessage.Key.CYCLIC_VALIDATION_FAILURE, + ResponseMessage.Message.CYCLIC_VALIDATION_FAILURE), + invalidUsrData(ResponseMessage.Key.INVALID_USR_DATA, ResponseMessage.Message.INVALID_USR_DATA), + usrValidationError( + ResponseMessage.Key.USR_DATA_VALIDATION_ERROR, + ResponseMessage.Message.USR_DATA_VALIDATION_ERROR), + errorInvalidOTP(ResponseMessage.Key.ERROR_INVALID_OTP, ResponseMessage.Message.ERROR_INVALID_OTP), + enrollmentStartDateRequiredError( + ResponseMessage.Key.ENROLLMENT_START_DATE_MISSING, + ResponseMessage.Message.ENROLLMENT_START_DATE_MISSING), + courseDurationRequiredError( + ResponseMessage.Key.COURSE_DURATION_MISSING, ResponseMessage.Message.COURSE_DURATION_MISSING), + loginTypeRequired( + ResponseMessage.Key.LOGIN_TYPE_MISSING, ResponseMessage.Message.LOGIN_TYPE_MISSING), + emailAlreadyExistError(ResponseMessage.Key.EMAIL_IN_USE, ResponseMessage.Message.EMAIL_IN_USE), + invalidCredentials( + ResponseMessage.Key.INVALID_CREDENTIAL, ResponseMessage.Message.INVALID_CREDENTIAL), + userNameRequired(ResponseMessage.Key.USERNAME_MISSING, ResponseMessage.Message.USERNAME_MISSING), + userNameAlreadyExistError( + ResponseMessage.Key.USERNAME_IN_USE, ResponseMessage.Message.USERNAME_IN_USE), + userIdRequired(ResponseMessage.Key.USERID_MISSING, ResponseMessage.Message.USERID_MISSING), + roleRequired(ResponseMessage.Key.ROLE_MISSING, ResponseMessage.Message.ROLE_MISSING), + msgIdRequiredError( + ResponseMessage.Key.MESSAGE_ID_MISSING, ResponseMessage.Message.MESSAGE_ID_MISSING), + userNameCanntBeUpdated( + ResponseMessage.Key.USERNAME_CANNOT_BE_UPDATED, + ResponseMessage.Message.USERNAME_CANNOT_BE_UPDATED), + authTokenRequired( + ResponseMessage.Key.AUTH_TOKEN_MISSING, ResponseMessage.Message.AUTH_TOKEN_MISSING), + invalidAuthToken( + ResponseMessage.Key.INVALID_AUTH_TOKEN, ResponseMessage.Message.INVALID_AUTH_TOKEN), + timeStampRequired( + ResponseMessage.Key.TIMESTAMP_REQUIRED, ResponseMessage.Message.TIMESTAMP_REQUIRED), + publishedCourseCanNotBeUpdated( + ResponseMessage.Key.PUBLISHED_COURSE_CAN_NOT_UPDATED, + ResponseMessage.Message.PUBLISHED_COURSE_CAN_NOT_UPDATED), + sourceRequired(ResponseMessage.Key.SOURCE_MISSING, ResponseMessage.Message.SOURCE_MISSING), + sectionNameRequired( + ResponseMessage.Key.SECTION_NAME_MISSING, ResponseMessage.Message.SECTION_NAME_MISSING), + sectionDataTypeRequired( + ResponseMessage.Key.SECTION_DATA_TYPE_MISSING, + ResponseMessage.Message.SECTION_DATA_TYPE_MISSING), + sectionIdRequired( + ResponseMessage.Key.SECTION_ID_REQUIRED, ResponseMessage.Message.SECTION_ID_REQUIRED), + pageNameRequired( + ResponseMessage.Key.PAGE_NAME_REQUIRED, ResponseMessage.Message.PAGE_NAME_REQUIRED), + pageIdRequired(ResponseMessage.Key.PAGE_ID_REQUIRED, ResponseMessage.Message.PAGE_ID_REQUIRED), + invaidConfiguration( + ResponseMessage.Key.INVALID_CONFIGURATION, ResponseMessage.Message.INVALID_CONFIGURATION), + assessmentItemIdRequired( + ResponseMessage.Key.ASSESSMENT_ITEM_ID_REQUIRED, + ResponseMessage.Message.ASSESSMENT_ITEM_ID_REQUIRED), + assessmentTypeRequired( + ResponseMessage.Key.ASSESSMENT_TYPE_REQUIRED, + ResponseMessage.Message.ASSESSMENT_TYPE_REQUIRED), + assessmentAttemptDateRequired( + ResponseMessage.Key.ATTEMPTED_DATE_REQUIRED, ResponseMessage.Message.ATTEMPTED_DATE_REQUIRED), + assessmentAnswersRequired( + ResponseMessage.Key.ATTEMPTED_ANSWERS_REQUIRED, + ResponseMessage.Message.ATTEMPTED_ANSWERS_REQUIRED), + assessmentmaxScoreRequired( + ResponseMessage.Key.MAX_SCORE_REQUIRED, ResponseMessage.Message.MAX_SCORE_REQUIRED), + statusCanntBeUpdated( + ResponseMessage.Key.STATUS_CANNOT_BE_UPDATED, + ResponseMessage.Message.STATUS_CANNOT_BE_UPDATED), + attemptIdRequired( + ResponseMessage.Key.ATTEMPT_ID_MISSING_ERROR, + ResponseMessage.Message.ATTEMPT_ID_MISSING_ERROR), + emailANDUserNameAlreadyExistError( + ResponseMessage.Key.USERNAME_EMAIL_IN_USE, ResponseMessage.Message.USERNAME_EMAIL_IN_USE), + keyCloakDefaultError( + ResponseMessage.Key.KEY_CLOAK_DEFAULT_ERROR, ResponseMessage.Message.KEY_CLOAK_DEFAULT_ERROR), + userRegUnSuccessfull( + ResponseMessage.Key.USER_REG_UNSUCCESSFUL, ResponseMessage.Message.USER_REG_UNSUCCESSFUL), + userUpdationUnSuccessfull( + ResponseMessage.Key.USER_UPDATE_UNSUCCESSFUL, + ResponseMessage.Message.USER_UPDATE_UNSUCCESSFUL), + loginTypeError(ResponseMessage.Key.LOGIN_TYPE_ERROR, ResponseMessage.Message.LOGIN_TYPE_ERROR), + invalidOrgId(ResponseMessage.Key.INVALID_ORG_ID, ResponseMessage.Key.INVALID_ORG_ID), + invalidOrgStatus(ResponseMessage.Key.INVALID_ORG_STATUS, ResponseMessage.Key.INVALID_ORG_STATUS), + invalidOrgStatusTransition( + ResponseMessage.Key.INVALID_ORG_STATUS_TRANSITION, + ResponseMessage.Key.INVALID_ORG_STATUS_TRANSITION), + addressRequired( + ResponseMessage.Key.ADDRESS_REQUIRED_ERROR, ResponseMessage.Message.ADDRESS_REQUIRED_ERROR), + educationRequired( + ResponseMessage.Key.EDUCATION_REQUIRED_ERROR, + ResponseMessage.Message.EDUCATION_REQUIRED_ERROR), + phoneNoRequired( + ResponseMessage.Key.PHONE_NO_REQUIRED_ERROR, ResponseMessage.Message.PHONE_NO_REQUIRED_ERROR), + jobDetailsRequired( + ResponseMessage.Key.JOBDETAILS_REQUIRED_ERROR, + ResponseMessage.Message.JOBDETAILS_REQUIRED_ERROR), + dataAlreadyExist( + ResponseMessage.Key.DATA_ALREADY_EXIST, ResponseMessage.Message.DATA_ALREADY_EXIST), + invalidData(ResponseMessage.Key.INVALID_DATA, ResponseMessage.Message.INVALID_DATA), + invalidCourseId(ResponseMessage.Key.INVALID_COURSE_ID, ResponseMessage.Message.INVALID_COURSE_ID), + orgIdRequired(ResponseMessage.Key.ORG_ID_MISSING, ResponseMessage.Message.ORG_ID_MISSING), + actorConnectionError( + ResponseMessage.Key.ACTOR_CONNECTION_ERROR, ResponseMessage.Message.ACTOR_CONNECTION_ERROR), + userAlreadyExists( + ResponseMessage.Key.USER_ALREADY_EXISTS, ResponseMessage.Message.USER_ALREADY_EXISTS), + invalidUserId(ResponseMessage.Key.INVALID_USER_ID, ResponseMessage.Message.INVALID_USER_ID), + loginIdRequired(ResponseMessage.Key.LOGIN_ID_MISSING, ResponseMessage.Message.LOGIN_ID_MISSING), + contentStatusRequired( + ResponseMessage.Key.CONTENT_STATUS_MISSING_ERROR, + ResponseMessage.Message.CONTENT_STATUS_MISSING_ERROR), + esError(ResponseMessage.Key.ES_ERROR, ResponseMessage.Message.ES_ERROR), + invalidPeriod(ResponseMessage.Key.INVALID_PERIOD, ResponseMessage.Message.INVALID_PERIOD), + userNotFound(ResponseMessage.Key.USER_NOT_FOUND, ResponseMessage.Message.USER_NOT_FOUND), + idRequired(ResponseMessage.Key.ID_REQUIRED_ERROR, ResponseMessage.Message.ID_REQUIRED_ERROR), + dataTypeError(ResponseMessage.Key.DATA_TYPE_ERROR, ResponseMessage.Message.DATA_TYPE_ERROR), + errorAttributeConflict( + ResponseMessage.Key.ERROR_ATTRIBUTE_CONFLICT, + ResponseMessage.Message.ERROR_ATTRIBUTE_CONFLICT), + addressError(ResponseMessage.Key.ADDRESS_ERROR, ResponseMessage.Message.ADDRESS_ERROR), + addressTypeError( + ResponseMessage.Key.ADDRESS_TYPE_ERROR, ResponseMessage.Message.ADDRESS_TYPE_ERROR), + educationNameError( + ResponseMessage.Key.NAME_OF_INSTITUTION_ERROR, + ResponseMessage.Message.NAME_OF_INSTITUTION_ERROR), + jobNameError(ResponseMessage.Key.JOB_NAME_ERROR, ResponseMessage.Message.JOB_NAME_ERROR), + educationDegreeError( + ResponseMessage.Key.EDUCATION_DEGREE_ERROR, ResponseMessage.Message.EDUCATION_DEGREE_ERROR), + organisationNameError( + ResponseMessage.Key.NAME_OF_ORGANISATION_ERROR, + ResponseMessage.Message.NAME_OF_ORGANISATION_ERROR), + rolesRequired(ResponseMessage.Key.ROLES_MISSING, ResponseMessage.Message.ROLES_MISSING), + emptyRolesProvided( + ResponseMessage.Key.EMPTY_ROLES_PROVIDED, ResponseMessage.Message.EMPTY_ROLES_PROVIDED), + invalidDateFormat( + ResponseMessage.Key.INVALID_DATE_FORMAT, ResponseMessage.Message.INVALID_DATE_FORMAT), + sourceAndExternalIdAlreadyExist( + ResponseMessage.Key.SRC_EXTERNAL_ID_ALREADY_EXIST, + ResponseMessage.Message.SRC_EXTERNAL_ID_ALREADY_EXIST), + userAlreadyEnrolledCourse( + ResponseMessage.Key.USER_ALREADY_ENROLLED_COURSE, + ResponseMessage.Message.USER_ALREADY_ENROLLED_COURSE), + userNotEnrolledCourse( + ResponseMessage.Key.USER_NOT_ENROLLED_COURSE, + ResponseMessage.Message.USER_NOT_ENROLLED_COURSE), + courseBatchAlreadyCompleted( + ResponseMessage.Key.COURSE_BATCH_ALREADY_COMPLETED, + ResponseMessage.Message.COURSE_BATCH_ALREADY_COMPLETED), + courseBatchEnrollmentDateEnded( + ResponseMessage.Key.COURSE_BATCH_ENROLLMENT_DATE_ENDED, + ResponseMessage.Message.COURSE_BATCH_ENROLLMENT_DATE_ENDED), + userAlreadyCompletedCourse( + ResponseMessage.Key.USER_ALREADY_COMPLETED_COURSE, + ResponseMessage.Message.USER_ALREADY_COMPLETED_COURSE), + pageAlreadyExist( + ResponseMessage.Key.PAGE_ALREADY_EXIST, ResponseMessage.Message.PAGE_ALREADY_EXIST), + contentTypeRequiredError( + ResponseMessage.Key.CONTENT_TYPE_ERROR, ResponseMessage.Message.CONTENT_TYPE_ERROR), + invalidPropertyError( + ResponseMessage.Key.INVALID_PROPERTY_ERROR, ResponseMessage.Message.INVALID_PROPERTY_ERROR), + usernameOrUserIdError( + ResponseMessage.Key.USER_NAME_OR_ID_ERROR, ResponseMessage.Message.USER_NAME_OR_ID_ERROR), + emailVerifiedError( + ResponseMessage.Key.EMAIL_VERIFY_ERROR, ResponseMessage.Message.EMAIL_VERIFY_ERROR), + phoneVerifiedError( + ResponseMessage.Key.PHONE_VERIFY_ERROR, ResponseMessage.Message.PHONE_VERIFY_ERROR), + bulkUserUploadError( + ResponseMessage.Key.BULK_USER_UPLOAD_ERROR, ResponseMessage.Message.BULK_USER_UPLOAD_ERROR), + dataSizeError(ResponseMessage.Key.DATA_SIZE_EXCEEDED, ResponseMessage.Message.DATA_SIZE_EXCEEDED), + InvalidColumnError( + ResponseMessage.Key.INVALID_COLUMN_NAME, ResponseMessage.Message.INVALID_COLUMN_NAME), + userAccountlocked( + ResponseMessage.Key.USER_ACCOUNT_BLOCKED, ResponseMessage.Message.USER_ACCOUNT_BLOCKED), + userAlreadyActive( + ResponseMessage.Key.USER_ALREADY_ACTIVE, ResponseMessage.Message.USER_ALREADY_ACTIVE), + userAlreadyInactive( + ResponseMessage.Key.USER_ALREADY_INACTIVE, ResponseMessage.Message.USER_ALREADY_INACTIVE), + enrolmentTypeRequired( + ResponseMessage.Key.ENROLMENT_TYPE_REQUIRED, ResponseMessage.Message.ENROLMENT_TYPE_REQUIRED), + enrolmentIncorrectValue( + ResponseMessage.Key.ENROLMENT_TYPE_VALUE_ERROR, + ResponseMessage.Message.ENROLMENT_TYPE_VALUE_ERROR), + courseBatchStartDateRequired( + ResponseMessage.Key.COURSE_BATCH_START_DATE_REQUIRED, + ResponseMessage.Message.COURSE_BATCH_START_DATE_REQUIRED), + courseBatchStartDateError( + ResponseMessage.Key.COURSE_BATCH_START_DATE_INVALID, + ResponseMessage.Message.COURSE_BATCH_START_DATE_INVALID), + dateFormatError( + ResponseMessage.Key.DATE_FORMAT_ERRROR, ResponseMessage.Message.DATE_FORMAT_ERRROR), + endDateError(ResponseMessage.Key.END_DATE_ERROR, ResponseMessage.Message.END_DATE_ERROR), + enrollmentEndDateStartError( + ResponseMessage.Key.ENROLLMENT_END_DATE_START_ERROR, + ResponseMessage.Message.ENROLLMENT_END_DATE_START_ERROR), + enrollmentEndDateEndError( + ResponseMessage.Key.ENROLLMENT_END_DATE_END_ERROR, + ResponseMessage.Message.ENROLLMENT_END_DATE_END_ERROR), + enrollmentEndDateUpdateError( + ResponseMessage.Key.ENROLLMENT_END_DATE_UPDATE_ERROR, + ResponseMessage.Message.ENROLLMENT_END_DATE_UPDATE_ERROR), + csvError(ResponseMessage.Key.INVALID_CSV_FILE, ResponseMessage.Message.INVALID_CSV_FILE), + invalidCourseBatchId( + ResponseMessage.Key.INVALID_COURSE_BATCH_ID, ResponseMessage.Message.INVALID_COURSE_BATCH_ID), + courseBatchIdRequired( + ResponseMessage.Key.COURSE_BATCH_ID_MISSING, ResponseMessage.Message.COURSE_BATCH_ID_MISSING), + enrollmentTypeValidation( + ResponseMessage.Key.ENROLLMENT_TYPE_VALIDATION, + ResponseMessage.Message.ENROLLMENT_TYPE_VALIDATION), + courseCreatedForIsNull( + ResponseMessage.Key.COURSE_CREATED_FOR_NULL, ResponseMessage.Message.COURSE_CREATED_FOR_NULL), + userNotAssociatedToOrg( + ResponseMessage.Key.USER_NOT_BELONGS_TO_ANY_ORG, + ResponseMessage.Message.USER_NOT_BELONGS_TO_ANY_ORG), + invalidObjectType( + ResponseMessage.Key.INVALID_OBJECT_TYPE, ResponseMessage.Message.INVALID_OBJECT_TYPE), + progressStatusError( + ResponseMessage.Key.INVALID_PROGRESS_STATUS, ResponseMessage.Message.INVALID_PROGRESS_STATUS), + courseBatchStartPassedDateError( + ResponseMessage.Key.COURSE_BATCH_START_PASSED_DATE_INVALID, + ResponseMessage.Message.COURSE_BATCH_START_PASSED_DATE_INVALID), + csvFileEmpty(ResponseMessage.Key.EMPTY_CSV_FILE, ResponseMessage.Message.EMPTY_CSV_FILE), + invalidRootOrgData( + ResponseMessage.Key.INVALID_ROOT_ORG_DATA, ResponseMessage.Message.INVALID_ROOT_ORG_DATA), + noDataForConsumption(ResponseMessage.Key.NO_DATA, ResponseMessage.Message.NO_DATA), + invalidChannel(ResponseMessage.Key.INVALID_CHANNEL, ResponseMessage.Message.INVALID_CHANNEL), + invalidProcessId( + ResponseMessage.Key.INVALID_PROCESS_ID, ResponseMessage.Message.INVALID_PROCESS_ID), + emailSubjectError( + ResponseMessage.Key.EMAIL_SUBJECT_ERROR, ResponseMessage.Message.EMAIL_SUBJECT_ERROR), + emailBodyError(ResponseMessage.Key.EMAIL_BODY_ERROR, ResponseMessage.Message.EMAIL_BODY_ERROR), + recipientAddressError( + ResponseMessage.Key.RECIPIENT_ADDRESS_ERROR, ResponseMessage.Message.RECIPIENT_ADDRESS_ERROR), + storageContainerNameMandatory( + ResponseMessage.Key.STORAGE_CONTAINER_NAME_MANDATORY, + ResponseMessage.Message.STORAGE_CONTAINER_NAME_MANDATORY), + userOrgAssociationError( + ResponseMessage.Key.USER_ORG_ASSOCIATION_ERROR, + ResponseMessage.Message.USER_ORG_ASSOCIATION_ERROR), + cloudServiceError( + ResponseMessage.Key.CLOUD_SERVICE_ERROR, ResponseMessage.Message.CLOUD_SERVICE_ERROR), + badgeTypeIdMandatory( + ResponseMessage.Key.BADGE_TYPE_ID_ERROR, ResponseMessage.Message.BADGE_TYPE_ID_ERROR), + receiverIdMandatory( + ResponseMessage.Key.RECEIVER_ID_ERROR, ResponseMessage.Message.RECEIVER_ID_ERROR), + invalidReceiverId( + ResponseMessage.Key.INVALID_RECEIVER_ID, ResponseMessage.Message.INVALID_RECEIVER_ID), + invalidBadgeTypeId( + ResponseMessage.Key.INVALID_BADGE_ID, ResponseMessage.Message.INVALID_BADGE_ID), + invalidRole(ResponseMessage.Key.INVALID_ROLE, ResponseMessage.Message.INVALID_ROLE), + saltValue(ResponseMessage.Key.INVALID_SALT, ResponseMessage.Message.INVALID_SALT), + orgTypeMandatory( + ResponseMessage.Key.ORG_TYPE_MANDATORY, ResponseMessage.Message.ORG_TYPE_MANDATORY), + orgTypeAlreadyExist( + ResponseMessage.Key.ORG_TYPE_ALREADY_EXIST, ResponseMessage.Message.ORG_TYPE_ALREADY_EXIST), + orgTypeIdRequired( + ResponseMessage.Key.ORG_TYPE_ID_REQUIRED_ERROR, + ResponseMessage.Message.ORG_TYPE_ID_REQUIRED_ERROR), + titleRequired(ResponseMessage.Key.TITLE_REQUIRED, ResponseMessage.Message.TITLE_REQUIRED), + noteRequired(ResponseMessage.Key.NOTE_REQUIRED, ResponseMessage.Message.NOTE_REQUIRED), + contentIdError(ResponseMessage.Key.CONTENT_ID_ERROR, ResponseMessage.Message.CONTENT_ID_ERROR), + invalidTags(ResponseMessage.Key.INVALID_TAGS, ResponseMessage.Message.INVALID_TAGS), + invalidNoteId(ResponseMessage.Key.NOTE_ID_INVALID, ResponseMessage.Message.NOTE_ID_INVALID), + userDataEncryptionError( + ResponseMessage.Key.USER_DATA_ENCRYPTION_ERROR, + ResponseMessage.Message.USER_DATA_ENCRYPTION_ERROR), + phoneNoFormatError( + ResponseMessage.Key.INVALID_PHONE_NO_FORMAT, ResponseMessage.Message.INVALID_PHONE_NO_FORMAT), + invalidWebPageData( + ResponseMessage.Key.INVALID_WEBPAGE_DATA, ResponseMessage.Message.INVALID_WEBPAGE_DATA), + invalidMediaType( + ResponseMessage.Key.INVALID_MEDIA_TYPE, ResponseMessage.Message.INVALID_MEDIA_TYPE), + invalidWebPageUrl( + ResponseMessage.Key.INVALID_WEBPAGE_URL, ResponseMessage.Message.INVALID_WEBPAGE_URL), + invalidDateRange( + ResponseMessage.Key.INVALID_DATE_RANGE, ResponseMessage.Message.INVALID_DATE_RANGE), + invalidBatchEndDateError( + ResponseMessage.Key.INVALID_BATCH_END_DATE_ERROR, + ResponseMessage.Message.INVALID_BATCH_END_DATE_ERROR), + invalidBatchStartDateError( + ResponseMessage.Key.INVALID_BATCH_START_DATE_ERROR, + ResponseMessage.Message.INVALID_BATCH_START_DATE_ERROR), + courseBatchEndDateError( + ResponseMessage.Key.COURSE_BATCH_END_DATE_ERROR, + ResponseMessage.Message.COURSE_BATCH_END_DATE_ERROR), + BatchCloseError( + ResponseMessage.Key.COURSE_BATCH_IS_CLOSED_ERROR, + ResponseMessage.Message.COURSE_BATCH_IS_CLOSED_ERROR), + newPasswordRequired( + ResponseMessage.Key.CONFIIRM_PASSWORD_MISSING, + ResponseMessage.Message.CONFIIRM_PASSWORD_MISSING), + newPasswordEmpty( + ResponseMessage.Key.CONFIIRM_PASSWORD_EMPTY, ResponseMessage.Message.CONFIIRM_PASSWORD_EMPTY), + samePasswordError( + ResponseMessage.Key.SAME_PASSWORD_ERROR, ResponseMessage.Message.SAME_PASSWORD_ERROR), + endorsedUserIdRequired( + ResponseMessage.Key.ENDORSED_USER_ID_REQUIRED, + ResponseMessage.Message.ENDORSED_USER_ID_REQUIRED), + canNotEndorse(ResponseMessage.Key.CAN_NOT_ENDORSE, ResponseMessage.Message.CAN_NOT_ENDORSE), + invalidOrgTypeId( + ResponseMessage.Key.INVALID_ORG_TYPE_ID_ERROR, + ResponseMessage.Message.INVALID_ORG_TYPE_ID_ERROR), + invalidOrgType( + ResponseMessage.Key.INVALID_ORG_TYPE_ERROR, ResponseMessage.Message.INVALID_ORG_TYPE_ERROR), + tableOrDocNameError( + ResponseMessage.Key.TABLE_OR_DOC_NAME_ERROR, ResponseMessage.Message.TABLE_OR_DOC_NAME_ERROR), + emailorPhoneRequired( + ResponseMessage.Key.EMAIL_OR_PHONE_MISSING, ResponseMessage.Message.EMAIL_OR_PHONE_MISSING), + emailorPhoneorManagedByRequired( + ResponseMessage.Key.EMAIL_OR_PHONE_OR_MANAGEDBY_MISSING, + ResponseMessage.Message.EMAIL_OR_PHONE_OR_MANAGEDBY_MISSING), + OnlyEmailorPhoneorManagedByRequired( + ResponseMessage.Key.ONLY_EMAIL_OR_PHONE_OR_MANAGEDBY_REQUIRED, + ResponseMessage.Message.ONLY_EMAIL_OR_PHONE_OR_MANAGEDBY_REQUIRED), + PhoneNumberInUse( + ResponseMessage.Key.PHONE_ALREADY_IN_USE, ResponseMessage.Message.PHONE_ALREADY_IN_USE), + invalidClientName( + ResponseMessage.Key.INVALID_CLIENT_NAME, ResponseMessage.Message.INVALID_CLIENT_NAME), + invalidClientId(ResponseMessage.Key.INVALID_CLIENT_ID, ResponseMessage.Message.INVALID_CLIENT_ID), + userPhoneUpdateFailed( + ResponseMessage.Key.USER_PHONE_UPDATE_FAILED, + ResponseMessage.Message.USER_PHONE_UPDATE_FAILED), + esUpdateFailed(ResponseMessage.Key.ES_UPDATE_FAILED, ResponseMessage.Message.ES_UPDATE_FAILED), + updateFailed(ResponseMessage.Key.UPDATE_FAILED, ResponseMessage.Message.UPDATE_FAILED), + invalidTypeValue(ResponseMessage.Key.INVALID_TYPE_VALUE, ResponseMessage.Key.INVALID_TYPE_VALUE), + invalidLocationId( + ResponseMessage.Key.INVALID_LOCATION_ID, ResponseMessage.Message.INVALID_LOCATION_ID), + invalidHashTagId( + ResponseMessage.Key.INVALID_HASHTAG_ID, ResponseMessage.Message.INVALID_HASHTAG_ID), + invalidUsrOrgData( + ResponseMessage.Key.INVALID_USR_ORG_DATA, ResponseMessage.Message.INVALID_USR_ORG_DATA), + visibilityInvalid( + ResponseMessage.Key.INVALID_VISIBILITY_REQUEST, + ResponseMessage.Message.INVALID_VISIBILITY_REQUEST), + invalidTopic(ResponseMessage.Key.INVALID_TOPIC_NAME, ResponseMessage.Message.INVALID_TOPIC_NAME), + invalidTopicData( + ResponseMessage.Key.INVALID_TOPIC_DATA, ResponseMessage.Message.INVALID_TOPIC_DATA), + invalidNotificationType( + ResponseMessage.Key.INVALID_NOTIFICATION_TYPE, + ResponseMessage.Message.INVALID_NOTIFICATION_TYPE), + notificationTypeSupport( + ResponseMessage.Key.INVALID_NOTIFICATION_TYPE_SUPPORT, + ResponseMessage.Message.INVALID_NOTIFICATION_TYPE_SUPPORT), + emailInUse(ResponseMessage.Key.EMAIL_IN_USE, ResponseMessage.Message.EMAIL_IN_USE), + invalidPhoneNumber( + ResponseMessage.Key.INVALID_PHONE_NUMBER, ResponseMessage.Message.INVALID_PHONE_NUMBER), + invalidCountryCode( + ResponseMessage.Key.INVALID_COUNTRY_CODE, ResponseMessage.Message.INVALID_COUNTRY_CODE), + locationIdRequired( + ResponseMessage.Key.LOCATION_ID_REQUIRED, ResponseMessage.Message.LOCATION_ID_REQUIRED), + functionalityMissing(ResponseMessage.Key.NOT_SUPPORTED, ResponseMessage.Message.NOT_SUPPORTED), + userNameOrUserIdRequired( + ResponseMessage.Key.USERNAME_USERID_MISSING, ResponseMessage.Message.USERNAME_USERID_MISSING), + channelRegFailed( + ResponseMessage.Key.CHANNEL_REG_FAILED, ResponseMessage.Message.CHANNEL_REG_FAILED), + invalidCourseCreatorId( + ResponseMessage.Key.INVALID_COURSE_CREATOR_ID, + ResponseMessage.Message.INVALID_COURSE_CREATOR_ID), + userNotAssociatedToRootOrg( + ResponseMessage.Key.USER_NOT_ASSOCIATED_TO_ROOT_ORG, + ResponseMessage.Message.USER_NOT_ASSOCIATED_TO_ROOT_ORG), + slugIsNotUnique( + ResponseMessage.Key.SLUG_IS_NOT_UNIQUE, ResponseMessage.Message.SLUG_IS_NOT_UNIQUE), + invalidDataForCreateBadgeIssuer( + ResponseMessage.Key.INVALID_CREATE_BADGE_ISSUER_DATA, + ResponseMessage.Message.INVALID_CREATE_BADGE_ISSUER_DATA), + issuerIdRequired( + ResponseMessage.Key.ISSUER_ID_REQUIRED, ResponseMessage.Message.ISSUER_ID_REQUIRED), + badgeIdRequired(ResponseMessage.Key.BADGE_ID_REQUIRED, ResponseMessage.Message.BADGE_ID_REQUIRED), + badgeNameRequired( + ResponseMessage.Key.BADGE_NAME_REQUIRED, ResponseMessage.Message.BADGE_NAME_REQUIRED), + badgeDescriptionRequired( + ResponseMessage.Key.BADGE_DESCRIPTION_REQUIRED, + ResponseMessage.Message.BADGE_DESCRIPTION_REQUIRED), + badgeCriteriaRequired( + ResponseMessage.Key.BADGE_CRITERIA_REQUIRED, ResponseMessage.Message.BADGE_CRITERIA_REQUIRED), + rootOrgIdRequired( + ResponseMessage.Key.ROOT_ORG_ID_REQUIRED, ResponseMessage.Message.ROOT_ORG_ID_REQUIRED), + badgeTypeRequired( + ResponseMessage.Key.BADGE_TYPE_REQUIRED, ResponseMessage.Message.BADGE_TYPE_REQUIRED), + invalidBadgeType( + ResponseMessage.Key.INVALID_BADGE_TYPE, ResponseMessage.Message.INVALID_BADGE_TYPE), + invalidBadgeSubtype( + ResponseMessage.Key.INVALID_BADGE_SUBTYPE, ResponseMessage.Message.INVALID_BADGE_SUBTYPE), + invalidBadgeRole( + ResponseMessage.Key.INVALID_BADGE_ROLE, ResponseMessage.Message.INVALID_BADGE_ROLE), + badgeRolesRequired( + ResponseMessage.Key.BADGE_ROLES_REQUIRED, ResponseMessage.Message.BADGE_ROLES_REQUIRED), + badgeImageRequired( + ResponseMessage.Key.BADGE_IMAGE_REQUIRED, ResponseMessage.Message.BADGE_IMAGE_REQUIRED), + recipientEmailRequired( + ResponseMessage.Key.RECIPIENT_EMAIL_REQUIRED, + ResponseMessage.Message.RECIPIENT_EMAIL_REQUIRED), + evidenceRequired( + ResponseMessage.Key.ASSERTION_EVIDENCE_REQUIRED, + ResponseMessage.Message.ASSERTION_EVIDENCE_REQUIRED), + assertionIdRequired( + ResponseMessage.Key.ASSERTION_ID_REQUIRED, ResponseMessage.Message.ASSERTION_ID_REQUIRED), + recipientIdRequired( + ResponseMessage.Key.RECIPIENT_ID_REQUIRED, ResponseMessage.Message.RECIPIENT_ID_REQUIRED), + recipientTypeRequired( + ResponseMessage.Key.RECIPIENT_TYPE_REQUIRED, ResponseMessage.Message.RECIPIENT_TYPE_REQUIRED), + badgingserverError( + ResponseMessage.Key.BADGING_SERVER_ERROR, ResponseMessage.Message.BADGING_SERVER_ERROR), + resourceNotFound( + ResponseMessage.Key.RESOURCE_NOT_FOUND, ResponseMessage.Message.RESOURCE_NOT_FOUND), + sizeLimitExceed( + ResponseMessage.Key.MAX_ALLOWED_SIZE_LIMIT_EXCEED, + ResponseMessage.Message.MAX_ALLOWED_SIZE_LIMIT_EXCEED), + slugRequired(ResponseMessage.Key.SLUG_REQUIRED, ResponseMessage.Message.SLUG_REQUIRED), + invalidIssuerId(ResponseMessage.Key.INVALID_ISSUER_ID, ResponseMessage.Message.INVALID_ISSUER_ID), + revocationReasonRequired( + ResponseMessage.Key.REVOCATION_REASON_REQUIRED, + ResponseMessage.Message.REVOCATION_REASON_REQUIRED), + badgeAssertionAlreadyRevoked( + ResponseMessage.Key.ALREADY_REVOKED, ResponseMessage.Message.ALREADY_REVOKED), + invalidRecipientType( + ResponseMessage.Key.INVALID_RECIPIENT_TYPE, ResponseMessage.Message.INVALID_RECIPIENT_TYPE), + customClientError( + ResponseMessage.Key.CUSTOM_CLIENT_ERROR, ResponseMessage.Message.CUSTOM_CLIENT_ERROR), + customResourceNotFound( + ResponseMessage.Key.CUSTOM_RESOURCE_NOT_FOUND_ERROR, + ResponseMessage.Message.CUSTOM_RESOURCE_NOT_FOUND_ERROR), + customServerError( + ResponseMessage.Key.CUSTOM_SERVER_ERROR, ResponseMessage.Message.CUSTOM_SERVER_ERROR), + inactiveUser(ResponseMessage.Key.INACTIVE_USER, ResponseMessage.Message.INACTIVE_USER), + userInactiveForThisOrg( + ResponseMessage.Key.USER_INACTIVE_FOR_THIS_ORG, + ResponseMessage.Message.USER_INACTIVE_FOR_THIS_ORG), + userUpdateToOrgFailed( + ResponseMessage.Key.USER_UPDATE_FAILED_FOR_THIS_ORG, + ResponseMessage.Message.USER_UPDATE_FAILED_FOR_THIS_ORG), + preferenceKeyMissing( + ResponseMessage.Key.USER_UPDATE_FAILED_FOR_THIS_ORG, + ResponseMessage.Message.USER_UPDATE_FAILED_FOR_THIS_ORG), + pageDoesNotExist(ResponseMessage.Key.PAGE_NOT_EXIST, ResponseMessage.Message.PAGE_NOT_EXIST), + sectionDoesNotExist( + ResponseMessage.Key.SECTION_NOT_EXIST, ResponseMessage.Message.SECTION_NOT_EXIST), + orgDoesNotExist(ResponseMessage.Key.ORG_NOT_EXIST, ResponseMessage.Message.ORG_NOT_EXIST), + invalidPageSource( + ResponseMessage.Key.INVALID_PAGE_SOURCE, ResponseMessage.Message.INVALID_PAGE_SOURCE), + badgeSubTypeRequired( + ResponseMessage.Key.BADGE_SUBTYPE_REQUIRED, ResponseMessage.Message.BADGE_SUBTYPE_REQUIRED), + locationTypeRequired( + ResponseMessage.Key.LOCATION_TYPE_REQUIRED, ResponseMessage.Message.LOCATION_TYPE_REQUIRED), + invalidRequestDataForLocation( + ResponseMessage.Key.INVALID_REQUEST_DATA_FOR_LOCATION, + ResponseMessage.Message.INVALID_REQUEST_DATA_FOR_LOCATION), + alreadyExists(ResponseMessage.Key.ALREADY_EXISTS, ResponseMessage.Message.ALREADY_EXISTS), + invalidValue(ResponseMessage.Key.INVALID_VALUE, ResponseMessage.Message.INVALID_VALUE), + parentCodeAndIdValidationError( + ResponseMessage.Key.PARENT_CODE_AND_PARENT_ID_MISSING, + ResponseMessage.Message.PARENT_CODE_AND_PARENT_ID_MISSING), + invalidParameter( + ResponseMessage.Key.INVALID_PARAMETER, ResponseMessage.Message.INVALID_PARAMETER), + invalidLocationDeleteRequest( + ResponseMessage.Key.INVALID_LOCATION_DELETE_REQUEST, + ResponseMessage.Message.INVALID_LOCATION_DELETE_REQUEST), + locationTypeConflicts( + ResponseMessage.Key.LOCATION_TYPE_CONFLICTS, ResponseMessage.Message.LOCATION_TYPE_CONFLICTS), + mandatoryParamsMissing( + ResponseMessage.Key.MANDATORY_PARAMETER_MISSING, + ResponseMessage.Message.MANDATORY_PARAMETER_MISSING), + errorMandatoryParamsEmpty( + ResponseMessage.Key.ERROR_MANDATORY_PARAMETER_EMPTY, + ResponseMessage.Message.ERROR_MANDATORY_PARAMETER_EMPTY), + errorNoFrameworkFound( + ResponseMessage.Key.ERROR_NO_FRAMEWORK_FOUND, + ResponseMessage.Message.ERROR_NO_FRAMEWORK_FOUND), + unupdatableField( + ResponseMessage.Key.UPDATE_NOT_ALLOWED, ResponseMessage.Message.UPDATE_NOT_ALLOWED), + mandatoryHeadersMissing( + ResponseMessage.Key.MANDATORY_HEADER_MISSING, + ResponseMessage.Message.MANDATORY_HEADER_MISSING), + invalidParameterValue( + ResponseMessage.Key.INVALID_PARAMETER_VALUE, ResponseMessage.Message.INVALID_PARAMETER_VALUE), + parentNotAllowed( + ResponseMessage.Key.PARENT_NOT_ALLOWED, ResponseMessage.Message.PARENT_NOT_ALLOWED), + missingFileAttachment( + ResponseMessage.Key.MISSING_FILE_ATTACHMENT, ResponseMessage.Message.MISSING_FILE_ATTACHMENT), + fileAttachmentSizeNotConfigured( + ResponseMessage.Key.FILE_ATTACHMENT_SIZE_NOT_CONFIGURED, + ResponseMessage.Message.FILE_ATTACHMENT_SIZE_NOT_CONFIGURED), + emptyFile(ResponseMessage.Key.EMPTY_FILE, ResponseMessage.Message.EMPTY_FILE), + invalidColumns(ResponseMessage.Key.INVALID_COLUMNS, ResponseMessage.Message.INVALID_COLUMNS), + conflictingOrgLocations( + ResponseMessage.Key.CONFLICTING_ORG_LOCATIONS, + ResponseMessage.Message.CONFLICTING_ORG_LOCATIONS), + unableToCommunicateWithActor( + ResponseMessage.Key.UNABLE_TO_COMMUNICATE_WITH_ACTOR, + ResponseMessage.Message.UNABLE_TO_COMMUNICATE_WITH_ACTOR), + emptyHeaderLine(ResponseMessage.Key.EMPTY_HEADER_LINE, ResponseMessage.Message.EMPTY_HEADER_LINE), + invalidRequestParameter( + ResponseMessage.Key.INVALID_REQUEST_PARAMETER, + ResponseMessage.Message.INVALID_REQUEST_PARAMETER), + rootOrgAssociationError( + ResponseMessage.Key.ROOT_ORG_ASSOCIATION_ERROR, + ResponseMessage.Message.ROOT_ORG_ASSOCIATION_ERROR), + dependentParameterMissing( + ResponseMessage.Key.DEPENDENT_PARAMETER_MISSING, + ResponseMessage.Message.DEPENDENT_PARAMETER_MISSING), + externalIdNotFound( + ResponseMessage.Key.EXTERNALID_NOT_FOUND, ResponseMessage.Message.EXTERNALID_NOT_FOUND), + externalIdAssignedToOtherUser( + ResponseMessage.Key.EXTERNALID_ASSIGNED_TO_OTHER_USER, + ResponseMessage.Message.EXTERNALID_ASSIGNED_TO_OTHER_USER), + dependentParamsMissing( + ResponseMessage.Key.DEPENDENT_PARAMETER_MISSING, + ResponseMessage.Message.DEPENDENT_PARAMS_MISSING), + mandatoryConfigParamMissing( + ResponseMessage.Key.MANDATORY_CONFIG_PARAMETER_MISSING, + ResponseMessage.Message.MANDATORY_CONFIG_PARAMETER_MISSING), + cassandraConnectionEstablishmentFailed( + ResponseMessage.Key.CASSANDRA_CONNECTION_ESTABLISHMENT_FAILED, + ResponseMessage.Message.CASSANDRA_CONNECTION_ESTABLISHMENT_FAILED), + commonAttributeMismatch( + ResponseMessage.Key.COMMON_ATTRIBUTE_MISMATCH, + ResponseMessage.Message.COMMON_ATTRIBUTE_MISMATCH), + multipleCoursesNotAllowedForBatch( + ResponseMessage.Key.MULTIPLE_COURSES_FOR_BATCH, + ResponseMessage.Message.MULTIPLE_COURSES_FOR_BATCH), + errorJsonTransformInvalidTypeConfig( + ResponseMessage.Key.ERROR_JSON_TRANSFORM_INVALID_TYPE_CONFIG, + ResponseMessage.Message.ERROR_JSON_TRANSFORM_INVALID_TYPE_CONFIG), + errorJsonTransformInvalidDateFormat( + ResponseMessage.Key.ERROR_JSON_TRANSFORM_INVALID_DATE_FORMAT, + ResponseMessage.Message.ERROR_JSON_TRANSFORM_INVALID_DATE_FORMAT), + errorJsonTransformInvalidInput( + ResponseMessage.Key.ERROR_JSON_TRANSFORM_INVALID_INPUT, + ResponseMessage.Message.ERROR_JSON_TRANSFORM_INVALID_INPUT), + errorJsonTransformInvalidEnumInput( + ResponseMessage.Key.ERROR_JSON_TRANSFORM_INVALID_ENUM_INPUT, + ResponseMessage.Message.ERROR_JSON_TRANSFORM_INVALID_ENUM_INPUT), + errorJsonTransformEnumValuesEmpty( + ResponseMessage.Key.ERROR_JSON_TRANSFORM_ENUM_VALUES_EMPTY, + ResponseMessage.Message.ERROR_JSON_TRANSFORM_ENUM_VALUES_EMPTY), + errorJsonTransformBasicConfigMissing( + ResponseMessage.Key.ERROR_JSON_TRANSFORM_BASIC_CONFIG_MISSING, + ResponseMessage.Message.ERROR_JSON_TRANSFORM_BASIC_CONFIG_MISSING), + errorJsonTransformInvalidFilterConfig( + ResponseMessage.Key.ERROR_JSON_TRANSFORM_INVALID_FILTER_CONFIG, + ResponseMessage.Message.ERROR_JSON_TRANSFORM_INVALID_FILTER_CONFIG), + errorLoadConfig(ResponseMessage.Key.ERROR_LOAD_CONFIG, ResponseMessage.Message.ERROR_LOAD_CONFIG), + errorRegistryClientCreation( + ResponseMessage.Key.ERROR_REGISTRY_CLIENT_CREATION, + ResponseMessage.Message.ERROR_REGISTRY_CLIENT_CREATION), + errorRegistryAddEntity( + ResponseMessage.Key.ERROR_REGISTRY_ADD_ENTITY, + ResponseMessage.Message.ERROR_REGISTRY_ADD_ENTITY), + errorRegistryReadEntity( + ResponseMessage.Key.ERROR_REGISTRY_READ_ENTITY, + ResponseMessage.Message.ERROR_REGISTRY_READ_ENTITY), + errorRegistryUpdateEntity( + ResponseMessage.Key.ERROR_REGISTRY_UPDATE_ENTITY, + ResponseMessage.Message.ERROR_REGISTRY_UPDATE_ENTITY), + errorRegistryDeleteEntity( + ResponseMessage.Key.ERROR_REGISTRY_DELETE_ENTITY, + ResponseMessage.Message.ERROR_REGISTRY_DELETE_ENTITY), + errorRegistryParseResponse( + ResponseMessage.Key.ERROR_REGISTRY_PARSE_RESPONSE, + ResponseMessage.Message.ERROR_REGISTRY_PARSE_RESPONSE), + errorRegistryEntityTypeBlank( + ResponseMessage.Key.ERROR_REGISTRY_ENTITY_TYPE_BLANK, + ResponseMessage.Message.ERROR_REGISTRY_ENTITY_TYPE_BLANK), + errorRegistryEntityIdBlank( + ResponseMessage.Key.ERROR_REGISTRY_ENTITY_ID_BLANK, + ResponseMessage.Message.ERROR_REGISTRY_ENTITY_ID_BLANK), + errorRegistryAccessTokenBlank( + ResponseMessage.Key.ERROR_REGISTRY_ACCESS_TOKEN_BLANK, + ResponseMessage.Message.ERROR_REGISTRY_ACCESS_TOKEN_BLANK), + duplicateExternalIds( + ResponseMessage.Key.DUPLICATE_EXTERNAL_IDS, ResponseMessage.Message.DUPLICATE_EXTERNAL_IDS), + invalidDuplicateValue( + ResponseMessage.Key.INVALID_DUPLICATE_VALUE, ResponseMessage.Message.INVALID_DUPLICATE_VALUE), + emailNotSentRecipientsExceededMaxLimit( + ResponseMessage.Key.EMAIL_RECIPIENTS_EXCEEDS_MAX_LIMIT, + ResponseMessage.Message.EMAIL_RECIPIENTS_EXCEEDS_MAX_LIMIT), + emailNotSentRecipientsZero( + ResponseMessage.Key.NO_EMAIL_RECIPIENTS, ResponseMessage.Message.NO_EMAIL_RECIPIENTS), + parameterMismatch( + ResponseMessage.Key.PARAMETER_MISMATCH, ResponseMessage.Message.PARAMETER_MISMATCH), + errorForbidden(ResponseMessage.Key.FORBIDDEN, ResponseMessage.Message.FORBIDDEN), + errorConfigLoadEmptyString( + ResponseMessage.Key.ERROR_CONFIG_LOAD_EMPTY_STRING, + ResponseMessage.Message.ERROR_CONFIG_LOAD_EMPTY_STRING), + errorConfigLoadParseString( + ResponseMessage.Key.ERROR_CONFIG_LOAD_PARSE_STRING, + ResponseMessage.Message.ERROR_CONFIG_LOAD_PARSE_STRING), + errorConfigLoadEmptyConfig( + ResponseMessage.Key.ERROR_CONFIG_LOAD_EMPTY_CONFIG, + ResponseMessage.Message.ERROR_CONFIG_LOAD_EMPTY_CONFIG), + errorConflictingFieldConfiguration( + ResponseMessage.Key.ERROR_CONFLICTING_FIELD_CONFIGURATION, + ResponseMessage.Message.ERROR_CONFLICTING_FIELD_CONFIGURATION), + errorSystemSettingNotFound( + ResponseMessage.Key.ERROR_SYSTEM_SETTING_NOT_FOUND, + ResponseMessage.Message.ERROR_SYSTEM_SETTING_NOT_FOUND), + errorNoRootOrgAssociated( + ResponseMessage.Key.ERROR_NO_ROOT_ORG_ASSOCIATED, + ResponseMessage.Message.ERROR_NO_ROOT_ORG_ASSOCIATED), + errorInactiveCustodianOrg( + ResponseMessage.Key.ERROR_INACTIVE_CUSTODIAN_ORG, + ResponseMessage.Message.ERROR_INACTIVE_CUSTODIAN_ORG), + errorUnsupportedCloudStorage( + ResponseMessage.Key.ERROR_UNSUPPORTED_CLOUD_STORAGE, + ResponseMessage.Message.ERROR_UNSUPPORTED_CLOUD_STORAGE), + errorUnsupportedField( + ResponseMessage.Key.ERROR_UNSUPPORTED_FIELD, ResponseMessage.Message.ERROR_UNSUPPORTED_FIELD), + errorGenerateDownloadLink( + ResponseMessage.Key.ERROR_GENERATE_DOWNLOAD_LINK, + ResponseMessage.Message.ERROR_GENERATE_DOWNLOAD_LINK), + errorUnavailableDownloadLink( + ResponseMessage.Key.ERROR_DOWNLOAD_LINK_UNAVAILABLE, + ResponseMessage.Message.ERROR_DOWNLOAD_LINK_UNAVAILABLE), + errorSavingStorageDetails( + ResponseMessage.Key.ERROR_SAVING_STORAGE_DETAILS, + ResponseMessage.Message.ERROR_SAVING_STORAGE_DETAILS), + errorCsvNoDataRows( + ResponseMessage.Key.ERROR_CSV_NO_DATA_ROWS, ResponseMessage.Message.ERROR_CSV_NO_DATA_ROWS), + errorInactiveOrg( + ResponseMessage.Key.ERROR_INACTIVE_ORG, ResponseMessage.Message.ERROR_INACTIVE_ORG), + errorDuplicateEntries( + ResponseMessage.Key.ERROR_DUPLICATE_ENTRIES, ResponseMessage.Message.ERROR_DUPLICATE_ENTRIES), + errorConflictingValues( + ResponseMessage.Key.ERROR_CONFLICTING_VALUES, + ResponseMessage.Message.ERROR_CONFLICTING_VALUES), + errorConflictingRootOrgId( + ResponseMessage.Key.ERROR_CONFLICTING_ROOT_ORG_ID, + ResponseMessage.Message.ERROR_CONFLICTING_ROOT_ORG_ID), + errorUpdateSettingNotAllowed( + ResponseMessage.Key.ERROR_UPDATE_SETTING_NOT_ALLOWED, + ResponseMessage.Message.ERROR_UPDATE_SETTING_NOT_ALLOWED), + errorCreatingFile( + ResponseMessage.Key.ERROR_CREATING_FILE, ResponseMessage.Message.ERROR_CREATING_FILE), + errorProcessingRequest( + ResponseMessage.Key.ERROR_PROCESSING_REQUEST, + ResponseMessage.Message.ERROR_PROCESSING_REQUEST), + errorUnavailableCertificate( + ResponseMessage.Key.ERROR_UNAVAILABLE_CERTIFICATE, + ResponseMessage.Message.ERROR_UNAVAILABLE_CERTIFICATE), + invalidTextbook(ResponseMessage.Key.INVALID_TEXTBOOK, ResponseMessage.Message.INVALID_TEXTBOOK), + csvRowsExceeds(ResponseMessage.Key.CSV_ROWS_EXCEEDS, ResponseMessage.Message.CSV_ROWS_EXCEEDS), + invalidTextbookName( + ResponseMessage.Key.INVALID_TEXTBOOK_NAME, ResponseMessage.Message.INVALID_TEXTBOOK_NAME), + duplicateRows(ResponseMessage.Key.DUPLICATE_ROWS, ResponseMessage.Message.DUPLICATE_ROWS), + requiredHeaderMissing( + ResponseMessage.Key.REQUIRED_HEADER_MISSING, ResponseMessage.Message.REQUIRED_HEADER_MISSING), + requiredFieldMissing( + ResponseMessage.Key.REQUIRED_FIELD_MISSING, ResponseMessage.Message.REQUIRED_FIELD_MISSING), + blankCsvData(ResponseMessage.Key.BLANK_CSV_DATA, ResponseMessage.Message.BLANK_CSV_DATA), + exceedMaxChildren( + ResponseMessage.Key.EXCEEDS_MAX_CHILDREN, ResponseMessage.Message.EXCEEDS_MAX_CHILDREN), + textbookChildrenExist( + ResponseMessage.Key.TEXTBOOK_CHILDREN_EXISTS, + ResponseMessage.Message.TEXTBOOK_CHILDREN_EXISTS), + textbookUpdateFailure( + ResponseMessage.Key.TEXTBOOK_UPDATE_FAILURE, ResponseMessage.Message.TEXTBOOK_UPDATE_FAILURE), + noChildrenExists( + ResponseMessage.Key.TEXTBOOK_CHILDREN_NOT_EXISTS, + ResponseMessage.Message.TEXTBOOK_CHILDREN_NOT_EXISTS), + textBookNotFound( + ResponseMessage.Key.TEXTBOOK_NOT_FOUND, ResponseMessage.Message.TEXTBOOK_NOT_FOUND), + errorProcessingFile( + ResponseMessage.Key.ERROR_PROCESSING_FILE, ResponseMessage.Message.ERROR_PROCESSING_FILE), + fileNotFound(ResponseMessage.Key.ERR_FILE_NOT_FOUND, ResponseMessage.Message.ERR_FILE_NOT_FOUND), + errorTbUpdate(ResponseMessage.Key.ERROR_TB_UPDATE, ResponseMessage.Message.ERROR_TB_UPDATE), + errorInvalidParameterSize( + ResponseMessage.Key.ERROR_INVALID_PARAMETER_SIZE, + ResponseMessage.Message.ERROR_INVALID_PARAMETER_SIZE), + errorInvalidPageSection( + ResponseMessage.Key.INVALID_PAGE_SECTION, ResponseMessage.Message.INVALID_PAGE_SECTION), + errorRateLimitExceeded( + ResponseMessage.Key.ERROR_RATE_LIMIT_EXCEEDED, + ResponseMessage.Message.ERROR_RATE_LIMIT_EXCEEDED), + errorInvalidDialCode( + ResponseMessage.Key.ERROR_INVALID_DIAL_CODE, ResponseMessage.Message.ERROR_INVALID_DIAL_CODE), + errorInvalidTopic( + ResponseMessage.Key.ERROR_INVALID_TOPIC, ResponseMessage.Message.ERROR_INVALID_TOPIC), + errorDialCodeDuplicateEntry( + ResponseMessage.Key.ERROR_DIAL_CODE_DUPLICATE_ENTRY, + ResponseMessage.Message.ERROR_DIAL_CODE_DUPLICATE_ENTRY), + errorDialCodeAlreadyAssociated( + ResponseMessage.Key.ERROR_DIAL_CODE_ALREADY_ASSOCIATED, + ResponseMessage.Message.ERROR_DIAL_CODE_ALREADY_ASSOCIATED), + errorDialCodeLinkingFail( + ResponseMessage.Key.DIAL_CODE_LINKING_FAILED, + ResponseMessage.Message.DIAL_CODE_LINKING_FAILED), + errorDialCodeLinkingClientError( + ResponseMessage.Key.ERROR_TEXTBOOK_UPDATE, ResponseMessage.Message.ERROR_TEXTBOOK_UPDATE), + errorInvalidLinkedContentId( + ResponseMessage.Key.ERROR_INVALID_LINKED_CONTENT_ID, + ResponseMessage.Message.ERROR_INVALID_LINKED_CONTENT_ID), + errorDuplicateLinkedContentId( + ResponseMessage.Key.ERROR_DUPLICATE_LINKED_CONTENT, + ResponseMessage.Message.ERROR_DUPLICATE_LINKED_CONTENT), + + errorTeacherCannotBelongToCustodianOrg( + ResponseMessage.Key.TEACHER_CANNOT_BELONG_TO_CUSTODIAN_ORG, + ResponseMessage.Message.TEACHER_CANNOT_BELONG_TO_CUSTODIAN_ORG), + errorDduplicateDialCodeEntry( + ResponseMessage.Key.ERROR_DUPLICATE_QR_CODE_ENTRY, + ResponseMessage.Message.ERROR_DUPLICATE_QR_CODE_ENTRY), + errorInvalidTextbookUnitId( + ResponseMessage.Key.ERROR_INVALID_TEXTBOOK_UNIT_ID, + ResponseMessage.Message.ERROR_INVALID_TEXTBOOK_UNIT_ID), + invalidRequestTimeout( + ResponseMessage.Key.INVALID_REQUEST_TIMEOUT, ResponseMessage.Message.INVALID_REQUEST_TIMEOUT), + errorBGMSMismatch( + ResponseMessage.Key.ERROR_BGMS_MISMATCH, ResponseMessage.Message.ERROR_BGMS_MISMATCH), + errorUserMigrationFailed( + ResponseMessage.Key.ERROR_USER_MIGRATION_FAILED, + ResponseMessage.Message.ERROR_USER_MIGRATION_FAILED), + invalidIdentifier( + ResponseMessage.Key.VALID_IDENTIFIER_ABSENSE, + ResponseMessage.Message.IDENTIFIER_VALIDATION_FAILED), + fromAccountIdRequired( + ResponseMessage.Key.FROM_ACCOUNT_ID_MISSING, ResponseMessage.Message.FROM_ACCOUNT_ID_MISSING), + toAccountIdRequired( + ResponseMessage.Key.TO_ACCOUNT_ID_MISSING, ResponseMessage.Message.TO_ACCOUNT_ID_MISSING), + fromAccountIdNotExists( + ResponseMessage.Key.FROM_ACCOUNT_ID_NOT_EXISTS, + ResponseMessage.Message.FROM_ACCOUNT_ID_NOT_EXISTS), + mandatoryHeaderParamsMissing( + ResponseMessage.Key.MANDATORY_HEADER_PARAMETER_MISSING, + ResponseMessage.Message.MANDATORY_HEADER_PARAMETER_MISSING), + recoveryParamsMatchException( + ResponseMessage.Key.RECOVERY_PARAM_MATCH_EXCEPTION, + ResponseMessage.Message.RECOVERY_PARAM_MATCH_EXCEPTION), + PARAM_NOT_MATCH(ResponseMessage.Key.PARAM_NOT_MATCH, ResponseMessage.Message.PARAM_NOT_MATCH), + emptyContentsForUpdateBatchStatus( + ResponseMessage.Key.EMPTY_CONTENTS_FOR_UPDATE_BATCH_STATUS, + ResponseMessage.Message.EMPTY_CONTENTS_FOR_UPDATE_BATCH_STATUS), + errorUserHasNotCreatedAnyCourse( + ResponseMessage.Key.ERROR_USER_HAS_NOT_CREATED_ANY_COURSE, + ResponseMessage.Message.ERROR_USER_HAS_NOT_CREATED_ANY_COURSE), + errorUploadQRCodeCSVfailed( + ResponseMessage.Key.ERROR_UPLOAD_QRCODE_CSV_FAILED, + ResponseMessage.Message.ERROR_UPLOAD_QRCODE_CSV_FAILED), + errorNoDialcodesLinked( + ResponseMessage.Key.ERROR_NO_DIALCODES_LINKED, + ResponseMessage.Message.ERROR_NO_DIALCODES_LINKED), + eventsRequired( + ResponseMessage.Key.EVENTS_DATA_MISSING, ResponseMessage.Message.EVENTS_DATA_MISSING), + accountNotFound(ResponseMessage.Key.ACCOUNT_NOT_FOUND, ResponseMessage.Message.ACCOUNT_NOT_FOUND), + userMigrationFiled( + ResponseMessage.Key.USER_MIGRATION_FAILED, ResponseMessage.Message.USER_MIGRATION_FAILED), + invalidUserExternalId( + ResponseMessage.Key.INVALID_EXT_USER_ID, ResponseMessage.Message.INVALID_EXT_USER_ID), + invalidElementInList( + ResponseMessage.Key.INVALID_ELEMENT_IN_LIST, ResponseMessage.Message.INVALID_ELEMENT_IN_LIST), + passwordValidation( + ResponseMessage.Key.INVALID_PASSWORD, ResponseMessage.Message.INVALID_PASSWORD), + otpVerificationFailed( + ResponseMessage.Key.OTP_VERIFICATION_FAILED, ResponseMessage.Message.OTP_VERIFICATION_FAILED), + serviceUnAvailable( + ResponseMessage.Key.SERVICE_UNAVAILABLE, ResponseMessage.Message.SERVICE_UNAVAILABLE), + missingData(ResponseMessage.Key.MISSING_CODE, ResponseMessage.Message.MISSING_MESSAGE), + managedByNotAllowed( + ResponseMessage.Key.MANAGED_BY_NOT_ALLOWED, ResponseMessage.Message.MANAGED_BY_NOT_ALLOWED), + managedByEmailPhoneUpdateError( + ResponseMessage.Key.MANAGED_BY_EMAIL_PHONE_UPDATE_ERROR, ResponseMessage.Message.MANAGED_BY_EMAIL_PHONE_UPDATE_ERROR), + managedUserLimitExceeded( + ResponseMessage.Key.MANAGED_USER_LIMIT_EXCEEDED, ResponseMessage.Message.MANAGED_USER_LIMIT_EXCEEDED), + unableToConnectToAdminUtil( + ResponseMessage.Key.UNABLE_TO_CONNECT_TO_ADMINUTIL, + ResponseMessage.Message.UNABLE_TO_CONNECT_TO_ADMINUTIL), + OK(200), + CLIENT_ERROR(400), + SERVER_ERROR(500), + RESOURCE_NOT_FOUND(404), + UNAUTHORIZED(401), + FORBIDDEN(403), + REDIRECTION_REQUIRED(302), + TOO_MANY_REQUESTS(429), + SERVICE_UNAVAILABLE(503), + PARTIAL_SUCCESS_RESPONSE(206); + private int responseCode; + /** error code contains String value */ + private String errorCode; + /** errorMessage contains proper error message. */ + private String errorMessage; + + /** + * @param errorCode String + * @param errorMessage String + */ + private ResponseCode(String errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + private ResponseCode(String errorCode, String errorMessage, int responseCode) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + this.responseCode = responseCode; + } + + /** + * @param errorCode + * @return + */ + public String getMessage(int errorCode) { + return ""; + } + + /** @return */ + public String getErrorCode() { + return errorCode; + } + + /** @param errorCode */ + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + /** @return */ + public String getErrorMessage() { + return errorMessage; + } + + /** @param errorMessage */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + /** + * This method will provide status message based on code + * + * @param code + * @return String + */ + public static String getResponseMessage(String code) { + if (StringUtils.isBlank(code)) { + return ""; + } + ResponseCode responseCodes[] = ResponseCode.values(); + for (ResponseCode actionState : responseCodes) { + if (actionState.getErrorCode().equals(code)) { + return actionState.getErrorMessage(); + } + } + return ""; + } + + private ResponseCode(int responseCode) { + this.responseCode = responseCode; + } + + public int getResponseCode() { + return responseCode; + } + + public void setResponseCode(int responseCode) { + this.responseCode = responseCode; + } + + /** + * This method will take header response code as int value and it provide matched enum value, if + * code is not matched or exception occurs then it will provide SERVER_ERROR + * + * @param code int + * @return HeaderResponseCode + */ + public static ResponseCode getHeaderResponseCode(int code) { + if (code > 0) { + try { + ResponseCode[] arr = ResponseCode.values(); + if (null != arr) { + for (ResponseCode rc : arr) { + if (rc.getResponseCode() == code) return rc; + } + } + } catch (Exception e) { + return ResponseCode.SERVER_ERROR; + } + } + return ResponseCode.SERVER_ERROR; + } + + /** + * This method will provide ResponseCode enum based on error code + * + * @param errorCode + * @return String + */ + public static ResponseCode getResponse(String errorCode) { + if (StringUtils.isBlank(errorCode)) { + return null; + } else if (JsonKey.UNAUTHORIZED.equals(errorCode)) { + return ResponseCode.unAuthorized; + } else { + ResponseCode value = null; + ResponseCode responseCodes[] = ResponseCode.values(); + for (ResponseCode response : responseCodes) { + if (response.getErrorCode().equals(errorCode)) { + return response; + } + } + return value; + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/ResponseMessage.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/ResponseMessage.java new file mode 100644 index 0000000000..a080792366 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/ResponseMessage.java @@ -0,0 +1,878 @@ +package org.sunbird.common.responsecode; + +/** + * This interface will hold all the response key and message + * + * @author Manzarul + */ +public interface ResponseMessage { + + interface Message { + + String UNAUTHORIZED_USER = "You are not authorized."; + String INVALID_USER_CREDENTIALS = "Please check your credentials"; + String OPERATION_TIMEOUT = "Request processing taking too long time. Please try again later."; + String INVALID_OPERATION_NAME = + "Operation name is invalid. Please provide a valid operation name"; + String INVALID_REQUESTED_DATA = "Requested data for this operation is not valid."; + String CONSUMER_ID_MISSING_ERROR = "Consumer id is mandatory."; + String CONSUMER_ID_INVALID_ERROR = "Consumer id is invalid."; + String DEVICE_ID_MISSING_ERROR = "Device id is mandatory."; + String CONTENT_ID_INVALID_ERROR = "Please provide a valid content id."; + String CONTENT_ID_MISSING_ERROR = "Please provide content id."; + String COURSE_ID_MISSING_ERROR = "Please provide course id."; + String API_KEY_MISSING_ERROR = "APi key is mandatory."; + String API_KEY_INVALID_ERROR = "APi key is invalid."; + String INTERNAL_ERROR = "Process failed,please try again later."; + String COURSE_NAME_MISSING = "Please provide the course name."; + String SUCCESS_MESSAGE = "Success"; + String SESSION_ID_MISSING = "Session id is mandatory."; + String COURSE_ID_MISSING = "Course id is mandatory."; + String CONTENT_ID_MISSING = "Content id is mandatory."; + String VERSION_MISSING = "Version is mandatory."; + String COURSE_VERSION_MISSING = "Course version is mandatory."; + String CONTENT_VERSION_MISSING = "Content version is mandatory."; + String COURSE_DESCRIPTION_MISSING = "Description is mandatory."; + String COURSE_TOCURL_MISSING = "Course tocurl is mandatory."; + String EMAIL_MISSING = "Email is mandatory."; + String EMAIL_FORMAT = "Email is invalid."; + String URL_FORMAT_ERROR = "URL is invalid."; + String FIRST_NAME_MISSING = "First name is mandatory."; + String LANGUAGE_MISSING = "Language is mandatory."; + String PASSWORD_MISSING = "Password is mandatory."; + String ERROR_INVALID_CONFIG_PARAM_VALUE = "Invalid value {0} for config parameter {1}."; + String ERROR_MAX_SIZE_EXCEEDED = "Size of {0} exceeds max limit {1}"; + String PASSWORD_MIN_LENGHT = "Password should have at least 8 character."; + String PASSWORD_MAX_LENGHT = "Password should not be more than 12 character."; + String ORGANISATION_ID_MISSING = "Organization id is mandatory."; + String REQUIRED_DATA_ORG_MISSING = + "Organization Id or Provider with External Id values are required for the operation"; + String ORGANISATION_NAME_MISSING = "organization name is mandatory."; + String CHANNEL_SHOULD_BE_UNIQUE = + "Channel value already used by another organization. Provide different value for channel"; + String ERROR_DUPLICATE_ENTRY = "Value {0} for {1} is already in use."; + String INVALID_ORG_DATA = + "Given Organization Data doesn't exist in our records. Please provide a valid one"; + String INVALID_USR_DATA = + "Given User Data doesn't exist in our records. Please provide a valid one"; + String USR_DATA_VALIDATION_ERROR = "Please provide valid userId or userName and provider"; + String INVALID_ROOT_ORGANIZATION = "Root organization id is invalid"; + String INVALID_PARENT_ORGANIZATION_ID = "Parent organization id is invalid"; + String CYCLIC_VALIDATION_FAILURE = "The relation cannot be created as it is cyclic"; + String ENROLLMENT_START_DATE_MISSING = "Enrollment start date is mandatory."; + String COURSE_DURATION_MISSING = "Course duration is mandatory."; + String LOGIN_TYPE_MISSING = "Login type is required."; + String ERROR_INVALID_OTP = "Invalid OTP."; + String EMAIL_IN_USE = "Email already exists."; + String USERNAME_EMAIL_IN_USE = + "Username or Email is already in use. Please try with a different Username or Email."; + String KEY_CLOAK_DEFAULT_ERROR = "server error at sso."; + String USER_REG_UNSUCCESSFUL = "User Registration unsuccessful."; + String USER_UPDATE_UNSUCCESSFUL = "User update operation is unsuccessful."; + String INVALID_CREDENTIAL = "Invalid credential."; + String USERNAME_MISSING = "Username is mandatory."; + String USERNAME_IN_USE = "Username already exists."; + String USERID_MISSING = "UserId is mandatory."; + String ROLE_MISSING = "Role of the user is required"; + String MESSAGE_ID_MISSING = "Message id is mandatory."; + String USERNAME_CANNOT_BE_UPDATED = "UserName cann't be updated."; + String AUTH_TOKEN_MISSING = "Auth token is mandatory."; + String INVALID_AUTH_TOKEN = "Auth token is invalid.Please login again."; + String TIMESTAMP_REQUIRED = "TimeStamp is required."; + String PUBLISHED_COURSE_CAN_NOT_UPDATED = "Published course can't be updated."; + String SOURCE_MISSING = "Source is required."; + String SECTION_NAME_MISSING = "Section name is required."; + String SECTION_DATA_TYPE_MISSING = "Section data type missing."; + String SECTION_ID_REQUIRED = "Section id is required."; + String PAGE_NAME_REQUIRED = "Page name is required."; + String PAGE_ID_REQUIRED = "Page id is required."; + String INVALID_CONFIGURATION = "Invalid configuration data."; + String ASSESSMENT_ITEM_ID_REQUIRED = "Assessment item id is required."; + String ASSESSMENT_TYPE_REQUIRED = "Assessment type is required."; + String ATTEMPTED_DATE_REQUIRED = "Attempted data is required."; + String ATTEMPTED_ANSWERS_REQUIRED = "Attempted answers is required."; + String MAX_SCORE_REQUIRED = "Max score is required."; + String STATUS_CANNOT_BE_UPDATED = "status cann't be updated."; + String ATTEMPT_ID_MISSING_ERROR = "Please provide attempt id."; + String LOGIN_TYPE_ERROR = "provide login type as null."; + String INVALID_ORG_ID = "Org id does not exist ."; + String INVALID_ORG_STATUS = "Invalid org status for approve ."; + String INVALID_ORG_STATUS_TRANSITION = "Can not change state of Org to requeted state ."; + String ADDRESS_REQUIRED_ERROR = "Please provide address."; + String EDUCATION_REQUIRED_ERROR = "Please provide education details."; + String JOBDETAILS_REQUIRED_ERROR = "Please provide job details."; + String DB_INSERTION_FAIL = "DB insert operation failed."; + String DB_UPDATE_FAIL = "Db update operation failed."; + String DATA_ALREADY_EXIST = "data already exist."; + String INVALID_DATA = "Incorrect data."; + String INVALID_COURSE_ID = "Course doesnot exist. Please provide a valid course identifier"; + String PHONE_NO_REQUIRED_ERROR = "Phone number is required."; + String ORG_ID_MISSING = "Organization Id required."; + String ACTOR_CONNECTION_ERROR = "Service is not able to connect with actor."; + String USER_ALREADY_EXISTS = "User already exists for given {0}."; + String PAGE_ALREADY_EXIST = "page already exist with this Page Name and Org Code."; + String INVALID_USER_ID = "User Id does not exists in our records"; + String LOGIN_ID_MISSING = "loginId is required."; + String CONTENT_STATUS_MISSING_ERROR = "content status is required ."; + String ES_ERROR = "Something went wrong when processing data for search"; + String INVALID_PERIOD = "Time Period is invalid"; + String USER_NOT_FOUND = "user not found."; + String ID_REQUIRED_ERROR = "For deleting a record, Id is required."; + String DATA_TYPE_ERROR = "Data type of {0} should be {1}."; + String ERROR_ATTRIBUTE_CONFLICT = "Either pass attribute {0} or {1} but not both."; + String ADDRESS_ERROR = "In {0}, {1} is mandatory."; + String ADDRESS_TYPE_ERROR = "Please provide correct address Type."; + String NAME_OF_INSTITUTION_ERROR = "Please provide name of Institution."; + String EDUCATION_DEGREE_ERROR = "Education degree is required."; + String JOB_NAME_ERROR = "Job Name is required."; + String NAME_OF_ORGANISATION_ERROR = "Organization Name is required."; + String ROLES_MISSING = "user role is required."; + String EMPTY_ROLES_PROVIDED = "Roles cannot be empty."; + String CHANNEL_REG_FAILED = "Channel Registration failed."; + String INVALID_COURSE_CREATOR_ID = "Course creator id does not exist ."; + String USER_NOT_ASSOCIATED_TO_ROOT_ORG = + "User (ID = {0}) not associated to course batch creator root org."; + String SLUG_IS_NOT_UNIQUE = + "Please provide different channel value. This channel value already exist."; + String INVALID_CREATE_BADGE_ISSUER_DATA = "{0}"; + String INVALID_DATE_FORMAT = + "Invalid Date format . Date format should be : yyyy-MM-dd hh:mm:ss:SSSZ"; + String SRC_EXTERNAL_ID_ALREADY_EXIST = "PROVIDER WITH EXTERNAL ID ALREADY EXIST ."; + String USER_ALREADY_ENROLLED_COURSE = "User has already Enrolled this course ."; + String USER_NOT_ENROLLED_COURSE = "User is not enrolled to given course batch."; + String USER_ALREADY_COMPLETED_COURSE = "User already completed given course batch."; + String COURSE_BATCH_ALREADY_COMPLETED = "Course batch is already completed."; + String COURSE_BATCH_ENROLLMENT_DATE_ENDED = "Course batch enrollment date has ended."; + String EXISTING_ORG_MEMBER = "You already have a membership of this organization."; + String CONTENT_TYPE_ERROR = "Please add Content-Type header with value application/json"; + String INVALID_PROPERTY_ERROR = "Invalid property {0}."; + String USER_NAME_OR_ID_ERROR = "Please provide either username or userId."; + String USER_ACCOUNT_BLOCKED = "User account has been blocked ."; + String EMAIL_VERIFY_ERROR = "Please provide a verified email in order to create user."; + String PHONE_VERIFY_ERROR = + "Please provide a verified phone number in order to create/update user."; + String BULK_USER_UPLOAD_ERROR = + "Please provide either organization Id or external Id & provider value."; + String DATA_SIZE_EXCEEDED = "Maximum upload data size should be {0}"; + String INVALID_COLUMN_NAME = "Invalid column name."; + String USER_ALREADY_ACTIVE = "User is already active."; + String USER_ALREADY_INACTIVE = "User is already inactive."; + String ENROLMENT_TYPE_REQUIRED = "Enrolment type is mandatory."; + String ENROLMENT_TYPE_VALUE_ERROR = "EnrolmentType value must be either open or invite-only."; + String COURSE_BATCH_START_DATE_REQUIRED = "Batch start date is mandatory."; + String COURSE_BATCH_START_DATE_INVALID = + "Batch start date should be either today or future date."; + String DATE_FORMAT_ERRROR = "Date format error."; + String END_DATE_ERROR = "End date should be greater than start date."; + String ENROLLMENT_END_DATE_START_ERROR = + "Enrollment End date should be greater than course batch start date."; + String ENROLLMENT_END_DATE_END_ERROR = + "Enrollment End date should be lesser than course batch end date."; + String ENROLLMENT_END_DATE_UPDATE_ERROR = + "Invalid Enrollment End date. Please provide future date."; + String INVALID_CSV_FILE = "Please provide valid csv file."; + String INVALID_COURSE_BATCH_ID = "Invalid course batch id "; + String COURSE_BATCH_ID_MISSING = "Course batch Id required"; + String ENROLLMENT_TYPE_VALIDATION = "Enrollment type should be invite-only."; + String USER_NOT_BELONGS_TO_ANY_ORG = "User does not belongs to any org ."; + String INVALID_OBJECT_TYPE = "Invalid Object Type."; + String INVALID_PROGRESS_STATUS = + "Progress status value should be NOT_STARTED(0), STARTED(1), COMPLETED(2)."; + String COURSE_CREATED_FOR_NULL = "Batch does not belong to any organization ."; + String COURSE_BATCH_START_PASSED_DATE_INVALID = "This Batch already started."; + String UNABLE_TO_CONNECT_TO_EKSTEP = "Unable to connect to Ekstep Server"; + String UNABLE_TO_CONNECT_TO_ES = "Unable to connect to Elastic Search"; + String UNABLE_TO_PARSE_DATA = "Unable to parse the data"; + String INVALID_JSON = "Unable to process object to JSON/ JSON to Object"; + String EMPTY_CSV_FILE = "CSV file is Empty."; + String INVALID_ROOT_ORG_DATA = + "Root org doesn't exist for this Organization Id and channel {0}"; + String NO_DATA = "You have uploaded an empty file. Fill mandatory details and upload the file."; + String INVALID_CHANNEL = "Channel value is invalid."; + String INVALID_PROCESS_ID = "Invalid Process Id."; + String EMAIL_SUBJECT_ERROR = "Email Subject is mandatory."; + String EMAIL_BODY_ERROR = "Email Body is mandatory."; + String RECIPIENT_ADDRESS_ERROR = "Please send recipientEmails or recipientUserIds."; + String STORAGE_CONTAINER_NAME_MANDATORY = " Container name can not be null or empty."; + String CLOUD_SERVICE_ERROR = "Cloud storage service error."; + String BADGE_TYPE_ID_ERROR = "Badge type id is mandatory."; + String RECEIVER_ID_ERROR = "Receiver id is mandatory."; + String INVALID_RECEIVER_ID = "Receiver id is invalid."; + String INVALID_BADGE_ID = "Invalid badge type id."; + String USER_ORG_ASSOCIATION_ERROR = "User is already associated with another organization."; + String INVALID_ROLE = "Invalid role value provided in request."; + String INVALID_SALT = "Please provide salt value."; + String ORG_TYPE_MANDATORY = "Org Type name is mandatory."; + String ORG_TYPE_ALREADY_EXIST = + "Org type with this name already exist.Please provide some other name."; + String ORG_TYPE_ID_REQUIRED_ERROR = "Org Type Id is required."; + String TITLE_REQUIRED = "Title is required"; + String NOTE_REQUIRED = "No data to store for notes"; + String CONTENT_ID_ERROR = "Please provide content id or course id"; + String INVALID_TAGS = "Invalid data for tags"; + String NOTE_ID_INVALID = "Invalid note id"; + String USER_DATA_ENCRYPTION_ERROR = "Exception Occurred while encrypting user data."; + String INVALID_PHONE_NO_FORMAT = "Please provide a valid phone number."; + String INVALID_WEBPAGE_DATA = "Invalid webPage data"; + String INVALID_MEDIA_TYPE = "Invalid media type for webPage"; + String INVALID_WEBPAGE_URL = "Invalid URL for {0}."; + String INVALID_DATE_RANGE = "Date range should be between 3 Month."; + String INVALID_BATCH_END_DATE_ERROR = "Please provide valid End Date."; + String INVALID_BATCH_START_DATE_ERROR = "Please provide valid Start Date."; + String COURSE_BATCH_END_DATE_ERROR = "Batch has been closed."; + String COURSE_BATCH_IS_CLOSED_ERROR = "Batch has been closed."; + String CONFIIRM_PASSWORD_MISSING = "Confirm password is mandatory."; + String CONFIIRM_PASSWORD_EMPTY = "Confirm password can not be empty."; + String SAME_PASSWORD_ERROR = "New password can't be same as old password."; + String ENDORSED_USER_ID_REQUIRED = " Endorsed user id required ."; + String CAN_NOT_ENDORSE = "Can not endorse since both belong to different orgs ."; + String INVALID_ORG_TYPE_ID_ERROR = "Please provide valid orgTypeId."; + String INVALID_ORG_TYPE_ERROR = "Please provide valid orgType."; + String TABLE_OR_DOC_NAME_ERROR = "Please provide valid table or documentName."; + String EMAIL_OR_PHONE_MISSING = "Please provide either email or phone."; + // No need to indicate managedby is missing to user. + String EMAIL_OR_PHONE_OR_MANAGEDBY_MISSING = "Please provide either email or phone."; + String ONLY_EMAIL_OR_PHONE_OR_MANAGEDBY_REQUIRED = + "Please provide only email or phone or managed by"; + String PHONE_ALREADY_IN_USE = "Phone already in use. Please provide different phone number."; + String INVALID_CLIENT_NAME = "Please provide unique valid client name"; + String INVALID_CLIENT_ID = "Please provide valid client id"; + String USER_PHONE_UPDATE_FAILED = "user phone update is failed."; + String ES_UPDATE_FAILED = "Data insertion to ES failed."; + String UPDATE_FAILED = "Data updation failed due to invalid Request"; + String INVALID_TYPE_VALUE = "Type value should be organisation OR location ."; + String INVALID_LOCATION_ID = "Please provide valid location id."; + String INVALID_HASHTAG_ID = + "Please provide different hashTagId.This HashTagId is associated with some other organization."; + String INVALID_USR_ORG_DATA = + "Given User Data doesn't belongs to this organization. Please provide a valid one."; + String INVALID_VISIBILITY_REQUEST = "Private and Public fields cannot be same."; + String INVALID_TOPIC_NAME = "Please provide a valid toipc."; + String INVALID_TOPIC_DATA = "Please provide valid notification data."; + String INVALID_NOTIFICATION_TYPE = "Please provide a valid notification type."; + String INVALID_NOTIFICATION_TYPE_SUPPORT = "Only notification type FCM is supported."; + String INVALID_PHONE_NUMBER = "Please send Phone and country code seprately."; + String INVALID_COUNTRY_CODE = "Please provide a valid country code."; + String ERROR_DUPLICATE_ENTRIES = "System contains duplicate entry for {0}."; + String LOCATION_ID_REQUIRED = "Please provide Location Id."; + String NOT_SUPPORTED = "Not Supported."; + String USERNAME_USERID_MISSING = "Please provide either userName or userId."; + String ISSUER_ID_REQUIRED = "Please provide issuer ID."; + String ISSUER_LIST_REQUIRED = "Please provide issuer list."; + String BADGE_ID_REQUIRED = "Please provide badge class ID."; + String BADGE_TYPE_REQUIRED = "Please provide badge class type."; + String INVALID_BADGE_TYPE = "Please provide valid badge class type."; + String INVALID_BADGE_SUBTYPE = "Please provide valid badge class subtype."; + String INVALID_BADGE_ROLE = "Please provide valid badge class role(s)."; + String BADGE_ROLES_REQUIRED = "Please provide authorised roles for badge class."; + String ROOT_ORG_ID_REQUIRED = "Please provide root organisation ID."; + String BADGE_NAME_REQUIRED = "Please provide badge class name."; + String BADGE_DESCRIPTION_REQUIRED = "Please provide badge class description."; + String BADGE_CRITERIA_REQUIRED = "Please provide badge class criteria."; + String BADGE_IMAGE_REQUIRED = "Please provide badge class image."; + String RECIPIENT_EMAIL_REQUIRED = "Please provide recipient email."; + String ASSERTION_EVIDENCE_REQUIRED = "Please provide valid assertion url as an evidence."; + String ASSERTION_ID_REQUIRED = "Please provide assertion ID."; + String RECIPIENT_ID_REQUIRED = "Please provide a recipient id."; + String RECIPIENT_TYPE_REQUIRED = "Please provide recipient type."; + String BADGING_SERVER_ERROR = "Badging server is down or on high load"; + String RESOURCE_NOT_FOUND = "Requested resource not found"; + String MAX_ALLOWED_SIZE_LIMIT_EXCEED = "Max allowed size is {0}"; + String SLUG_REQUIRED = "Slug is required ."; + String INVALID_ISSUER_ID = "Invalid issuer ID."; + String REVOCATION_REASON_REQUIRED = "Please provide revocation reason."; + String ALREADY_REVOKED = "Assertion is already revoked."; + String INVALID_RECIPIENT_TYPE = "Please provide a valid recipient type."; + String CUSTOM_CLIENT_ERROR = "Request failed. {0}"; + String CUSTOM_RESOURCE_NOT_FOUND_ERROR = "{0}"; + String CUSTOM_SERVER_ERROR = "{0}"; + String INACTIVE_USER = "User is Inactive. Please make it active to proceed."; + String USER_INACTIVE_FOR_THIS_ORG = + "User is Inactive for this org. Please make it active to proceed."; + String USER_UPDATE_FAILED_FOR_THIS_ORG = "user updation failed for this org."; + String PAGE_NOT_EXIST = "Requested page does not exist."; + String SECTION_NOT_EXIST = "Requested section does not exist."; + String ORG_NOT_EXIST = "Requested organisation does not exist."; + String INVALID_PAGE_SOURCE = "Invalid page source."; + String BADGE_SUBTYPE_REQUIRED = "Please provide badge class subtype."; + String LOCATION_TYPE_REQUIRED = "Location type required."; + String INVALID_REQUEST_DATA_FOR_LOCATION = "{0} field required."; + String ALREADY_EXISTS = "A {0} with {1} already exists. Please retry with a unique value."; + String INVALID_VALUE = "Invalid {0}: {1}. Valid values are: {2}."; + String PARENT_CODE_AND_PARENT_ID_MISSING = "Please provide either parentCode or parentId."; + String INVALID_PARAMETER = "Please provide valid {0}."; + String INVALID_PARENT_ID = "Please provide valid parentId."; + String INVALID_LOCATION_DELETE_REQUEST = + "One or more locations have a parent reference to given location and hence cannot be deleted."; + String LOCATION_TYPE_CONFLICTS = "Location type conflicts with its parent location type."; + String MANDATORY_PARAMETER_MISSING = "Mandatory parameter {0} is missing."; + String ERROR_MANDATORY_PARAMETER_EMPTY = "Mandatory parameter {0} is empty."; + String ERROR_NO_FRAMEWORK_FOUND = "No framework found."; + String INVALID_LOCN_ID = "Please provide valid locationId."; + String UPDATE_NOT_ALLOWED = "Update of {0} is not allowed."; + String MANDATORY_HEADER_MISSING = "Mandatory header {0} is missing."; + String INVALID_PARAMETER_VALUE = + "Invalid value {0} for parameter {1}. Please provide a valid value."; + String PARENT_NOT_ALLOWED = "For top level location, {0} is not allowed."; + String MISSING_FILE_ATTACHMENT = "Missing file attachment."; + String FILE_ATTACHMENT_SIZE_NOT_CONFIGURED = "File attachment max size is not configured."; + String EMPTY_FILE = "Attached file is empty."; + String INVALID_COLUMNS = "Invalid column: {0}. Valid columns are: {1}."; + String CONFLICTING_ORG_LOCATIONS = + "An organisation cannot be associated to two conflicting locations ({0}, {1}) at {2} level. "; + String UNABLE_TO_COMMUNICATE_WITH_ACTOR = "Unable to communicate with actor."; + String EMPTY_HEADER_LINE = "Missing header line in CSV file."; + String INVALID_REQUEST_PARAMETER = "Invalid parameter {0} in request."; + String ROOT_ORG_ASSOCIATION_ERROR = + "No root organisation found which is associated with given {0}."; + String OR_FORMAT = "{0} or {1}"; + String AND_FORMAT = "{0} and {1}"; + String DOT_FORMAT = "{0}.{1}"; + String DEPENDENT_PARAMETER_MISSING = "Missing parameter {0} which is dependent on {1}."; + String DEPENDENT_PARAMS_MISSING = "Missing parameter value in {0}."; + String EXTERNALID_NOT_FOUND = + "External ID (id: {0}, idType: {1}, provider: {2}) not found for given user."; + String PARSING_FAILED = "Failed to parse {0}."; + String EXTERNAL_ID_FORMAT = "externalId (id: {0}, idType: {1}, provider: {2})"; + String EXTERNALID_ASSIGNED_TO_OTHER_USER = + "External ID (id: {0}, idType: {1}, provider: {2}) already assigned to another user."; + String MANDATORY_CONFIG_PARAMETER_MISSING = + "Mandatory configuration parameter {0} missing which is required for service startup."; + String CASSANDRA_CONNECTION_ESTABLISHMENT_FAILED = + "Cassandra connection establishment failed in {0} mode."; + String COMMON_ATTRIBUTE_MISMATCH = "{0} mismatch of {1} and {2}"; + String MULTIPLE_COURSES_FOR_BATCH = "A batch cannot belong to multiple courses."; + String ERROR_JSON_TRANSFORM_INVALID_TYPE_CONFIG = + "JSON transformation failed as invalid type configuration found for field {0}."; + String ERROR_JSON_TRANSFORM_INVALID_DATE_FORMAT = + "JSON transformation failed as invalid date format configuration found for field {0}."; + String ERROR_JSON_TRANSFORM_INVALID_INPUT = + "JSON transformation failed as invalid input provided for field {0}."; + String ERROR_JSON_TRANSFORM_INVALID_ENUM_INPUT = + "JSON transformation failed as invalid enum input provided for field {0}."; + String ERROR_JSON_TRANSFORM_ENUM_VALUES_EMPTY = + "JSON transformation failed as enum values is empty in configuration for field {0}."; + String ERROR_JSON_TRANSFORM_BASIC_CONFIG_MISSING = + "JSON transformation failed as mandatory configuration (toFieldName, fromType or toType) is missing for field {0}."; + String ERROR_JSON_TRANSFORM_INVALID_FILTER_CONFIG = + "JSON transformation failed as invalid filter configuration found for field {0}."; + String ERROR_LOAD_CONFIG = "Loading failed for configuration file {0}."; + String ERROR_REGISTRY_CLIENT_CREATION = "Registry client creation failed."; + String ERROR_REGISTRY_ADD_ENTITY = "Registry add entity API failed."; + String ERROR_REGISTRY_READ_ENTITY = "Registry read entity API failed."; + String ERROR_REGISTRY_UPDATE_ENTITY = "Registry update entity API failed."; + String ERROR_REGISTRY_DELETE_ENTITY = "Registry delete entity API failed."; + String ERROR_REGISTRY_PARSE_RESPONSE = "Error while parsing response from registry."; + String ERROR_REGISTRY_ENTITY_TYPE_BLANK = "Request failed as entity type is blank."; + String ERROR_REGISTRY_ENTITY_ID_BLANK = "Request failed as entity id is not provided."; + String ERROR_REGISTRY_ACCESS_TOKEN_BLANK = + "Request failed as user access token is not provided."; + String DUPLICATE_EXTERNAL_IDS = + "Duplicate external IDs for given idType ({0}) and provider ({1})."; + String INVALID_DUPLICATE_VALUE = "Values for {0} and {1} cannot be same."; + String EMAIL_RECIPIENTS_EXCEEDS_MAX_LIMIT = + "Email notification is not sent as the number of recipients exceeded configured limit ({0})."; + String NO_EMAIL_RECIPIENTS = + "Email notification is not sent as the number of recipients is zero."; + String PARAMETER_MISMATCH = "Mismatch of given parameters: {0}."; + String FORBIDDEN = "You are forbidden from accessing specified resource."; + String ERROR_CONFIG_LOAD_EMPTY_STRING = + "Loading {0} configuration failed as empty string is passed as parameter."; + String ERROR_CONFIG_LOAD_PARSE_STRING = + "Loading {0} configuration failed due to parsing error."; + String ERROR_CONFIG_LOAD_EMPTY_CONFIG = "Loading {0} configuration failed."; + String ERROR_CONFLICTING_FIELD_CONFIGURATION = + "Field {0} in {1} configuration is conflicting in {2} and {3}."; + String ERROR_SYSTEM_SETTING_NOT_FOUND = "System Setting not found for id: {0}"; + String ERROR_NO_ROOT_ORG_ASSOCIATED = "Not able to associate with root org"; + String ERROR_INACTIVE_CUSTODIAN_ORG = "Custodian organisation is inactive."; + String ERROR_UNSUPPORTED_CLOUD_STORAGE = "Unsupported cloud storage type {0}."; + String ERROR_UNSUPPORTED_FIELD = "Unsupported field {0}."; + String ERROR_GENERATE_DOWNLOAD_LINK = "Error in generating download link."; + String ERROR_DOWNLOAD_LINK_UNAVAILABLE = "Download link is unavailable."; + String ERROR_SAVING_STORAGE_DETAILS = "Error saving storage details for download link."; + String ERROR_CSV_NO_DATA_ROWS = "No data rows in CSV."; + String ERROR_INACTIVE_ORG = "Organisation corresponding to given {0} ({1}) is inactive."; + String ERROR_CONFLICTING_VALUES = "Conflicting values for {0} ({1}) and {2} ({3})."; + String ERROR_CONFLICTING_ROOT_ORG_ID = + "Root organisation ID of API user is conflicting with that of specified organisation ID."; + String ERROR_UPDATE_SETTING_NOT_ALLOWED = "Update of system setting {0} is not allowed."; + String ERROR_CREATING_FILE = "Error Reading File"; + String ERROR_PROCESSING_REQUEST = "Something went wrong while Processing Request"; + String ERROR_UNAVAILABLE_CERTIFICATE = "Certificate is unavailable"; + String INVALID_TEXTBOOK = "Invalid Textbook. Please Provide Valid Textbook Identifier."; + String CSV_ROWS_EXCEEDS = "Number of rows in csv file is more than "; + String INVALID_TEXTBOOK_NAME = + "Textbook Name given in the file doesn’t match current Textbook name. Please check and upload again."; + String DUPLICATE_ROWS = + "Duplicate Textbook node found. Please check and upload again. Row number "; + String REQUIRED_HEADER_MISSING = "Required set of header missing: "; + String REQUIRED_FIELD_MISSING = + "Required columns missing. Please check and upload again. Mandatory fields are: "; + String BLANK_CSV_DATA = + "Did not find any Table of Contents data. Please check and upload again."; + String EXCEEDS_MAX_CHILDREN = "Number of first level units is more than allowed."; + String TEXTBOOK_CHILDREN_EXISTS = "Textbook is already having children."; + String TEXTBOOK_UPDATE_FAILURE = "Textbook could not be updated."; + String TEXTBOOK_CHILDREN_NOT_EXISTS = "No Children Exists for given TextBook."; + String TEXTBOOK_NOT_FOUND = "Textbook not found."; + String ERROR_PROCESSING_FILE = + "Something Went Wrong While Reading File. Please Check The File."; + String ERR_FILE_NOT_FOUND = "File not found. Please select valid file and upload."; + String ERROR_TB_UPDATE = "Error while updating the textbook"; + String ERROR_INVALID_PARAMETER_SIZE = + "Parameter {0} is of invalid size (expected: {1}, actual: {2})."; + String INVALID_PAGE_SECTION = "Page section associated with the page is invalid."; + String ERROR_RATE_LIMIT_EXCEEDED = + "Your per {0} rate limit has exceeded. You can retry after some time."; + String ERROR_INVALID_DIAL_CODE = "The given QR code {0} is not valid."; + String ERROR_INVALID_TOPIC = "Topic {0} not found in the framework. Please check and correct."; + String ERROR_DIAL_CODE_DUPLICATE_ENTRY = + "QR code {0} is associated with more than one section {1}."; + String ERROR_DIAL_CODE_ALREADY_ASSOCIATED = + "QR code {0} is already associated with a section {1} in the textbook"; + String DIAL_CODE_LINKING_FAILED = "QR code linking failed."; + String ERROR_TEXTBOOK_UPDATE = "{0}"; + + String ERROR_INVALID_LINKED_CONTENT_ID = "Linked Content {0} is not valid at row {1}."; + String ERROR_DUPLICATE_LINKED_CONTENT = "Duplicate content {0} at row {1}."; + String TEACHER_CANNOT_BELONG_TO_CUSTODIAN_ORG = + "User type teacher is not supported for custodian organisation users"; + String ERROR_DUPLICATE_QR_CODE_ENTRY = + "CSV file contains more than one entry for {0}. Correct the duplicate entry and try again."; + String ERROR_INVALID_TEXTBOOK_UNIT_ID = "Invalid textbook unit id {0} for texbook."; + String INVALID_REQUEST_TIMEOUT = "Invalid request timeout value {0}."; + String ERROR_USER_UPDATE_PASSWORD = "User is created but password couldn't be updated."; + String ERROR_BGMS_MISMATCH = "Mismatch in {0} at row - {1}"; + String ERROR_USER_MIGRATION_FAILED = "User migration failed."; + String EMPTY_CONTENTS_FOR_UPDATE_BATCH_STATUS = + "Contents should not be empty for batch status update."; + String IDENTIFIER_VALIDATION_FAILED = + "Valid identifier is not present in List, Valid supported identifiers are "; + String FROM_ACCOUNT_ID_MISSING = "From Account id is mandatory."; + String TO_ACCOUNT_ID_MISSING = "To Account id is mandatory."; + String FROM_ACCOUNT_ID_NOT_EXISTS = "From Account id not exists"; + String PARAM_NOT_MATCH = "%s-NOT-MATCH"; + String MANDATORY_HEADER_PARAMETER_MISSING = "Mandatory header parameter {0} is missing."; + String RECOVERY_PARAM_MATCH_EXCEPTION = "{0} could not be same as {1}"; + String ERROR_USER_HAS_NOT_CREATED_ANY_COURSE = + "User hasn't created any course, or may not have a creator role"; + String ERROR_UPLOAD_QRCODE_CSV_FAILED = "Uploading the html file to cloud storage has failed."; + String ERROR_NO_DIALCODES_LINKED = "No dialcodes are linked to any courses created by user(s)"; + String EVENTS_DATA_MISSING = "Events array is mandatory"; + String ACCOUNT_NOT_FOUND = "Account not found."; + String INVALID_EXT_USER_ID = "provided ext user id {0} is incorrect"; + String USER_MIGRATION_FAILED = "user is failed to migrate"; + String INVALID_ELEMENT_IN_LIST = + "Invalid value supplied for parameter {0}.Supported values are {1}"; + String INVALID_PASSWORD = + "Password must contain a minimum of 8 characters including numerals, lower and upper case alphabets and special characters"; + String OTP_VERIFICATION_FAILED = "OTP verification failed. Remaining attempt count is {0}."; + String SERVICE_UNAVAILABLE = "SERVICE UNAVAILABLE"; + String MISSING_MESSAGE = "Required fields for create course are missing. {0}"; + String MANAGED_BY_NOT_ALLOWED = "managedBy cannot be updated."; + String MANAGED_BY_EMAIL_PHONE_UPDATE_ERROR = "ManagedBy User phone/email cannot be updated."; + String MANAGED_USER_LIMIT_EXCEEDED = "Managed user creation limit exceeded"; + String UNABLE_TO_CONNECT_TO_ADMINUTIL = "Unable to connect to admin util service"; + } + + interface Key { + String UNAUTHORIZED_USER = "UNAUTHORIZED_USER"; + String INVALID_USER_CREDENTIALS = "INVALID_USER_CREDENTIALS"; + String OPERATION_TIMEOUT = "PROCESS_EXE_TIMEOUT"; + String INVALID_OPERATION_NAME = "INVALID_OPERATION_NAME"; + String INVALID_REQUESTED_DATA = "INVALID_REQUESTED_DATA"; + String CONSUMER_ID_MISSING_ERROR = "CONSUMER_ID_REQUIRED_ERROR"; + String CONSUMER_ID_INVALID_ERROR = "CONSUMER_ID_INVALID_ERROR"; + String DEVICE_ID_MISSING_ERROR = "DEVICE_ID_REQUIRED_ERROR"; + String CONTENT_ID_INVALID_ERROR = "CONTENT_ID_INVALID_ERROR"; + String CONTENT_ID_MISSING_ERROR = "CONTENT_ID_REQUIRED_ERROR"; + String COURSE_ID_MISSING_ERROR = "COURSE_ID_REQUIRED_ERROR"; + String API_KEY_MISSING_ERROR = "API_KEY_REQUIRED_ERROR"; + String API_KEY_INVALID_ERROR = "API_KEY_INVALID_ERROR"; + String INTERNAL_ERROR = "INTERNAL_ERROR"; + String COURSE_NAME_MISSING = "COURSE_NAME_REQUIRED_ERROR"; + String SUCCESS_MESSAGE = "SUCCESS"; + String SESSION_ID_MISSING = "SESSION_ID_REQUIRED_ERROR"; + String COURSE_ID_MISSING = "COURSE_ID_REQUIRED_ERROR"; + String CONTENT_ID_MISSING = "CONTENT_ID_REQUIRED_ERROR"; + String VERSION_MISSING = "VERSION_REQUIRED_ERROR"; + String COURSE_VERSION_MISSING = "COURSE_VERSION_REQUIRED_ERROR"; + String CONTENT_VERSION_MISSING = "CONTENT_VERSION_REQUIRED_ERROR"; + String COURSE_DESCRIPTION_MISSING = "COURSE_DESCRIPTION_REQUIRED_ERROR"; + String COURSE_TOCURL_MISSING = "COURSE_TOCURL_REQUIRED_ERROR"; + String EMAIL_MISSING = "EMAIL_ID_REQUIRED_ERROR"; + String EMAIL_FORMAT = "EMAIL_FORMAT_ERROR"; + String URL_FORMAT_ERROR = "URL_FORMAT_ERROR"; + String FIRST_NAME_MISSING = "FIRST_NAME_REQUIRED_ERROR"; + String LANGUAGE_MISSING = "LANGUAGE_REQUIRED_ERROR"; + String PASSWORD_MISSING = "PASSWORD_REQUIRED_ERROR"; + String PASSWORD_MIN_LENGHT = "PASSWORD_MIN_LENGHT_ERROR"; + String PASSWORD_MAX_LENGHT = "PASSWORD_MAX_LENGHT_ERROR"; + String ORGANISATION_ID_MISSING = "ORGANIZATION_ID_MISSING"; + String REQUIRED_DATA_ORG_MISSING = "REQUIRED_DATA_MISSING"; + String ORGANISATION_NAME_MISSING = "ORGANIZATION_NAME_MISSING"; + String CHANNEL_SHOULD_BE_UNIQUE = "CHANNEL_SHOULD_BE_UNIQUE"; + String ERROR_DUPLICATE_ENTRY = "ERROR_DUPLICATE_ENTRY"; + String INVALID_ORG_DATA = "INVALID_ORGANIZATION_DATA"; + String INVALID_USR_DATA = "INVALID_USER_DATA"; + String USR_DATA_VALIDATION_ERROR = "USER_DATA_VALIDATION_ERROR"; + String INVALID_ROOT_ORGANIZATION = "INVALID ROOT ORGANIZATION"; + String INVALID_PARENT_ORGANIZATION_ID = "INVALID_PARENT_ORGANIZATION_ID"; + String CYCLIC_VALIDATION_FAILURE = "CYCLIC_VALIDATION_FAILURE"; + String ENROLLMENT_START_DATE_MISSING = "ENROLLMENT_START_DATE_MISSING"; + String COURSE_DURATION_MISSING = "COURSE_DURATION_MISSING"; + String LOGIN_TYPE_MISSING = "LOGIN_TYPE_MISSING"; + String EMAIL_IN_USE = "EMAIL_IN_USE"; + String USERNAME_EMAIL_IN_USE = "USERNAME_EMAIL_IN_USE"; + String KEY_CLOAK_DEFAULT_ERROR = "KEY_CLOAK_DEFAULT_ERROR"; + String USER_REG_UNSUCCESSFUL = "USER_REG_UNSUCCESSFUL"; + String USER_UPDATE_UNSUCCESSFUL = "USER_UPDATE_UNSUCCESSFUL"; + String INVALID_CREDENTIAL = "INVALID_CREDENTIAL"; + String USERNAME_MISSING = "USERNAME_MISSING"; + String USERNAME_IN_USE = "USERNAME_IN_USE"; + String USERID_MISSING = "USERID_MISSING"; + String ROLE_MISSING = "ROLE_MISSING"; + String MESSAGE_ID_MISSING = "MESSAGE_ID_MISSING"; + String USERNAME_CANNOT_BE_UPDATED = "USERNAME_CANNOT_BE_UPDATED"; + String AUTH_TOKEN_MISSING = "X_Authenticated_Userid_MISSING"; + String INVALID_AUTH_TOKEN = "INVALID_AUTH_TOKEN"; + String TIMESTAMP_REQUIRED = "TIMESTAMP_REQUIRED"; + String PUBLISHED_COURSE_CAN_NOT_UPDATED = "PUBLISHED_COURSE_CAN_NOT_UPDATED"; + String SOURCE_MISSING = "SOURCE_MISSING"; + String SECTION_NAME_MISSING = "SECTION_NAME_MISSING"; + String SECTION_DATA_TYPE_MISSING = "SECTION_DATA_TYPE_MISSING"; + String SECTION_ID_REQUIRED = "SECTION_ID_REQUIRED"; + String PAGE_NAME_REQUIRED = "PAGE_NAME_REQUIRED"; + String PAGE_ID_REQUIRED = "PAGE_ID_REQUIRED"; + String INVALID_CONFIGURATION = "INVALID_CONFIGURATION"; + String ASSESSMENT_ITEM_ID_REQUIRED = "ASSESSMENT_ITEM_ID_REQUIRED"; + String ASSESSMENT_TYPE_REQUIRED = "ASSESSMENT_TYPE_REQUIRED"; + String ATTEMPTED_DATE_REQUIRED = "ATTEMPTED_DATE_REQUIRED"; + String ATTEMPTED_ANSWERS_REQUIRED = "ATTEMPTED_ANSWERS_REQUIRED"; + String MAX_SCORE_REQUIRED = "MAX_SCORE_REQUIRED"; + String STATUS_CANNOT_BE_UPDATED = "STATUS_CANNOT_BE_UPDATED"; + String ATTEMPT_ID_MISSING_ERROR = "ATTEMPT_ID_REQUIRED_ERROR"; + String LOGIN_TYPE_ERROR = "LOGIN_TYPE_ERROR"; + String INVALID_ORG_ID = "INVALID_ORG_ID"; + String INVALID_ORG_STATUS = "INVALID_ORG_STATUS"; + String INVALID_ORG_STATUS_TRANSITION = "INVALID_ORG_STATUS_TRANSITION"; + String ADDRESS_REQUIRED_ERROR = "ADDRESS_REQUIRED_ERROR"; + String EDUCATION_REQUIRED_ERROR = "EDUCATION_REQUIRED_ERROR"; + String JOBDETAILS_REQUIRED_ERROR = "JOBDETAILS_REQUIRED_ERROR"; + String DB_INSERTION_FAIL = "DB_INSERTION_FAIL"; + String DB_UPDATE_FAIL = "DB_UPDATE_FAIL"; + String DATA_ALREADY_EXIST = "DATA_ALREADY_EXIST"; + String INVALID_DATA = "INVALID_DATA"; + String INVALID_COURSE_ID = "INVALID_COURSE_ID"; + String PHONE_NO_REQUIRED_ERROR = "PHONE_NO_REQUIRED_ERROR"; + String ORG_ID_MISSING = "ORG_ID_MISSING"; + String ACTOR_CONNECTION_ERROR = "ACTOR_CONNECTION_ERROR"; + String USER_ALREADY_EXISTS = "USER_ALREADY_EXISTS"; + String PAGE_ALREADY_EXIST = "PAGE_ALREADY_EXIST"; + String INVALID_USER_ID = "INVALID_USER_ID"; + String LOGIN_ID_MISSING = "LOGIN_ID_MISSING"; + String CONTENT_STATUS_MISSING_ERROR = "CONTENT_STATUS_MISSING_ERROR"; + String ES_ERROR = "ELASTICSEARCH_ERROR"; + String INVALID_PERIOD = "INVALID_PERIOD"; + String USER_NOT_FOUND = "USER_NOT_FOUND"; + String ID_REQUIRED_ERROR = "ID_REQUIRED_ERROR"; + String DATA_TYPE_ERROR = "DATA_TYPE_ERROR"; + String ERROR_ATTRIBUTE_CONFLICT = "ERROR_ATTRIBUTE_CONFLICT"; + String ADDRESS_ERROR = "ADDRESS_ERROR"; + String ADDRESS_TYPE_ERROR = "ADDRESS_TYPE_ERROR"; + String NAME_OF_INSTITUTION_ERROR = "NAME_OF_INSTITUTION_ERROR"; + String EDUCATION_DEGREE_ERROR = "EDUCATION_DEGREE_ERROR"; + String JOB_NAME_ERROR = "JOB_NAME_ERROR"; + String NAME_OF_ORGANISATION_ERROR = "NAME_OF_ORGANIZATION_ERROR"; + String ROLES_MISSING = "ROLES_REQUIRED_ERROR"; + String EMPTY_ROLES_PROVIDED = "EMPTY_ROLES_PROVIDED"; + String INVALID_DATE_FORMAT = "INVALID_DATE_FORMAT"; + String SRC_EXTERNAL_ID_ALREADY_EXIST = "SRC_EXTERNAL_ID_ALREADY_EXIST"; + String USER_ALREADY_ENROLLED_COURSE = "USER_ALREADY_ENROLLED_COURSE"; + String USER_NOT_ENROLLED_COURSE = "USER_NOT_ENROLLED_COURSE"; + String USER_ALREADY_COMPLETED_COURSE = "USER_ALREADY_COMPLETED_COURSE"; + String COURSE_BATCH_ALREADY_COMPLETED = "COURSE_BATCH_ALREADY_COMPLETED"; + String COURSE_BATCH_ENROLLMENT_DATE_ENDED = "COURSE_BATCH_ENROLLMENT_DATE_ENDED"; + String CONTENT_TYPE_ERROR = "CONTENT_TYPE_ERROR"; + String INVALID_PROPERTY_ERROR = "INVALID_PROPERTY_ERROR"; + String USER_NAME_OR_ID_ERROR = "USER_NAME_OR_ID_ERROR"; + String USER_ACCOUNT_BLOCKED = "USER_ACCOUNT_BLOCKED"; + String EMAIL_VERIFY_ERROR = "EMAIL_VERIFY_ERROR"; + String PHONE_VERIFY_ERROR = "PHONE_VERIFY_ERROR"; + String BULK_USER_UPLOAD_ERROR = "BULK_USER_UPLOAD_ERROR"; + String DATA_SIZE_EXCEEDED = "DATA_SIZE_EXCEEDED"; + String INVALID_COLUMN_NAME = "INVALID_COLUMN_NAME"; + String USER_ALREADY_ACTIVE = "USER_ALREADY_ACTIVE"; + String USER_ALREADY_INACTIVE = "USER_ALREADY_INACTIVE"; + String ENROLMENT_TYPE_REQUIRED = "ENROLMENT_TYPE_REQUIRED"; + String ENROLMENT_TYPE_VALUE_ERROR = "ENROLMENT_TYPE_VALUE_ERROR"; + String COURSE_BATCH_START_DATE_REQUIRED = "COURSE_BATCH_START_DATE_REQUIRED"; + String COURSE_BATCH_START_DATE_INVALID = "COURSE_BATCH_START_DATE_INVALID"; + String DATE_FORMAT_ERRROR = "DATE_FORMAT_ERRROR"; + String END_DATE_ERROR = "END_DATE_ERROR"; + String ENROLLMENT_END_DATE_START_ERROR = "ENROLLMENT_END_DATE_START_ERROR"; + String ENROLLMENT_END_DATE_END_ERROR = "ENROLLMENT_END_DATE_END_ERROR"; + String ENROLLMENT_END_DATE_UPDATE_ERROR = "ENROLLMENT_END_DATE_UPDATE_ERROR"; + String INVALID_CSV_FILE = "INVALID_CSV_FILE"; + String INVALID_COURSE_BATCH_ID = "INVALID_COURSE_BATCH_ID"; + String COURSE_BATCH_ID_MISSING = "COURSE_BATCH_ID_MISSING"; + String ENROLLMENT_TYPE_VALIDATION = "ENROLLMENT_TYPE_VALIDATION"; + String COURSE_CREATED_FOR_NULL = "COURSE_CREATED_FOR_NULL"; + String USER_NOT_BELONGS_TO_ANY_ORG = "USER_NOT_BELONGS_TO_ANY_ORG"; + String INVALID_OBJECT_TYPE = "INVALID_OBJECT_TYPE"; + String INVALID_PROGRESS_STATUS = "INVALID_PROGRESS_STATUS"; + String COURSE_BATCH_START_PASSED_DATE_INVALID = "COURSE_BATCH_START_PASSED_DATE_INVALID"; + String UNABLE_TO_CONNECT_TO_EKSTEP = "UNABLE_TO_CONNECT_TO_EKSTEP"; + String UNABLE_TO_CONNECT_TO_ES = "UNABLE_TO_CONNECT_TO_ES"; + String UNABLE_TO_PARSE_DATA = "UNABLE_TO_PARSE_DATA"; + String INVALID_JSON = "INVALID_JSON"; + String EMPTY_CSV_FILE = "EMPTY_CSV_FILE"; + String INVALID_ROOT_ORG_DATA = "INVALID_ROOT_ORG_DATA"; + String NO_DATA = "NO_DATA"; + String INVALID_CHANNEL = "INVALID_CHANNEL"; + String INVALID_PROCESS_ID = "INVALID_PROCESS_ID"; + String EMAIL_SUBJECT_ERROR = "EMAIL_SUBJECT_ERROR"; + String EMAIL_BODY_ERROR = "EMAIL_BODY_ERROR"; + String RECIPIENT_ADDRESS_ERROR = "RECIPIENT_ADDRESS_ERROR"; + String ISSUER_ID_REQUIRED = "ISSUER_ID_REQUIRED"; + String ISSUER_LIST_REQUIRED = "ISSUER_LIST_REQUIRED"; + String BADGE_ID_REQUIRED = "BADGE_ID_REQUIRED"; + String ROOT_ORG_ID_REQUIRED = "BADGE_ROOT_ORG_ID_REQUIRED"; + String BADGE_TYPE_REQUIRED = "BADGE_TYPE_REQUIRED"; + String INVALID_BADGE_TYPE = "INVALID_BADGE_TYPE"; + String INVALID_BADGE_SUBTYPE = "INVALID_BADGE_SUBTYPE"; + String INVALID_BADGE_ROLE = "INVALID_BADGE_ROLE"; + String BADGE_ROLES_REQUIRED = "BADGE_ROLES_REQUIRED"; + String BADGE_NAME_REQUIRED = "BADGE_NAME_REQUIRED"; + String BADGE_DESCRIPTION_REQUIRED = "BADGE_DESCRIPTION_REQUIRED"; + String BADGE_CRITERIA_REQUIRED = "BADGE_CRITERIA_REQUIRED"; + String BADGE_IMAGE_REQUIRED = "BADGE_IMAGE_REQUIRED"; + String RECIPIENT_EMAIL_REQUIRED = "RECIPIENT_EMAIL_REQUIRED"; + String ASSERTION_EVIDENCE_REQUIRED = "ASSERTION_EVIDENCE_REQUIRED"; + String ASSERTION_ID_REQUIRED = "ASSERTION_ID_REQUIRED"; + String STORAGE_CONTAINER_NAME_MANDATORY = "STORAGE_CONTAINER_NAME_MANDATORY"; + String USER_ORG_ASSOCIATION_ERROR = "USER_ORG_ASSOCIATION_ERROR"; + String CLOUD_SERVICE_ERROR = "CLOUD_SERVICE_ERROR"; + String BADGE_TYPE_ID_ERROR = "BADGE_TYPE_ID_ERROR"; + String RECEIVER_ID_ERROR = "RECEIVER_ID_ERROR"; + String INVALID_RECEIVER_ID = "INVALID_RECEIVER_ID"; + String INVALID_BADGE_ID = "INVALID_BADGE_ID"; + String INVALID_ROLE = "INVALID_ROLE"; + String INVALID_SALT = "INVALID_SALT"; + String ORG_TYPE_MANDATORY = "ORG_TYPE_MANDATORY"; + String ORG_TYPE_ALREADY_EXIST = "ORG_TYPE_ALREADY_EXIST"; + String ORG_TYPE_ID_REQUIRED_ERROR = "ORG_TYPE_ID_REQUIRED_ERROR"; + String TITLE_REQUIRED = "TITLE_REQUIRED"; + String NOTE_REQUIRED = "NOTE_REQUIRED"; + String CONTENT_ID_ERROR = "CONTENT_ID_OR_COURSE_ID_REQUIRED"; + String INVALID_TAGS = "INVALID_TAGS"; + String NOTE_ID_INVALID = "NOTE_ID_INVALID"; + String USER_DATA_ENCRYPTION_ERROR = "USER_DATA_ENCRYPTION_ERROR"; + String INVALID_PHONE_NO_FORMAT = "INVALID_PHONE_NO_FORMAT"; + String INVALID_WEBPAGE_DATA = "INVALID_WEBPAGE_DATA"; + String INVALID_MEDIA_TYPE = "INVALID_MEDIA_TYPE"; + String INVALID_WEBPAGE_URL = "INVALID_WEBPAGE_URL"; + String INVALID_DATE_RANGE = "INVALID_DATE_RANGE"; + String INVALID_BATCH_END_DATE_ERROR = "INVALID_BATCH_END_DATE_ERROR"; + String INVALID_BATCH_START_DATE_ERROR = "INVALID_BATCH_START_DATE_ERROR"; + String COURSE_BATCH_END_DATE_ERROR = "COURSE_BATCH_END_DATE_ERROR"; + String COURSE_BATCH_IS_CLOSED_ERROR = "COURSE_BATCH_IS_CLOSED_ERROR"; + String CONFIIRM_PASSWORD_MISSING = "CONFIIRM_PASSWORD_MISSING"; + String CONFIIRM_PASSWORD_EMPTY = "CONFIIRM_PASSWORD_EMPTY"; + String SAME_PASSWORD_ERROR = "SAME_PASSWORD_ERROR"; + String ENDORSED_USER_ID_REQUIRED = "ENDORSED_USER_ID_REQUIRED"; + String CAN_NOT_ENDORSE = "CAN_NOT_ENDORSE"; + String INVALID_ORG_TYPE_ID_ERROR = "INVALID_ORG_TYPE_ID_ERROR"; + String INVALID_ORG_TYPE_ERROR = "INVALID_ORG_TYPE_ERROR"; + String TABLE_OR_DOC_NAME_ERROR = "TABLE_OR_DOC_NAME_ERROR"; + String EMAIL_OR_PHONE_MISSING = "EMAIL_OR_PHONE_MISSING"; + String EMAIL_OR_PHONE_OR_MANAGEDBY_MISSING = "EMAIL_OR_PHONE_OR_MANAGEDBY_MISSING"; + String ONLY_EMAIL_OR_PHONE_OR_MANAGEDBY_REQUIRED = "ONLY_EMAIL_OR_PHONE_OR_MANAGEDBY_REQUIRED"; + String PHONE_ALREADY_IN_USE = "PHONE_ALREADY_IN_USE"; + String INVALID_CLIENT_NAME = "INVALID_CLIENT_NAME"; + String INVALID_CLIENT_ID = "INVALID_CLIENT_ID"; + String USER_PHONE_UPDATE_FAILED = "USER_PHONE_UPDATE_FAILED"; + String ES_UPDATE_FAILED = "ES_UPDATE_FAILED"; + String UPDATE_FAILED = "UPDATE_FAILED"; + String INVALID_TYPE_VALUE = "INVALID_TYPE_VALUE"; + String INVALID_LOCATION_ID = "INVALID_LOCATION_ID"; + String INVALID_HASHTAG_ID = "INVALID_HASHTAG_ID"; + String INVALID_USR_ORG_DATA = "INVALID_USR_ORG_DATA"; + String INVALID_VISIBILITY_REQUEST = "INVALID_VISIBILITY_REQUEST"; + String INVALID_TOPIC_NAME = "INVALID_TOPIC_NAME"; + String INVALID_TOPIC_DATA = "INVALID_TOPIC_DATA"; + String INVALID_NOTIFICATION_TYPE = "INVALID_NOTIFICATION_TYPE"; + String INVALID_NOTIFICATION_TYPE_SUPPORT = "INVALID_NOTIFICATION_TYPE_SUPPORT"; + String INVALID_PHONE_NUMBER = "INVALID_PHONE_NUMBER"; + String INVALID_COUNTRY_CODE = "INVALID_COUNTRY_CODE"; + String LOCATION_ID_REQUIRED = "LOCATION_ID_REQUIRED"; + String NOT_SUPPORTED = "NOT_SUPPORTED"; + String USERNAME_USERID_MISSING = "USERNAME_USERID_MISSING"; + String CHANNEL_REG_FAILED = "CHANNEL_REG_FAILED"; + String INVALID_COURSE_CREATOR_ID = "INVALID_COURSE_CREATOR_ID"; + String USER_NOT_ASSOCIATED_TO_ROOT_ORG = "USER_NOT_ASSOCIATED_TO_ROOT_ORG"; + String SLUG_IS_NOT_UNIQUE = "SLUG_IS_NOT_UNIQUE"; + String INVALID_CREATE_BADGE_ISSUER_DATA = "INVALID_CREATE_BADGE_ISSUER_DATA"; + String RECIPIENT_ID_REQUIRED = "RECIPIENT_ID_REQUIRED"; + String RECIPIENT_TYPE_REQUIRED = "RECIPIENT_TYPE_REQUIRED"; + String BADGING_SERVER_ERROR = "BADGING_SERVER_ERROR"; + String RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND"; + String MAX_ALLOWED_SIZE_LIMIT_EXCEED = "MAX_ALLOWED_SIZE_LIMIT_EXCEED"; + String SLUG_REQUIRED = "SLUG_REQUIRED"; + String INVALID_ISSUER_ID = "INVALID_ISSUER_ID"; + String REVOCATION_REASON_REQUIRED = "REVOCATION_REASON_REQUIRED"; + String ALREADY_REVOKED = "ALREADY_REVOKED"; + String INVALID_RECIPIENT_TYPE = "INVALID_RECIPIENT_TYPE"; + String CUSTOM_CLIENT_ERROR = "CLIENT_ERROR"; + String CUSTOM_RESOURCE_NOT_FOUND_ERROR = "RESOURCE_NOT_FOUND"; + String CUSTOM_SERVER_ERROR = "SERVER_ERROR"; + String INACTIVE_USER = "INACTIVE_USER"; + String USER_INACTIVE_FOR_THIS_ORG = "USER_INACTIVE_FOR_THIS_ORG"; + String USER_UPDATE_FAILED_FOR_THIS_ORG = "USER_UPDATE_FAILED_FOR_THIS_ORG"; + String PREFERENCE_KEY_MISSING = "PREFERENCE_KEY_MISSING"; + String PAGE_NOT_EXIST = "PAGE_NOT_EXIST"; + String SECTION_NOT_EXIST = "SECTION_NOT_EXIST"; + String ORG_NOT_EXIST = "ORG_NOT_EXIST"; + String INVALID_PAGE_SOURCE = "INVALID_PAGE_SOURCE"; + String BADGE_SUBTYPE_REQUIRED = "BADGE_SUBTYPE_REQUIRED"; + String LOCATION_TYPE_REQUIRED = "LOCATION_TYPE_REQUIRED"; + String INVALID_REQUEST_DATA_FOR_LOCATION = "INVALID_REQUEST_DATA_CREATE_LOCATION"; + String ALREADY_EXISTS = "ALREADY_EXISTS"; + String INVALID_VALUE = "INVALID_VALUE"; + String PARENT_CODE_AND_PARENT_ID_MISSING = "PARENT_CODE_AND_PARENT_ID_MISSING"; + String INVALID_PARAMETER = "INVALID_PARAMETER"; + String INVALID_PARENT_ID = "INVALID_PARENT_ID"; + String INVALID_LOCATION_DELETE_REQUEST = "INVALID_LOCATION_DELETE_REQUEST"; + String LOCATION_TYPE_CONFLICTS = "LOCATION_TYPE_CONFLICTS"; + String MANDATORY_PARAMETER_MISSING = "MANDATORY_PARAMETER_MISSING"; + String ERROR_MANDATORY_PARAMETER_EMPTY = "ERROR_MANDATORY_PARAMETER_EMPTY"; + String ERROR_NO_FRAMEWORK_FOUND = "ERROR_NO_FRAMEWORK_FOUND"; + String INVALID_LOCN_ID = "INVALID_LOCATION_ID"; + String UPDATE_NOT_ALLOWED = "UPDATE_NOT_ALLOWED"; + String MANDATORY_HEADER_MISSING = "MANDATORY_HEADER_MISSING"; + String INVALID_PARAMETER_VALUE = "INVALID_PARAMETER_VALUE"; + String PARENT_NOT_ALLOWED = "PARENT_NOT_ALLOWED"; + String MISSING_FILE_ATTACHMENT = "MISSING_FILE_ATTACHMENT"; + String FILE_ATTACHMENT_SIZE_NOT_CONFIGURED = "ATTACHMENT_SIZE_NOT_CONFIGURED"; + String EMPTY_FILE = "EMPTY_FILE"; + String INVALID_COLUMNS = "INVALID_COLUMNS"; + String INVALID_COLUMN = "INVALID_COLUMN"; + String CONFLICTING_ORG_LOCATIONS = "CONFLICTING_ORG_LOCATIONS"; + String UNABLE_TO_COMMUNICATE_WITH_ACTOR = "UNABLE_TO_COMMUNICATE_WITH_ACTOR"; + String EMPTY_HEADER_LINE = "EMPTY_HEADER_LINE"; + String INVALID_REQUEST_PARAMETER = "INVALID_REQUEST_PARAMETER"; + String ROOT_ORG_ASSOCIATION_ERROR = "ROOT_ORG_ASSOCIATION_ERROR"; + String DEPENDENT_PARAMETER_MISSING = "DEPENDENT_PARAMETER_MISSING"; + String EXTERNALID_NOT_FOUND = "EXTERNALID_NOT_FOUND"; + String EXTERNALID_ASSIGNED_TO_OTHER_USER = "EXTERNALID_ASSIGNED_TO_OTHER_USER"; + String MANDATORY_CONFIG_PARAMETER_MISSING = "MANDATORY_CONFIG_PARAMETER_MISSING"; + String CASSANDRA_CONNECTION_ESTABLISHMENT_FAILED = "CASSANDRA_CONNECTION_ESTABLISHMENT_FAILED"; + String COMMON_ATTRIBUTE_MISMATCH = "COMMON_ATTRIBUTE_MISMATCH"; + String MULTIPLE_COURSES_FOR_BATCH = "MULTIPLE_COURSES_FOR_BATCH"; + String ERROR_JSON_TRANSFORM_INVALID_TYPE_CONFIG = "ERROR_JSON_TRANSFORM_INVALID_TYPE_CONFIG"; + String ERROR_JSON_TRANSFORM_INVALID_DATE_FORMAT = "ERROR_JSON_TRANSFORM_INVALID_DATE_FORMAT"; + String ERROR_JSON_TRANSFORM_INVALID_INPUT = "ERROR_JSON_TRANSFORM_INVALID_INPUT"; + String ERROR_JSON_TRANSFORM_INVALID_ENUM_INPUT = "ERROR_JSON_TRANSFORM_INVALID_ENUM_INPUT"; + String ERROR_JSON_TRANSFORM_ENUM_VALUES_EMPTY = "ERROR_JSON_TRANSFORM_ENUM_VALUES_EMPTY"; + String ERROR_JSON_TRANSFORM_BASIC_CONFIG_MISSING = "ERROR_JSON_TRANSFORM_BASIC_CONFIG_MISSING"; + String ERROR_JSON_TRANSFORM_INVALID_FILTER_CONFIG = + "ERROR_JSON_TRANSFORM_INVALID_FILTER_CONFIG"; + String ERROR_LOAD_CONFIG = "ERROR_LOAD_CONFIG"; + String ERROR_REGISTRY_CLIENT_CREATION = "ERROR_REGISTRY_CLIENT_CREATION"; + String ERROR_REGISTRY_ADD_ENTITY = "ERROR_REGISTRY_ADD_ENTITY"; + String ERROR_REGISTRY_READ_ENTITY = "ERROR_REGISTRY_READ_ENTITY"; + String ERROR_REGISTRY_UPDATE_ENTITY = "ERROR_REGISTRY_UPDATE_ENTITY"; + String ERROR_REGISTRY_DELETE_ENTITY = "ERROR_REGISTRY_DELETE_ENTITY"; + String ERROR_REGISTRY_PARSE_RESPONSE = "ERROR_REGISTRY_PARSE_RESPONSE"; + String ERROR_REGISTRY_ENTITY_TYPE_BLANK = "ERROR_REGISTRY_ENTITY_TYPE_BLANK"; + String ERROR_REGISTRY_ENTITY_ID_BLANK = "ERROR_REGISTRY_ENTITY_ID_BLANK"; + String ERROR_REGISTRY_ACCESS_TOKEN_BLANK = "ERROR_REGISTRY_ACCESS_TOKEN_BLANK"; + String DUPLICATE_EXTERNAL_IDS = "DUPLICATE_EXTERNAL_IDS"; + String INVALID_DUPLICATE_VALUE = "INVALID_DUPLICATE_VALUE"; + String EMAIL_RECIPIENTS_EXCEEDS_MAX_LIMIT = "EMAIL_RECIPIENTS_EXCEEDS_MAX_LIMIT"; + String NO_EMAIL_RECIPIENTS = "NO_EMAIL_RECIPIENTS"; + String PARAMETER_MISMATCH = "PARAMETER_MISMATCH"; + String FORBIDDEN = "FORBIDDEN"; + String ERROR_CONFIG_LOAD_EMPTY_STRING = "ERROR_CONFIG_LOAD_EMPTY_STRING"; + String ERROR_CONFIG_LOAD_PARSE_STRING = "ERROR_CONFIG_LOAD_PARSE_STRING"; + String ERROR_CONFIG_LOAD_EMPTY_CONFIG = "ERROR_CONFIG_LOAD_EMPTY_CONFIG"; + String ERROR_CONFLICTING_FIELD_CONFIGURATION = "ERROR_CONFLICTING_FIELD_CONFIGURATION"; + String ERROR_SYSTEM_SETTING_NOT_FOUND = "ERROR_SYSTEM_SETTING_NOT_FOUND"; + String ERROR_NO_ROOT_ORG_ASSOCIATED = "ERROR_NO_ROOT_ORG_ASSOCIATED"; + String ERROR_INACTIVE_CUSTODIAN_ORG = "ERROR_INACTIVE_CUSTODIAN_ORG"; + String ERROR_UNSUPPORTED_CLOUD_STORAGE = "ERROR_ UNSUPPORTED_CLOUD_STORAGE"; + String ERROR_UNSUPPORTED_FIELD = "ERROR_UNSUPPORTED_FIELD"; + String ERROR_GENERATE_DOWNLOAD_LINK = "ERROR_GENERATING_DOWNLOAD_LINK"; + String ERROR_DOWNLOAD_LINK_UNAVAILABLE = "ERROR_DOWNLOAD_LINK_UNAVAILABLE"; + String ERROR_SAVING_STORAGE_DETAILS = "ERROR_SAVING_STORAGE_DETAILS"; + String ERROR_CSV_NO_DATA_ROWS = "ERROR_CSV_NO_DATA_ROWS"; + String ERROR_INACTIVE_ORG = "ERROR_INACTIVE_ORG"; + String ERROR_DUPLICATE_ENTRIES = "ERROR_DUPLICATE_ENTRIES"; + String ERROR_CONFLICTING_VALUES = "ERROR_CONFLICTING_VALUES"; + String ERROR_CONFLICTING_ROOT_ORG_ID = "ERROR_CONFLICTING_ROOT_ORG_ID"; + String ERROR_UPDATE_SETTING_NOT_ALLOWED = "ERROR_UPDATE_SETTING_NOT_ALLOWED"; + String ERROR_CREATING_FILE = "ERROR_CREATING_FILE"; + String ERROR_PROCESSING_REQUEST = "ERROR_PROCESSING_REQUEST"; + String ERROR_UNAVAILABLE_CERTIFICATE = "ERROR_UNAVAILABLE_CERTIFICATE"; + String INVALID_TEXTBOOK = "INVALID_TEXTBOOK"; + String CSV_ROWS_EXCEEDS = "CSV_ROWS_EXCEEDS"; + String INVALID_TEXTBOOK_NAME = "INVALID_TEXTBOOK_NAME"; + String DUPLICATE_ROWS = "DUPLICATE_ROWS"; + String ERROR_INVALID_OTP = "ERROR_INVALID_OTP"; + String REQUIRED_HEADER_MISSING = "REQUIRED_HEADER_MISSING"; + String REQUIRED_FIELD_MISSING = "REQUIRED_FIELD_MISSING"; + String BLANK_CSV_DATA = "BLANK_CSV_DATA"; + String EXCEEDS_MAX_CHILDREN = "EXCEEDS_MAX_CHILDREN"; + String TEXTBOOK_CHILDREN_EXISTS = "TEXTBOOK_CHILDREN_EXISTS"; + String TEXTBOOK_UPDATE_FAILURE = "TEXTBOOK_UPDATE_FAILURE"; + String TEXTBOOK_CHILDREN_NOT_EXISTS = "TEXTBOOK_CHILDREN_NOT_EXISTS"; + String TEXTBOOK_NOT_FOUND = "TEXTBOOK_NOT_FOUND"; + String ERROR_PROCESSING_FILE = "ERROR_PROCESSING_FILE"; + String ERR_FILE_NOT_FOUND = "ERR_FILE_NOT_FOUND"; + String ERROR_TB_UPDATE = "ERROR_TB_UPDATE"; + String ERROR_INVALID_PARAMETER_SIZE = "ERROR_INVALID_PARAMETER_SIZE"; + String INVALID_PAGE_SECTION = "INVALID_PAGE_SECTION"; + String ERROR_RATE_LIMIT_EXCEEDED = "ERROR_RATE_LIMIT_EXCEEDED"; + String ERROR_INVALID_CONFIG_PARAM_VALUE = "ERROR_INVALID_CONFIG_PARAM_VALUE"; + String ERROR_MAX_SIZE_EXCEEDED = "ERROR_MAX_SIZE_EXCEEDED"; + String ERROR_INVALID_DIAL_CODE = "ERROR_INVALID_DIAL_CODE"; + String ERROR_INVALID_TOPIC = "ERROR_INVALID_TOPIC"; + String ERROR_DIAL_CODE_DUPLICATE_ENTRY = "ERROR_DIAL_CODE_DUPLICATE_ENTRY"; + String ERROR_DIAL_CODE_ALREADY_ASSOCIATED = "ERROR_DIAL_CODE_ALREADY_ASSOCIATED"; + String DIAL_CODE_LINKING_FAILED = "DIAL_CODE_LINKING_FAILED"; + String ERROR_TEXTBOOK_UPDATE = "ERROR_TEXTBOOK_UPDATE"; + String ERROR_INVALID_LINKED_CONTENT_ID = "ERROR_INVALID_LINKED_CONTENT_ID"; + String ERROR_DUPLICATE_LINKED_CONTENT = "DUPLICATE_LINKED_CONTENT"; + String TEACHER_CANNOT_BELONG_TO_CUSTODIAN_ORG = "TEACHER_CANNOT_BELONG_TO_CUSTODIAN_ORG"; + String ERROR_DUPLICATE_QR_CODE_ENTRY = "ERROR_DUPLICATE_QR_CODE_ENTRY"; + String ERROR_INVALID_TEXTBOOK_UNIT_ID = "ERROR_INVALID_TEXTBOOK_UNIT_ID"; + String INVALID_REQUEST_TIMEOUT = "INVALID_REQUEST_TIMEOUT"; + String ERROR_BGMS_MISMATCH = "ERROR_BGMS_MISMATCH"; + String ERROR_USER_MIGRATION_FAILED = "ERROR_USER_MIGRATION_FAILED"; + String VALID_IDENTIFIER_ABSENSE = "IDENTIFIER IN LIST IS NOT SUPPORTED OR INCORRECT"; + String FROM_ACCOUNT_ID_MISSING = "FROM_ACCOUNT_ID_MISSING"; + String TO_ACCOUNT_ID_MISSING = "TO_ACCOUNT_ID_MISSING"; + String FROM_ACCOUNT_ID_NOT_EXISTS = "FROM_ACCOUNT_ID_NOT_EXISTS"; + String PARAM_NOT_MATCH = "%s-NOT-MATCH"; + String MANDATORY_HEADER_PARAMETER_MISSING = "MANDATORY_HEADER_PARAMETER_MISSING"; + String RECOVERY_PARAM_MATCH_EXCEPTION = "RECOVERY_PARAM_MATCH_EXCEPTION"; + String EMPTY_CONTENTS_FOR_UPDATE_BATCH_STATUS = "EMPTY_CONTENTS_FOR_UPDATE_BATCH_STATUS"; + String ERROR_USER_HAS_NOT_CREATED_ANY_COURSE = "USER_HAS_NOT_CREATED_ANY_COURSE"; + String ERROR_UPLOAD_QRCODE_CSV_FAILED = "ERROR_UPLOAD_QRCODE_CSV_FAILED"; + String ERROR_NO_DIALCODES_LINKED = "ERROR_NO_DIALCODES_LINKED"; + String EVENTS_DATA_MISSING = "EVENTS_DATA_MISSING"; + String ACCOUNT_NOT_FOUND = "ACCOUNT_NOT_FOUND"; + String INVALID_EXT_USER_ID = "INVALID_EXT_USER_ID"; + String USER_MIGRATION_FAILED = "USER_MIGRATION_FAILED"; + String INVALID_ELEMENT_IN_LIST = "INVALID_ELEMENT_IN_LIST"; + String INVALID_PASSWORD = "INVALID_PASSWORD"; + String OTP_VERIFICATION_FAILED = "OTP_VERIFICATION_FAILED"; + String SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE"; + String MISSING_CODE = "ERR_COURSE_CREATE_FIELDS_MISSING"; + String MANAGED_BY_NOT_ALLOWED = "MANAGED_BY_NOT_ALLOWED"; + String MANAGED_BY_EMAIL_PHONE_UPDATE_ERROR = "MANAGED_BY_EMAIL_PHONE_UPDATE_ERROR"; + String MANAGED_USER_LIMIT_EXCEEDED = "MANAGED_USER_LIMIT_EXCEEDED"; + String UNABLE_TO_CONNECT_TO_ADMINUTIL = "UNABLE_TO_CONNECT_TO_ADMINUTIL"; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/package-info.java new file mode 100644 index 0000000000..b6c7ea9e2b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/responsecode/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.responsecode; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/ProfileCompletenessService.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/ProfileCompletenessService.java new file mode 100644 index 0000000000..63d0e10ec2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/ProfileCompletenessService.java @@ -0,0 +1,21 @@ +/** */ +package org.sunbird.common.services; + +import java.util.Map; + +/** + * This interface will have method to compute the profile completeness. + * + * @author Manzarul + */ +public interface ProfileCompletenessService { + + /** + * This method will compute the user profile completeness percentage based on attribute weighted + * settings. it will provide completeness percentage value and list of all missing keys. + * + * @param profileData Map + * @return Map + */ + Map computeProfile(Map profileData); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/ProfileCompletenessFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/ProfileCompletenessFactory.java new file mode 100644 index 0000000000..d544cf95fe --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/ProfileCompletenessFactory.java @@ -0,0 +1,13 @@ +/** */ +package org.sunbird.common.services.impl; + +import org.sunbird.common.services.ProfileCompletenessService; + +/** @author Manzarul */ +public class ProfileCompletenessFactory { + + /** @return */ + public static ProfileCompletenessService getInstance() { + return new ProfileCompletenessServiceImpl(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/ProfileCompletenessServiceImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/ProfileCompletenessServiceImpl.java new file mode 100644 index 0000000000..e14dbbbda3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/ProfileCompletenessServiceImpl.java @@ -0,0 +1,101 @@ +/** */ +package org.sunbird.common.services.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.services.ProfileCompletenessService; + +/** @author Manzarul */ +public class ProfileCompletenessServiceImpl implements ProfileCompletenessService { + + @Override + public Map computeProfile(Map profileData) { + Map response = new HashMap<>(); + float completedCount = 0; + if (profileData == null || profileData.size() == 0) { + response.put(JsonKey.COMPLETENESS, (int) Math.ceil(completedCount)); + response.put(JsonKey.MISSING_FIELDS, findMissingAttribute(profileData)); + return response; + } + Iterator> itr = profileData.entrySet().iterator(); + while (itr.hasNext()) { + Entry entry = itr.next(); + Object value = entry.getValue(); + if (value instanceof List) { + List list = (List) value; + if (list.size() > 0) { + completedCount = completedCount + getValue(entry.getKey()); + } + } else if (value instanceof Map) { + Map map = (Map) value; + if (map != null && map.size() > 0) { + completedCount = completedCount + getValue(entry.getKey()); + } + } else { + if (value != null && !StringUtils.isBlank(value.toString())) { + completedCount = completedCount + getValue(entry.getKey()); + } + } + } + response.put(JsonKey.COMPLETENESS, (int) Math.ceil(completedCount)); + response.put(JsonKey.MISSING_FIELDS, findMissingAttribute(profileData)); + return response; + } + + /** + * This method will provide weighted value for particular attribute + * + * @param key String + * @return float + */ + private float getValue(String key) { + return PropertiesCache.getInstance().attributePercentageMap.get(key) != null + ? PropertiesCache.getInstance().attributePercentageMap.get(key) + : 0; + } + + /** + * This method will provide all the missing filed list + * + * @param profileData Map + * @return List + */ + private List findMissingAttribute(Map profileData) { + List attribute = new ArrayList<>(); + Iterator> itr = + PropertiesCache.getInstance().attributePercentageMap.entrySet().iterator(); + while (itr.hasNext()) { + Entry entry = itr.next(); + if (profileData == null || !profileData.containsKey(entry.getKey())) { + attribute.add(entry.getKey()); + } else { + Object val = profileData.get(entry.getKey()); + if (val == null) { + attribute.add(entry.getKey()); + } else if (val instanceof List) { + List list = (List) val; + if (list.size() == 0) { + attribute.add(entry.getKey()); + } + } else if (val instanceof Map) { + Map map = (Map) val; + if (map == null || map.size() == 0) { + attribute.add(entry.getKey()); + } + } else { + if (StringUtils.isBlank(val.toString())) { + attribute.add(entry.getKey()); + } + } + } + } + return attribute; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/package-info.java new file mode 100644 index 0000000000..9513083f39 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/impl/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.services.impl; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/package-info.java new file mode 100644 index 0000000000..38e8eba946 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/services/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.common.services; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/CloudStorageUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/CloudStorageUtil.java new file mode 100644 index 0000000000..0f4f6b07b2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/CloudStorageUtil.java @@ -0,0 +1,120 @@ +package org.sunbird.common.util; + +import java.util.HashMap; +import java.util.Map; +import org.sunbird.cloud.storage.IStorageService; +import org.sunbird.cloud.storage.factory.StorageConfig; +import org.sunbird.cloud.storage.factory.StorageServiceFactory; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.responsecode.ResponseCode; +import scala.Option; +import scala.Some; + +public class CloudStorageUtil { + private static final int STORAGE_SERVICE_API_RETRY_COUNT = 3; + + private static final Map storageServiceMap = new HashMap<>(); + + public enum CloudStorageType { + AZURE("azure"); + private String type; + + private CloudStorageType(String type) { + this.type = type; + } + + public String getType() { + return this.type; + } + + public static CloudStorageType getByName(String type) { + if (AZURE.type.equals(type)) { + return CloudStorageType.AZURE; + } else { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorUnsupportedCloudStorage, + ProjectUtil.formatMessage( + ResponseCode.errorUnsupportedCloudStorage.getErrorMessage(), type)); + return null; + } + } + } + + public static String upload( + CloudStorageType storageType, String container, String objectKey, String filePath) { + + IStorageService storageService = getStorageService(storageType); + + return storageService.upload( + container, + filePath, + objectKey, + Option.apply(false), + Option.apply(1), + Option.apply(STORAGE_SERVICE_API_RETRY_COUNT), + Option.empty()); + } + + public static String getSignedUrl( + CloudStorageType storageType, String container, String objectKey) { + IStorageService storageService = getStorageService(storageType); + return getSignedUrl(storageService, storageType, container, objectKey); + } + + public static String getAnalyticsSignedUrl( + CloudStorageType storageType, String container, String objectKey) { + IStorageService analyticsStorageService = getAnalyticsStorageService(storageType); + return getSignedUrl(analyticsStorageService, storageType, container, objectKey); + } + + public static String getSignedUrl( + IStorageService storageService, + CloudStorageType storageType, + String container, + String objectKey) { + int timeoutInSeconds = getTimeoutInSeconds(); + return storageService.getSignedURL( + container, objectKey, Some.apply(timeoutInSeconds), Some.apply("r")); + } + + private static IStorageService getStorageService(CloudStorageType storageType) { + String storageKey = PropertiesCache.getInstance().getProperty(JsonKey.ACCOUNT_NAME); + String storageSecret = PropertiesCache.getInstance().getProperty(JsonKey.ACCOUNT_KEY); + return getStorageService(storageType, storageKey, storageSecret); + } + + private static IStorageService getAnalyticsStorageService(CloudStorageType storageType) { + String storageKey = PropertiesCache.getInstance().getProperty(JsonKey.ANALYTICS_ACCOUNT_NAME); + String storageSecret = PropertiesCache.getInstance().getProperty(JsonKey.ANALYTICS_ACCOUNT_KEY); + return getStorageService(storageType, storageKey, storageSecret); + } + + private static IStorageService getStorageService( + CloudStorageType storageType, String storageKey, String storageSecret) { + String compositeKey = storageType.getType() + "-" + storageKey; + if (storageServiceMap.containsKey(compositeKey)) { + return storageServiceMap.get(compositeKey); + } + synchronized (CloudStorageUtil.class) { + StorageConfig storageConfig = + new StorageConfig(storageType.getType(), storageKey, storageSecret); + IStorageService storageService = StorageServiceFactory.getStorageService(storageConfig); + storageServiceMap.put(compositeKey, storageService); + } + return storageServiceMap.get(compositeKey); + } + + private static int getTimeoutInSeconds() { + String timeoutInSecondsStr = ProjectUtil.getConfigValue(JsonKey.DOWNLOAD_LINK_EXPIRY_TIMEOUT); + return Integer.parseInt(timeoutInSecondsStr); + } + + public static String getUri( + CloudStorageType storageType, String container, String prefix, boolean isDirectory) { + IStorageService storageService = getStorageService(storageType); + return storageService.getUri(container, prefix, Option.apply(isDirectory)); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/ConfigUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/ConfigUtil.java new file mode 100644 index 0000000000..50a0be8eed --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/ConfigUtil.java @@ -0,0 +1,133 @@ +package org.sunbird.common.util; + +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * This util class for providing type safe config to any service that requires it. + * + * @author Manzarul + */ +public class ConfigUtil { + + private static Config config; + private static final String DEFAULT_TYPE_SAFE_CONFIG_FILE_NAME = "service.conf"; + private static final String INVALID_FILE_NAME = "Please provide a valid file name."; + + /** Private default constructor. */ + private ConfigUtil() {} + + /** + * This method will create a type safe config object and return to caller. It will read the config + * value from System env first and as a fall back it will use service.conf file. + * + * @return Type safe config object + */ + public static Config getConfig() { + if (config == null) { + synchronized (ConfigUtil.class) { + config = createConfig(DEFAULT_TYPE_SAFE_CONFIG_FILE_NAME); + } + } + return config; + } + + /** + * This method will create a type safe config object and return to caller. It will read the config + * value from System env first and as a fall back it will use provided file name. If file name is + * null or empty then it will throw ProjectCommonException with status code as 500. + * + * @return Type safe config object + */ + public static Config getConfig(String fileName) { + if (StringUtils.isBlank(fileName)) { + ProjectLogger.log( + "ConfigUtil:getConfigWithFilename: Given file name is null or empty: " + fileName, + LoggerEnum.INFO.name()); + throw new ProjectCommonException( + ResponseCode.internalError.getErrorCode(), + INVALID_FILE_NAME, + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (config == null) { + synchronized (ConfigUtil.class) { + config = createConfig(fileName); + } + } + return config; + } + + public static void validateMandatoryConfigValue(String configParameter) { + if (StringUtils.isBlank(configParameter)) { + ProjectLogger.log( + "ConfigUtil:validateMandatoryConfigValue: Missing mandatory configuration parameter: " + + configParameter, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.mandatoryConfigParamMissing.getErrorCode(), + ResponseCode.mandatoryConfigParamMissing.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode(), + configParameter); + } + } + + private static Config createConfig(String fileName) { + Config defaultConf = ConfigFactory.load(fileName); + Config envConf = ConfigFactory.systemEnvironment(); + return envConf.withFallback(defaultConf); + } + + /* + * Parse configuration in JSON format and return a type safe config object. + * + * @param jsonString Configuration in JSON format + * @return Type safe config object + */ + public static Config getConfigFromJsonString(String jsonString, String configType) { + ProjectLogger.log("ConfigUtil: getConfigFromJsonString called", LoggerEnum.DEBUG.name()); + + if (null == jsonString || StringUtils.isBlank(jsonString)) { + ProjectLogger.log( + "ConfigUtil:getConfigFromJsonString: Empty string", LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException( + ResponseCode.errorConfigLoadEmptyString, + ProjectUtil.formatMessage( + ResponseCode.errorConfigLoadEmptyString.getErrorMessage(), configType)); + } + + Config jsonConfig = null; + try { + jsonConfig = ConfigFactory.parseString(jsonString); + } catch (Exception e) { + ProjectLogger.log( + "ConfigUtil:getConfigFromJsonString: Exception occurred during parse with error message = " + + e.getMessage(), + LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException( + ResponseCode.errorConfigLoadParseString, + ProjectUtil.formatMessage( + ResponseCode.errorConfigLoadParseString.getErrorMessage(), configType)); + } + + if (null == jsonConfig || jsonConfig.isEmpty()) { + ProjectLogger.log( + "ConfigUtil:getConfigFromJsonString: Empty configuration", LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException( + ResponseCode.errorConfigLoadEmptyConfig, + ProjectUtil.formatMessage( + ResponseCode.errorConfigLoadEmptyConfig.getErrorMessage(), configType)); + } + + ProjectLogger.log( + "ConfigUtil:getConfigFromJsonString: Successfully constructed type safe configuration", + LoggerEnum.DEBUG.name()); + + return jsonConfig; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/KeycloakRequiredActionLinkUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/KeycloakRequiredActionLinkUtil.java new file mode 100644 index 0000000000..f0c8b52bc8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/KeycloakRequiredActionLinkUtil.java @@ -0,0 +1,134 @@ +package org.sunbird.common.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.JsonNode; +import com.mashape.unirest.http.Unirest; +import com.mashape.unirest.request.BaseRequest; +import com.mashape.unirest.request.body.RequestBodyEntity; +import java.util.HashMap; +import java.util.Map; +import javax.ws.rs.core.MediaType; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHeaders; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; + +/** + * Keycloak utility to create required action links. + * + * @author Amit Kumar + */ +public class KeycloakRequiredActionLinkUtil { + + public static final String VERIFY_EMAIL = "VERIFY_EMAIL"; + public static final String UPDATE_PASSWORD = "UPDATE_PASSWORD"; + private static final String CLIENT_ID = "clientId"; + private static final String REQUIRED_ACTION = "requiredAction"; + private static final String USERNAME = "userName"; + private static final String EXPIRATION_IN_SEC = "expirationInSecs"; + private static final String REDIRECT_URI = "redirectUri"; + private static final String ACCESS_TOKEN = "access_token"; + private static final String SUNBIRD_KEYCLOAK_LINK_EXPIRATION_TIME = + "sunbird_keycloak_required_action_link_expiration_seconds"; + private static final String SUNBIRD_KEYCLOAK_REQD_ACTION_LINK = "/get-required-action-link"; + private static final String LINK = "link"; + + private static ObjectMapper mapper = new ObjectMapper(); + + /** + * Get generated link for specified type and user from Keycloak service. + * + * @param userName User name + * @param requiredAction Type of link to be generated. Supported types are UPDATE_PASSWORD and + * VERIFY_EMAIL. + * @return Generated link from Keycloak service + */ + public static String getLink(String userName, String redirectUri, String requiredAction) { + Map request = new HashMap<>(); + + request.put(CLIENT_ID, ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_CLIENT_ID)); + request.put(USERNAME, userName); + request.put(REQUIRED_ACTION, requiredAction); + + String expirationInSecs = ProjectUtil.getConfigValue(SUNBIRD_KEYCLOAK_LINK_EXPIRATION_TIME); + if (StringUtils.isNotBlank(expirationInSecs)) { + request.put(EXPIRATION_IN_SEC, expirationInSecs); + } + request.put(REDIRECT_URI, redirectUri); + + try { + Thread.sleep( + Integer.parseInt(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SYNC_READ_WAIT_TIME))); + return generateLink(request); + } catch (Exception ex) { + ProjectLogger.log( + "KeycloakRequiredActionLinkUtil:getLink: Exception occurred with error message = " + + ex.getMessage(), + ex); + } + return null; + } + + private static String generateLink(Map request) throws Exception { + Map headers = new HashMap<>(); + + headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + headers.put(JsonKey.AUTHORIZATION, JsonKey.BEARER + getAdminAccessToken()); + + ProjectLogger.log( + "KeycloakRequiredActionLinkUtil:generateLink: complete URL " + + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_URL) + + "realms/" + + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_RELAM) + + SUNBIRD_KEYCLOAK_REQD_ACTION_LINK, + LoggerEnum.INFO.name()); + ProjectLogger.log( + "KeycloakRequiredActionLinkUtil:generateLink: request body " + + mapper.writeValueAsString(request), + LoggerEnum.INFO.name()); + RequestBodyEntity baseRequest = + Unirest.post( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_URL) + + "realms/" + + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_RELAM) + + SUNBIRD_KEYCLOAK_REQD_ACTION_LINK) + .headers(headers) + .body(mapper.writeValueAsString(request)); + HttpResponse response = baseRequest.asJson(); + + ProjectLogger.log( + "KeycloakRequiredActionLinkUtil:generateLink: Response status = " + + response.getStatus() + + " body " + + response.getBody(), + LoggerEnum.INFO.name()); + + return response.getBody().getObject().getString(LINK); + } + + public static String getAdminAccessToken() throws Exception { + Map headers = new HashMap<>(); + headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); + BaseRequest request = + Unirest.post( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_URL) + + "realms/" + + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_RELAM) + + "/protocol/openid-connect/token") + .headers(headers) + .field("client_id", ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_CLIENT_ID)) + .field("client_secret", ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SSO_CLIENT_SECRET)) + .field("grant_type", "client_credentials"); + + HttpResponse response = request.asJson(); + ProjectLogger.log( + "KeycloakRequiredActionLinkUtil:getAdminAccessToken: Response status = " + + response.getStatus(), + LoggerEnum.INFO.name()); + + return response.getBody().getObject().getString(ACCESS_TOKEN); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/Matcher.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/Matcher.java new file mode 100644 index 0000000000..148321605e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/common/util/Matcher.java @@ -0,0 +1,19 @@ +package org.sunbird.common.util; + +import org.apache.commons.lang3.StringUtils; + +/** this class is used to match the identifiers. */ +public class Matcher { + + /** + * this method will match the two arguments , equal or not if two string is null or empty this + * method will return true + * + * @param firstVal + * @param secondVal + * @return boolean + */ + public static boolean matchIdentifiers(String firstVal, String secondVal) { + return StringUtils.equalsIgnoreCase(firstVal, secondVal); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/kafka/client/InstructionEventGenerator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/kafka/client/InstructionEventGenerator.java new file mode 100644 index 0000000000..b148e0d138 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/kafka/client/InstructionEventGenerator.java @@ -0,0 +1,105 @@ +package org.sunbird.kafka.client; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.telemetry.dto.TelemetryBJREvent; + +public class InstructionEventGenerator { + + private static ObjectMapper mapper = new ObjectMapper(); + private static String beJobRequesteventId = "BE_JOB_REQUEST"; + private static int iteration = 1; + + private static String actorId = "Sunbird LMS Samza Job"; + private static String actorType = "System"; + private static String pdataId = "org.sunbird.platform"; + private static String pdataVersion = "1.0"; + + public static void pushInstructionEvent(String topic, Map data) throws Exception { + pushInstructionEvent("", topic, data); + } + + public static void pushInstructionEvent(String key, String topic, Map data) + throws Exception { + String beJobRequestEvent = generateInstructionEventMetadata(data); + if (StringUtils.isBlank(beJobRequestEvent)) { + throw new ProjectCommonException( + "BE_JOB_REQUEST_EXCEPTION", + "Event is not generated properly.", + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (StringUtils.isNotBlank(topic)) { + if (StringUtils.isNotBlank(key)) KafkaClient.send(key, beJobRequestEvent, topic); + else KafkaClient.send(beJobRequestEvent, topic); + } else { + throw new ProjectCommonException( + "BE_JOB_REQUEST_EXCEPTION", + "Invalid topic id.", + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private static String generateInstructionEventMetadata(Map data) { + Map actor = new HashMap<>(); + Map context = new HashMap<>(); + Map object = new HashMap<>(); + Map edata = new HashMap<>(); + if (MapUtils.isNotEmpty((Map) data.get("actor"))) { + actor.putAll((Map) data.get("actor")); + } else { + actor.put("id", actorId); + actor.put("type", actorType); + } + + if (MapUtils.isNotEmpty((Map) data.get("context"))) { + context.putAll((Map) data.get("context")); + } + Map pdata = new HashMap<>(); + pdata.put("id", pdataId); + pdata.put("ver", pdataVersion); + context.put("pdata", pdata); + if (MapUtils.isNotEmpty((Map) data.get("object"))) object.putAll((Map) data.get("object")); + + if (MapUtils.isNotEmpty((Map) data.get("edata"))) edata.putAll((Map) data.get("edata")); + + if (StringUtils.isNotBlank((String) data.get("action"))) + edata.put("action", data.get("action")); + + return logInstructionEvent(actor, context, object, edata); + } + + private static String logInstructionEvent( + Map actor, + Map context, + Map object, + Map edata) { + + TelemetryBJREvent te = new TelemetryBJREvent(); + long unixTime = System.currentTimeMillis(); + String mid = "LP." + System.currentTimeMillis() + "." + UUID.randomUUID(); + edata.put("iteration", iteration); + + te.setEid(beJobRequesteventId); + te.setEts(unixTime); + te.setMid(mid); + te.setActor(actor); + te.setContext(context); + te.setObject(object); + te.setEdata(edata); + + String jsonMessage = null; + try { + jsonMessage = mapper.writeValueAsString(te); + } catch (Exception e) { + ProjectLogger.log("Error logging BE_JOB_REQUEST event: " + e.getMessage(), e); + } + return jsonMessage; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/kafka/client/KafkaClient.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/kafka/client/KafkaClient.java new file mode 100644 index 0000000000..0e22edc1bb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/kafka/client/KafkaClient.java @@ -0,0 +1,110 @@ +package org.sunbird.kafka.client; + +import java.util.List; +import java.util.Map; +import java.util.Properties; +import org.apache.kafka.clients.consumer.Consumer; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.PartitionInfo; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; + +/** + * Helper class for creating a Kafka consumer and producer. + * + * @author Pradyumna + */ +public class KafkaClient { + + private static final String BOOTSTRAP_SERVERS = ProjectUtil.getConfigValue("kafka_urls"); + private static Producer producer; + private static Consumer consumer; + private static volatile Map> topics; + + static { + loadProducerProperties(); + loadConsumerProperties(); + loadTopics(); + } + + private static void loadProducerProperties() { + Properties props = new Properties(); + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS); + props.put(ProducerConfig.CLIENT_ID_CONFIG, "KafkaClientProducer"); + props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + props.put(ProducerConfig.LINGER_MS_CONFIG, ProjectUtil.getConfigValue("kafka_linger_ms")); + producer = new KafkaProducer(props); + } + + private static void loadTopics() { + if (consumer == null) { + loadConsumerProperties(); + } + topics = consumer.listTopics(); + ProjectLogger.log( + "KafkaClient:loadTopics Kafka topic infos =>" + topics, LoggerEnum.INFO.name()); + } + + private static void loadConsumerProperties() { + Properties props = new Properties(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS); + props.put(ConsumerConfig.CLIENT_ID_CONFIG, "KafkaClientConsumer"); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumer = new KafkaConsumer<>(props); + } + + public static Producer getProducer() { + return producer; + } + + public static Consumer getConsumer() { + return consumer; + } + + public static void send(String event, String topic) throws Exception { + if (validate(topic)) { + final Producer producer = getProducer(); + ProducerRecord record = new ProducerRecord(topic, event); + producer.send(record); + } else { + ProjectLogger.log("Topic id: " + topic + ", does not exists.", LoggerEnum.ERROR); + throw new ProjectCommonException( + "TOPIC_NOT_EXISTS_EXCEPTION", + "Topic id: " + topic + ", does not exists.", + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + public static void send(String key, String event, String topic) throws Exception { + if (validate(topic)) { + final Producer producer = getProducer(); + ProducerRecord record = new ProducerRecord(topic, key, event); + producer.send(record); + } else { + ProjectLogger.log("Topic id: " + topic + ", does not exists.", LoggerEnum.ERROR); + throw new ProjectCommonException( + "TOPIC_NOT_EXISTS_EXCEPTION", + "Topic id: " + topic + ", does not exists.", + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private static boolean validate(String topic) throws Exception { + if (topics == null) { + loadTopics(); + } + return topics.keySet().contains(topic); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/SSOManager.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/SSOManager.java new file mode 100644 index 0000000000..4726818368 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/SSOManager.java @@ -0,0 +1,131 @@ +/** */ +package org.sunbird.services.sso; + +import java.util.Map; + +/** @author Manzarul This interface will handle all call related to single sign out. */ +public interface SSOManager { + + /** + * This method will verify user access token and provide userId if token is valid. in case of + * invalid access token it will throw ProjectCommon exception with 401. + * + * @param token String JWT access token + * @return String + */ + String verifyToken(String token); + + /** Update password in SSO server (keycloak). */ + boolean updatePassword(String userId, String password); + + /** + * Method to update user account in keycloak on basis of userId. + * + * @param request + * @return + */ + String updateUser(Map request); + + /** + * Method to remove user from keycloak account on basis of userId . + * + * @param request + * @return + */ + String removeUser(Map request); + + /** + * This method will check email is verified by user or not. + * + * @param userId String + * @return boolean + */ + boolean isEmailVerified(String userId); + + /** + * Method to deactivate user from keycloak , it is like soft delete . + * + * @param request + * @return + */ + String deactivateUser(Map request); + + /** + * Method to activate user from keycloak , it is like soft delete . + * + * @param request + * @return + */ + String activateUser(Map request); + + /** + * This method will read user last login time from key claok. + * + * @param userId String + * @return String (as epoch value or null) + */ + String getLastLoginTime(String userId); + + /** + * This method will add user current login time to keycloak. + * + * @param userId String + * @return boolean + */ + boolean addUserLoginTime(String userId); + + /** + * this method will set emailVerified flag of keycloak as false. + * + * @param userId + */ + String setEmailVerifiedAsFalse(String userId); + + /** + * This method will set email verified flag on keycloak. + * + * @param userId String + * @param flag boolean (true/false) + */ + void setEmailVerifiedUpdatedFlag(String userId, String flag); + + /** + * This method will provide the user already set attribute under keycloak. + * + * @param userId String + * @return String + */ + String getEmailVerifiedUpdatedFlag(String userId); + + /** + * This method will do the data sync from cassandra db to keyclaok. + * + * @param request Map + * @return String + */ + String syncUserData(Map request); + + /** + * This method will do the user password update. + * + * @param userId String + * @param password String + * @return boolean true/false + */ + boolean doPasswordUpdate(String userId, String password); + + String setEmailVerifiedTrue(String userId); + + void setRequiredAction(String userId, String requiredAction); + + String getUsernameById(String userId); + /** + * This method will verify user access token and provide userId if token is valid. in case of + * invalid access token it will throw ProjectCommon exception with 401. + * + * @param token String JWT access token + * @param url token will be validated against this url + * @return String + */ + String verifyToken(String token, String url); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/SSOServiceFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/SSOServiceFactory.java new file mode 100644 index 0000000000..dfc12406d8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/SSOServiceFactory.java @@ -0,0 +1,22 @@ +package org.sunbird.services.sso; + +import org.sunbird.services.sso.impl.KeyCloakServiceImpl; + +/** @author Amit Kumar */ +public class SSOServiceFactory { + private static SSOManager ssoManager = null; + + private SSOServiceFactory() {} + + /** + * On call of this method , it will provide a new KeyCloakServiceImpl instance on each call. + * + * @return SSOManager + */ + public static SSOManager getInstance() { + if (null == ssoManager) { + ssoManager = new KeyCloakServiceImpl(); + } + return ssoManager; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/KeyCloakRsaKeyFetcher.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/KeyCloakRsaKeyFetcher.java new file mode 100644 index 0000000000..49cfc3f508 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/KeyCloakRsaKeyFetcher.java @@ -0,0 +1,133 @@ +package org.sunbird.services.sso.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.RSAPublicKeySpec; +import java.util.Base64; +import java.util.Base64.Decoder; +import java.util.HashMap; +import java.util.Map; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +/** Class to fetch SSO public key from Keycloak server using 'certs' HTTP API call. */ +public class KeyCloakRsaKeyFetcher { + private static final String MODULUS = "modulusBase64"; + private static final String EXPONENT = "exponentBase64"; + + /** + * This method will accept keycloak base URL and realm name. Based on provided values it will + * fetch public key from keycloak. + * + * @param url A string value having keycloak base URL + * @param realm Keycloak realm name + * @return Public key used to verify user access token. + */ + public PublicKey getPublicKeyFromKeyCloak(String url, String realm) { + try { + Map valueMap = null; + Decoder urlDecoder = Base64.getUrlDecoder(); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + String publicKeyString = requestKeyFromKeycloak(url, realm); + if (publicKeyString != null) { + valueMap = getValuesFromJson(publicKeyString); + if (valueMap != null) { + BigInteger modulus = new BigInteger(1, urlDecoder.decode(valueMap.get(MODULUS))); + BigInteger publicExponent = new BigInteger(1, urlDecoder.decode(valueMap.get(EXPONENT))); + PublicKey key = keyFactory.generatePublic(new RSAPublicKeySpec(modulus, publicExponent)); + saveToCache(key); + return key; + } + } + } catch (Exception e) { + ProjectLogger.log( + "KeyCloakRsaKeyFetcher:getPublicKeyFromKeyCloak: Exception occurred with message = " + + e.getMessage(), + LoggerEnum.ERROR); + } + return null; + } + + /** + * This method will save the public key string value to cache + * + * @param key Public key to save in cache + */ + private void saveToCache(PublicKey key) { + byte[] encodedPublicKey = key.getEncoded(); + String publicKey = Base64.getEncoder().encodeToString(encodedPublicKey); + PropertiesCache cache = PropertiesCache.getInstance(); + cache.saveConfigProperty(JsonKey.SSO_PUBLIC_KEY, publicKey); + } + + /** + * This method will connect to keycloak server using API call for getting public key. + * + * @param url A string value having keycloak base URL + * @param realm Keycloak realm name + * @return Public key JSON response string + */ + private String requestKeyFromKeycloak(String url, String realm) { + HttpClient client = HttpClientBuilder.create().build(); + HttpGet request = new HttpGet(url + "realms/" + realm + "/protocol/openid-connect/certs"); + + try { + HttpResponse response = client.execute(request); + HttpEntity entity = response.getEntity(); + + if (entity != null) { + return EntityUtils.toString(entity); + } else { + ProjectLogger.log( + "KeyCloakRsaKeyFetcher:requestKeyFromKeycloak: Not able to fetch SSO public key from keycloak server", + LoggerEnum.ERROR); + } + } catch (IOException e) { + ProjectLogger.log( + "KeyCloakRsaKeyFetcher:requestKeyFromKeycloak: Exception occurred with message = " + + e.getMessage(), + LoggerEnum.ERROR); + } + return null; + } + + /** + * This method will return a map containing values extracted from public key JSON string. + * + * @param response Public key JSON response string + */ + private Map getValuesFromJson(String response) { + ObjectMapper mapper = new ObjectMapper(); + Map values = new HashMap<>(); + try { + JsonNode res = mapper.readTree(response); + JsonNode keys = res.get("keys"); + if (keys != null) { + + JsonNode value = keys.get(0); + values.put(MODULUS, value.get("n").asText()); + values.put(EXPONENT, value.get("e").asText()); + } + } catch (Exception e) { + ProjectLogger.log( + "KeyCloakRsaKeyFetcher:getValuesFromJson: Exception occurred with message = " + + e.getMessage(), + LoggerEnum.ERROR); + return null; + } + + return values; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/KeyCloakServiceImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/KeyCloakServiceImpl.java new file mode 100644 index 0000000000..bf08b0980a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/KeyCloakServiceImpl.java @@ -0,0 +1,629 @@ +package org.sunbird.services.sso.impl; + +import static java.util.Arrays.asList; +import static org.sunbird.common.models.util.ProjectUtil.isNotNull; +import static org.sunbird.common.models.util.ProjectUtil.isNull; + +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.keycloak.RSATokenVerifier; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.UserRepresentation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.KeyCloakConnectionProvider; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.util.KeycloakRequiredActionLinkUtil; +import org.sunbird.services.sso.SSOManager; + +/** + * Single sign out service implementation with Key Cloak. + * + * @author Manzarul + */ +public class KeyCloakServiceImpl implements SSOManager { + + private Keycloak keycloak = KeyCloakConnectionProvider.getConnection(); + private static final String URL = + KeyCloakConnectionProvider.SSO_URL + + "realms/" + + KeyCloakConnectionProvider.SSO_REALM + + "/protocol/openid-connect/token"; + + private static PublicKey SSO_PUBLIC_KEY = null; + + public PublicKey getPublicKey() { + if (null == SSO_PUBLIC_KEY) { + SSO_PUBLIC_KEY = + new KeyCloakRsaKeyFetcher() + .getPublicKeyFromKeyCloak( + KeyCloakConnectionProvider.SSO_URL, KeyCloakConnectionProvider.SSO_REALM); + } + return SSO_PUBLIC_KEY; + } + + @Override + public String verifyToken(String accessToken) { + return verifyToken(accessToken, null); + } + + /** + * This method will generate Public key form keycloak realm publickey String + * + * @param publicKeyString String + * @return PublicKey + */ + private PublicKey toPublicKey(String publicKeyString) { + try { + byte[] publicBytes = Base64.getDecoder().decode(publicKeyString); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(keySpec); + } catch (Exception e) { + return null; + } + } + + @Override + public boolean updatePassword(String userId, String password) { + try { + String fedUserId = getFederatedUserId(userId); + UserResource ur = keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + CredentialRepresentation cr = new CredentialRepresentation(); + cr.setType(CredentialRepresentation.PASSWORD); + cr.setValue(password); + ur.resetPassword(cr); + return true; + } catch (Exception e) { + ProjectLogger.log( + "KeyCloakServiceImpl:updatePassword: Exception occurred with error message = " + e, + LoggerEnum.ERROR.name()); + } + return false; + } + + @Override + public String updateUser(Map request) { + String userId = (String) request.get(JsonKey.USER_ID); + String fedUserId = getFederatedUserId(userId); + UserRepresentation ur = null; + UserResource resource = null; + boolean needTobeUpdate = false; + try { + resource = keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + ur = resource.toRepresentation(); + } catch (Exception e) { + ProjectUtil.createAndThrowInvalidUserDataException(); + } + + // set the UserRepresantation with the map value... + if (isNotNull(request.get(JsonKey.FIRST_NAME))) { + needTobeUpdate = true; + ur.setFirstName((String) request.get(JsonKey.FIRST_NAME)); + } + if (isNotNull(request.get(JsonKey.LAST_NAME))) { + needTobeUpdate = true; + ur.setLastName((String) request.get(JsonKey.LAST_NAME)); + } + if (isNotNull(request.get(JsonKey.EMAIL))) { + needTobeUpdate = true; + ur.setEmail((String) request.get(JsonKey.EMAIL)); + ur.setEmailVerified(false); + + Map> map = ur.getAttributes(); + List list = new ArrayList<>(); + list.add("false"); + if (map == null) { + map = new HashMap<>(); + } + map.put(JsonKey.EMAIL_VERIFIED_UPDATED, list); + ur.setAttributes(map); + } + if (!StringUtils.isBlank((String) request.get(JsonKey.PHONE))) { + needTobeUpdate = true; + Map> map = ur.getAttributes(); + List list = new ArrayList<>(); + list.add((String) request.get(JsonKey.PHONE)); + if (map == null) { + map = new HashMap<>(); + } + map.put(JsonKey.PHONE, list); + ur.setAttributes(map); + } + + if (!StringUtils.isBlank((String) request.get(JsonKey.COUNTRY_CODE))) { + needTobeUpdate = true; + Map> map = ur.getAttributes(); + if (map == null) { + map = new HashMap<>(); + } + List list = new ArrayList<>(); + list.add(PropertiesCache.getInstance().getProperty("sunbird_default_country_code")); + if (!StringUtils.isBlank((String) request.get(JsonKey.COUNTRY_CODE))) { + list.add(0, (String) request.get(JsonKey.COUNTRY_CODE)); + } + map.put(JsonKey.COUNTRY_CODE, list); + ur.setAttributes(map); + } + + try { + // if user sending any basic profile data + // then no need to make api call to keycloak to update profile. + if (needTobeUpdate) { + resource.update(ur); + } + } catch (Exception ex) { + ProjectUtil.createAndThrowInvalidUserDataException(); + } + return JsonKey.SUCCESS; + } + + @Override + public String syncUserData(Map request) { + String userId = (String) request.get(JsonKey.USER_ID); + String fedUserId = getFederatedUserId(userId); + UserRepresentation ur = null; + UserResource resource = null; + boolean needTobeUpdate = false; + try { + resource = keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + ur = resource.toRepresentation(); + } catch (Exception e) { + ProjectUtil.createAndThrowInvalidUserDataException(); + } + + // set the UserRepresantation with the map value... + if (isNotNull(request.get(JsonKey.FIRST_NAME))) { + needTobeUpdate = true; + ur.setFirstName((String) request.get(JsonKey.FIRST_NAME)); + } + if (isNotNull(request.get(JsonKey.LAST_NAME))) { + needTobeUpdate = true; + ur.setLastName((String) request.get(JsonKey.LAST_NAME)); + } + + if (isNotNull(request.get(JsonKey.EMAIL))) { + needTobeUpdate = true; + ur.setEmail((String) request.get(JsonKey.EMAIL)); + } + ProjectLogger.log( + "check user email is verified or not ,resource.toRepresentation().isEmailVerified() :" + + resource.toRepresentation().isEmailVerified() + + " for userId :" + + userId); + if (!resource.toRepresentation().isEmailVerified()) { + needTobeUpdate = true; + Map> map = ur.getAttributes(); + List list = new ArrayList<>(); + list.add("false"); + if (map == null) { + map = new HashMap<>(); + } + map.put(JsonKey.EMAIL_VERIFIED_UPDATED, list); + ur.setAttributes(map); + } else { + needTobeUpdate = true; + Map> map = ur.getAttributes(); + List list = new ArrayList<>(); + list.add("true"); + if (map == null) { + map = new HashMap<>(); + } + map.put(JsonKey.EMAIL_VERIFIED_UPDATED, list); + ur.setAttributes(map); + } + + if (isNotNull(request.get(JsonKey.LOGIN_ID))) { + needTobeUpdate = true; + ur.setUsername((String) request.get(JsonKey.LOGIN_ID)); + } + if (!StringUtils.isBlank((String) request.get(JsonKey.PHONE))) { + needTobeUpdate = true; + Map> map = ur.getAttributes(); + List list = new ArrayList<>(); + list.add((String) request.get(JsonKey.PHONE)); + if (map == null) { + map = new HashMap<>(); + } + map.put(JsonKey.PHONE, list); + ur.setAttributes(map); + } + Map> map = ur.getAttributes(); + if (map == null) { + map = new HashMap<>(); + } + List list = new ArrayList<>(); + list.add(PropertiesCache.getInstance().getProperty("sunbird_default_country_code")); + map.put(JsonKey.COUNTRY_CODE, list); + if (!StringUtils.isBlank((String) request.get(JsonKey.COUNTRY_CODE))) { + needTobeUpdate = true; + list.add(0, (String) request.get(JsonKey.COUNTRY_CODE)); + map.put(JsonKey.COUNTRY_CODE, list); + } + ur.setAttributes(map); + try { + // if user sending any basic profile data + // then no need to make api call to keycloak to update profile. + if (needTobeUpdate) { + resource.update(ur); + } + } catch (Exception ex) { + ProjectUtil.createAndThrowInvalidUserDataException(); + } + return JsonKey.SUCCESS; + } + + /** + * Method to remove the user on basis of user id. + * + * @param request Map + * @return boolean true if success otherwise false . + */ + @Override + public String removeUser(Map request) { + Keycloak keycloak = KeyCloakConnectionProvider.getConnection(); + String userId = (String) request.get(JsonKey.USER_ID); + try { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + if (isNotNull(resource)) { + resource.remove(); + } + } catch (Exception ex) { + ProjectUtil.createAndThrowInvalidUserDataException(); + } + return JsonKey.SUCCESS; + } + + /** + * Method to deactivate the user on basis of user id. + * + * @param request Map + * @return boolean true if success otherwise false . + */ + @Override + public String deactivateUser(Map request) { + String userId = (String) request.get(JsonKey.USER_ID); + makeUserActiveOrInactive(userId, false); + return JsonKey.SUCCESS; + } + + /** + * Method to activate the user on basis of user id. + * + * @param request Map + * @return boolean true if success otherwise false . + */ + @Override + public String activateUser(Map request) { + String userId = (String) request.get(JsonKey.USER_ID); + makeUserActiveOrInactive(userId, true); + return JsonKey.SUCCESS; + } + + /** + * This method will take userid and boolean status to update user status + * + * @param userId String + * @param status boolean + * @throws ProjectCommonException + */ + private void makeUserActiveOrInactive(String userId, boolean status) { + try { + String fedUserId = getFederatedUserId(userId); + ProjectLogger.log( + "KeyCloakServiceImpl:makeUserActiveOrInactive: fedration id formed: " + fedUserId, + LoggerEnum.INFO.name()); + validateUserId(fedUserId); + Keycloak keycloak = KeyCloakConnectionProvider.getConnection(); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + UserRepresentation ur = resource.toRepresentation(); + ur.setEnabled(status); + if (isNotNull(resource)) { + resource.update(ur); + } + } catch (Exception e) { + ProjectLogger.log( + "KeyCloakServiceImpl:makeUserActiveOrInactive:error occurred while blocking user: " + e, + LoggerEnum.ERROR.name()); + ProjectUtil.createAndThrowInvalidUserDataException(); + } + } + + /** + * This method will check userId value, if value is null or empty then it will throw + * ProjectCommonException + * + * @param userId String + * @throws ProjectCommonException + */ + private void validateUserId(String userId) { + if (StringUtils.isBlank(userId)) { + ProjectUtil.createAndThrowInvalidUserDataException(); + } + } + + @Override + public boolean isEmailVerified(String userId) { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + if (isNull(resource)) { + return false; + } + return resource.toRepresentation().isEmailVerified(); + } + + @Override + public void setEmailVerifiedUpdatedFlag(String userId, String flag) { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + UserRepresentation user = resource.toRepresentation(); + Map> map = user.getAttributes(); + List list = new ArrayList<>(); + list.add(flag); + if (map == null) { + map = new HashMap<>(); + } + map.put(JsonKey.EMAIL_VERIFIED_UPDATED, list); + user.setAttributes(map); + resource.update(user); + } + + @Override + public String getEmailVerifiedUpdatedFlag(String userId) { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + UserRepresentation user = resource.toRepresentation(); + Map> map = user.getAttributes(); + List list = null; + if (MapUtils.isNotEmpty(map)) { + list = map.get(JsonKey.EMAIL_VERIFIED_UPDATED); + } + if (CollectionUtils.isNotEmpty(list)) { + return list.get(0); + } else { + return ""; + } + } + + /** + * This method will do the user password update. + * + * @param userId String + * @param password String + * @return boolean true/false + */ + @Override + public boolean doPasswordUpdate(String userId, String password) { + boolean response = false; + try { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + CredentialRepresentation newCredential = new CredentialRepresentation(); + newCredential.setValue(password); + newCredential.setType(CredentialRepresentation.PASSWORD); + newCredential.setTemporary(true); + resource.resetPassword(newCredential); + response = true; + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + return response; + } + + @Override + public String getLastLoginTime(String userId) { + String lastLoginTime = null; + try { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + UserRepresentation ur = resource.toRepresentation(); + Map> map = ur.getAttributes(); + if (map == null) { + map = new HashMap<>(); + } + List list = map.get(JsonKey.LAST_LOGIN_TIME); + if (list != null && !list.isEmpty()) { + lastLoginTime = list.get(0); + } + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return lastLoginTime; + } + + @Override + public boolean addUserLoginTime(String userId) { + boolean response = true; + try { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + UserRepresentation ur = resource.toRepresentation(); + Map> map = ur.getAttributes(); + List list = new ArrayList<>(); + if (map == null) { + map = new HashMap<>(); + } + List currentLogTime = map.get(JsonKey.CURRENT_LOGIN_TIME); + if (currentLogTime == null || currentLogTime.isEmpty()) { + currentLogTime = new ArrayList<>(); + currentLogTime.add(Long.toString(System.currentTimeMillis())); + } else { + list.add(currentLogTime.get(0)); + currentLogTime.clear(); + currentLogTime.add(0, Long.toString(System.currentTimeMillis())); + } + map.put(JsonKey.CURRENT_LOGIN_TIME, currentLogTime); + map.put(JsonKey.LAST_LOGIN_TIME, list); + ur.setAttributes(map); + resource.update(ur); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + response = false; + } + return response; + } + + private String getFederatedUserId(String userId) { + return String.join( + ":", + "f", + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_KEYCLOAK_USER_FEDERATION_PROVIDER_ID), + userId); + } + + @Override + public String setEmailVerifiedTrue(String userId) { + updateEmailVerifyStatus(userId, true); + return JsonKey.SUCCESS; + } + + @Override + public String setEmailVerifiedAsFalse(String userId) { + updateEmailVerifyStatus(userId, false); + return JsonKey.SUCCESS; + } + + /** + * This method will update user email verified status + * + * @param userId String + * @param status boolean + * @throws ProjectCommonException + */ + private void updateEmailVerifyStatus(String userId, boolean status) { + try { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + UserRepresentation ur = resource.toRepresentation(); + ur.setEmailVerified(status); + if (isNotNull(resource)) { + resource.update(ur); + } + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + ProjectUtil.createAndThrowInvalidUserDataException(); + } + } + + @Override + public void setRequiredAction(String userId, String requiredAction) { + String fedUserId = getFederatedUserId(userId); + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + + UserRepresentation userRepresentation = resource.toRepresentation(); + userRepresentation.setRequiredActions(asList(requiredAction)); + if (KeycloakRequiredActionLinkUtil.VERIFY_EMAIL.equalsIgnoreCase(requiredAction)) { + userRepresentation.setEmailVerified(false); + } + resource.update(userRepresentation); + } + + @Override + public String getUsernameById(String userId) { + String fedUserId = getFederatedUserId(userId); + try { + UserResource resource = + keycloak.realm(KeyCloakConnectionProvider.SSO_REALM).users().get(fedUserId); + UserRepresentation ur = resource.toRepresentation(); + return ur.getUsername(); + } catch (Exception e) { + ProjectLogger.log( + "KeyCloakServiceImpl:getUsernameById: User not found for userId = " + + userId + + " error message = " + + e.getMessage(), + e); + } + ProjectLogger.log( + "KeyCloakServiceImpl:getUsernameById: User not found for userId = " + userId, + LoggerEnum.INFO.name()); + return ""; + } + + @Override + public String verifyToken(String accessToken, String url) { + + try { + PublicKey publicKey = getPublicKey(); + if (publicKey == null) { + ProjectLogger.log( + "KeyCloakServiceImpl: SSO_PUBLIC_KEY is NULL. Keycloak server may need to be started. Read value from environment variable.", + LoggerEnum.INFO); + publicKey = toPublicKey(System.getenv(JsonKey.SSO_PUBLIC_KEY)); + } + if (publicKey != null) { + String ssoUrl = (url != null ? url : KeyCloakConnectionProvider.SSO_URL); + AccessToken token = + RSATokenVerifier.verifyToken( + accessToken, + publicKey, + ssoUrl + "realms/" + KeyCloakConnectionProvider.SSO_REALM, + true, + true); + ProjectLogger.log( + token.getId() + + " " + + token.issuedFor + + " " + + token.getProfile() + + " " + + token.getSubject() + + " Active: " + + token.isActive() + + " isExpired: " + + token.isExpired() + + " " + + token.issuedNow().getExpiration(), + LoggerEnum.INFO.name()); + String tokenSubject = token.getSubject(); + if (StringUtils.isNotBlank(tokenSubject)) { + int pos = tokenSubject.lastIndexOf(":"); + return tokenSubject.substring(pos + 1); + } + return token.getSubject(); + } else { + ProjectLogger.log( + "KeyCloakServiceImpl:verifyToken: SSO_PUBLIC_KEY is NULL.", LoggerEnum.ERROR); + throw new ProjectCommonException( + ResponseCode.keyCloakDefaultError.getErrorCode(), + ResponseCode.keyCloakDefaultError.getErrorMessage(), + ResponseCode.keyCloakDefaultError.getResponseCode()); + } + } catch (Exception e) { + ProjectLogger.log( + "KeyCloakServiceImpl:verifyToken: Exception occurred with message = " + e.getMessage(), + LoggerEnum.ERROR); + throw new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ResponseCode.unAuthorized.getErrorMessage(), + ResponseCode.UNAUTHORIZED.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/package-info.java new file mode 100644 index 0000000000..af2698a92c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/impl/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.services.sso.impl; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/package-info.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/package-info.java new file mode 100644 index 0000000000..47a89ebb87 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/services/sso/package-info.java @@ -0,0 +1,3 @@ +/** */ +/** @author Manzarul */ +package org.sunbird.services.sso; diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryAssemblerFactory.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryAssemblerFactory.java new file mode 100644 index 0000000000..86d4e89880 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryAssemblerFactory.java @@ -0,0 +1,18 @@ +package org.sunbird.telemetry.collector; + +/** Created by arvind on 16/1/18. */ +public class TelemetryAssemblerFactory { + + private static TelemetryDataAssembler telemetryDataAssembler = null; + + public static TelemetryDataAssembler get() { + if (telemetryDataAssembler == null) { + synchronized (TelemetryAssemblerFactory.class) { + if (telemetryDataAssembler == null) { + telemetryDataAssembler = new TelemetryDataAssemblerImpl(); + } + } + } + return telemetryDataAssembler; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryDataAssembler.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryDataAssembler.java new file mode 100644 index 0000000000..748b3315b8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryDataAssembler.java @@ -0,0 +1,15 @@ +package org.sunbird.telemetry.collector; + +import java.util.Map; + +/** Created by arvind on 16/1/18. */ +public interface TelemetryDataAssembler { + + public String audit(Map context, Map params); + + public String search(Map context, Map params); + + public String log(Map context, Map params); + + public String error(Map context, Map params); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryDataAssemblerImpl.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryDataAssemblerImpl.java new file mode 100644 index 0000000000..7047c3849a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/collector/TelemetryDataAssemblerImpl.java @@ -0,0 +1,28 @@ +package org.sunbird.telemetry.collector; + +import java.util.Map; +import org.sunbird.telemetry.util.TelemetryGenerator; + +/** Created by arvind on 5/1/18. */ +public class TelemetryDataAssemblerImpl implements TelemetryDataAssembler { + + @Override + public String audit(Map context, Map params) { + return TelemetryGenerator.audit(context, params); + } + + @Override + public String search(Map context, Map params) { + return TelemetryGenerator.search(context, params); + } + + @Override + public String log(Map context, Map params) { + return TelemetryGenerator.log(context, params); + } + + @Override + public String error(Map context, Map params) { + return TelemetryGenerator.error(context, params); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Actor.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Actor.java new file mode 100644 index 0000000000..c69b605b11 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Actor.java @@ -0,0 +1,35 @@ +package org.sunbird.telemetry.dto; + +public class Actor { + + private String id; + private String type; + + public Actor() {} + + public Actor(String id, String type) { + super(); + this.id = id; + this.type = type; + } + + /** @return the id */ + public String getId() { + return id; + } + + /** @param id the id to set */ + public void setId(String id) { + this.id = id; + } + + /** @return the type */ + public String getType() { + return type; + } + + /** @param type the type to set */ + public void setType(String type) { + this.type = type; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Context.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Context.java new file mode 100644 index 0000000000..9ba76facaa --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Context.java @@ -0,0 +1,85 @@ +/** */ +package org.sunbird.telemetry.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@JsonInclude(Include.NON_NULL) +public class Context { + + private String channel; + private Producer pdata; + private String env; + private String did; + private List> cdata = new ArrayList<>(); + private Map rollup = new HashMap<>(); + + public Context() {} + + public Context(String channel, String env, Producer pdata) { + super(); + this.channel = channel; + this.env = env; + this.pdata = pdata; + } + + public Map getRollup() { + return rollup; + } + + public void setRollup(Map rollup) { + this.rollup = rollup; + } + + public List> getCdata() { + return cdata; + } + + public void setCdata(List> cdata) { + this.cdata = cdata; + } + + /** @return the channel */ + public String getChannel() { + return channel; + } + + /** @param channel the channel to set */ + public void setChannel(String channel) { + this.channel = channel; + } + + /** @return the pdata */ + public Producer getPdata() { + return pdata; + } + + /** @param pdata the pdata to set */ + public void setPdata(Producer pdata) { + this.pdata = pdata; + } + + /** @return the env */ + public String getEnv() { + return env; + } + + /** @param env the env to set */ + public void setEnv(String env) { + this.env = env; + } + + /** @return the did */ + public String getDid() { + return did; + } + + /** @param did the did to set */ + public void setDid(String did) { + this.did = did; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Producer.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Producer.java new file mode 100644 index 0000000000..be56b1e05b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Producer.java @@ -0,0 +1,56 @@ +package org.sunbird.telemetry.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +@JsonInclude(Include.NON_NULL) +public class Producer { + + private String id; + private String pid; + private String ver; + + public Producer() {} + + public Producer(String id, String ver) { + super(); + this.id = id; + this.ver = ver; + } + + public Producer(String id, String pid, String ver) { + this.id = id; + this.pid = pid; + this.ver = ver; + } + + /** @return the id */ + public String getId() { + return id; + } + + /** @param id the id to set */ + public void setId(String id) { + this.id = id; + } + + /** @return the pid */ + public String getPid() { + return pid; + } + + /** @param pid the pid to set */ + public void setPid(String pid) { + this.pid = pid; + } + + /** @return the ver */ + public String getVer() { + return ver; + } + + /** @param ver the ver to set */ + public void setVer(String ver) { + this.ver = ver; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Target.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Target.java new file mode 100644 index 0000000000..071311494b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Target.java @@ -0,0 +1,60 @@ +package org.sunbird.telemetry.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import java.util.Map; + +@JsonInclude(Include.NON_NULL) +public class Target { + + private String id; + private String type; + private String ver; + private Map rollup; + + public Target() {} + + public Target(String id, String type) { + super(); + this.id = id; + this.type = type; + } + + public Map getRollup() { + return rollup; + } + + public void setRollup(Map rollup) { + this.rollup = rollup; + } + + /** @return the id */ + public String getId() { + return id; + } + + /** @param id the id to set */ + public void setId(String id) { + this.id = id; + } + + /** @return the type */ + public String getType() { + return type; + } + + /** @param type the type to set */ + public void setType(String type) { + this.type = type; + } + + /** @return the ver */ + public String getVer() { + return ver; + } + + /** @param ver the ver to set */ + public void setVer(String ver) { + this.ver = ver; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Telemetry.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Telemetry.java new file mode 100644 index 0000000000..d468b92ae9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/Telemetry.java @@ -0,0 +1,132 @@ +package org.sunbird.telemetry.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** Telemetry V3 POJO to generate telemetry event. */ +@JsonInclude(Include.NON_NULL) +public class Telemetry { + + private String eid; + private long ets = System.currentTimeMillis(); + private String ver = "3.0"; + private String mid = System.currentTimeMillis() + "." + UUID.randomUUID(); + private Actor actor; + private Context context; + private Target object; + private Map edata; + private List tags; + + public Telemetry() {} + + public Telemetry( + String eid, Actor actor, Context context, Map edata, Target object) { + super(); + this.eid = eid; + this.actor = actor; + this.context = context; + this.edata = edata; + this.object = object; + } + + public Telemetry(String eid, Actor actor, Context context, Map edata) { + super(); + this.eid = eid; + this.actor = actor; + this.context = context; + this.edata = edata; + } + + /** @return the eid */ + public String getEid() { + return eid; + } + + /** @param eid the eid to set */ + public void setEid(String eid) { + this.eid = eid; + } + + /** @return the ets */ + public long getEts() { + return ets; + } + + /** @param ets the ets to set */ + public void setEts(long ets) { + this.ets = ets; + } + + /** @return the ver */ + public String getVer() { + return ver; + } + + /** @param ver the ver to set */ + public void setVer(String ver) { + this.ver = ver; + } + + /** @return the mid */ + public String getMid() { + return mid; + } + + /** @param mid the mid to set */ + public void setMid(String mid) { + this.mid = mid; + } + + /** @return the actor */ + public Actor getActor() { + return actor; + } + + /** @param actor the actor to set */ + public void setActor(Actor actor) { + this.actor = actor; + } + + /** @return the context */ + public Context getContext() { + return context; + } + + /** @param context the context to set */ + public void setContext(Context context) { + this.context = context; + } + + /** @return the object */ + public Target getObject() { + return object; + } + + /** @param object the object to set */ + public void setObject(Target object) { + this.object = object; + } + + /** @return the edata */ + public Map getEdata() { + return edata; + } + + /** @param edata the edata to set */ + public void setEdata(Map edata) { + this.edata = edata; + } + + /** @return the tags */ + public List getTags() { + return tags; + } + + /** @param tags the tags to set */ + public void setTags(List tags) { + this.tags = tags; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/TelemetryBEEvent.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/TelemetryBEEvent.java new file mode 100644 index 0000000000..c82a585945 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/TelemetryBEEvent.java @@ -0,0 +1,125 @@ +package org.sunbird.telemetry.dto; + +import java.util.HashMap; +import java.util.Map; + +public class TelemetryBEEvent { + + private String eid; + private long ets; + private String mid; + private String ver; + private String channel; + private Map pdata; + private Map edata; + + public String getEid() { + return eid; + } + + public void setEid(String eid) { + this.eid = eid; + } + + public long getEts() { + return ets; + } + + public void setEts(long ets) { + this.ets = ets; + } + + public String getVer() { + return ver; + } + + public void setVer(String ver) { + this.ver = ver; + } + + public Map getPdata() { + return pdata; + } + + public void setPdata(Map pdata) { + this.pdata = pdata; + } + + public Map getEdata() { + return edata; + } + + public void setEdata(Map eks) { + this.edata = new HashMap<>(); + edata.put("eks", eks); + } + + public void setPdata(String id, String pid, String ver, String uid) { + this.pdata = new HashMap<>(); + this.pdata.put("id", id); + this.pdata.put("pid", pid); + this.pdata.put("ver", ver); + } + + public void setEdata( + String cid, + Object status, + Object prevState, + Object size, + Object pkgVersion, + Object concepts) { + this.edata = new HashMap<>(); + Map eks = new HashMap<>(); + eks.put("cid", cid); + eks.put("state", status); + eks.put("prevstate", prevState); + eks.put("size", size); + eks.put("pkgVersion", pkgVersion); + eks.put("concepts", concepts); + edata.put("eks", eks); + } + + public void setEdata(String query, Object filters, Object sort, String correlationId, int size) { + this.edata = new HashMap<>(); + Map eks = new HashMap<>(); + eks.put("query", query); + eks.put("filters", filters); + eks.put("sort", sort); + eks.put("correlationid", correlationId); + eks.put("size", size); + edata.put("eks", eks); + } + + public void setEdata(String id, Object state, Object prevState, Object lemma) { + this.edata = new HashMap<>(); + Map eks = new HashMap<>(); + eks.put("id", id); + eks.put("state", state); + eks.put("prevstate", prevState); + eks.put("lemma", lemma); + edata.put("eks", eks); + } + + public String getMid() { + return mid; + } + + public void setMid(String mid) { + this.mid = mid; + } + + public String getChannel() { + if (null == channel) { + channel = ""; + } + return channel; + } + + public void setChannel(String channel) { + String tempChannel = channel; + if (null == channel) { + tempChannel = ""; + } + this.channel = tempChannel; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/TelemetryBJREvent.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/TelemetryBJREvent.java new file mode 100644 index 0000000000..a94a365d3a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/dto/TelemetryBJREvent.java @@ -0,0 +1,70 @@ +package org.sunbird.telemetry.dto; + +import java.util.Map; + +public class TelemetryBJREvent { + + private String eid; + private long ets; + private String mid; + private Map actor; + private Map context; + private Map object; + private Map edata; + + public String getEid() { + return eid; + } + + public void setEid(String eid) { + this.eid = eid; + } + + public long getEts() { + return ets; + } + + public void setEts(long ets) { + this.ets = ets; + } + + public String getMid() { + return mid; + } + + public void setMid(String mid) { + this.mid = mid; + } + + public Map getActor() { + return actor; + } + + public void setActor(Map actor) { + this.actor = actor; + } + + public Map getContext() { + return context; + } + + public void setContext(Map context) { + this.context = context; + } + + public Map getObject() { + return object; + } + + public void setObject(Map object) { + this.object = object; + } + + public Map getEdata() { + return edata; + } + + public void setEdata(Map edata) { + this.edata = edata; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryConstant.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryConstant.java new file mode 100644 index 0000000000..b4394cc25a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryConstant.java @@ -0,0 +1,11 @@ +package org.sunbird.telemetry.util; + +/** + * Class contains Constants for telemetry. + * + * @author arvind. + */ +public class TelemetryConstant { + + public static final String LOG_LEVEL_ERROR = "error"; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryEvents.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryEvents.java new file mode 100644 index 0000000000..76d8b61147 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryEvents.java @@ -0,0 +1,22 @@ +package org.sunbird.telemetry.util; + +/** + * enum for telemetry events + * + * @author arvind. + */ +public enum TelemetryEvents { + AUDIT("AUDIT"), + SEARCH("SEARCH"), + LOG("LOG"), + ERROR("ERROR"); + private String name; + + TelemetryEvents(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryGenerator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryGenerator.java new file mode 100644 index 0000000000..f298e4a61a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryGenerator.java @@ -0,0 +1,364 @@ +package org.sunbird.telemetry.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.telemetry.dto.Actor; +import org.sunbird.telemetry.dto.Context; +import org.sunbird.telemetry.dto.Producer; +import org.sunbird.telemetry.dto.Target; +import org.sunbird.telemetry.dto.Telemetry; + +/** + * class to transform the request data to telemetry events + * + * @author Arvind + */ +public class TelemetryGenerator { + + private static ObjectMapper mapper = new ObjectMapper(); + + private TelemetryGenerator() {} + + /** + * To generate api_access LOG telemetry JSON string. + * + * @param context Map contains the telemetry context info like actor info, env info etc. + * @param params Map contains the telemetry event data info + * @return Telemetry event + */ + public static String audit(Map context, Map params) { + if (!validateRequest(context, params)) { + return ""; + } + String actorId = (String) context.get(JsonKey.ACTOR_ID); + String actorType = (String) context.get(JsonKey.ACTOR_TYPE); + Actor actor = new Actor(actorId, StringUtils.capitalize(actorType)); + Target targetObject = + generateTargetObject((Map) params.get(JsonKey.TARGET_OBJECT)); + Context eventContext = getContext(context); + // assign cdata into context from params correlated objects... + if (params.containsKey(JsonKey.CORRELATED_OBJECTS)) { + setCorrelatedDataToContext(params.get(JsonKey.CORRELATED_OBJECTS), eventContext); + } + + // assign request id into context cdata ... + String reqId = (String) context.get(JsonKey.REQUEST_ID); + if (!StringUtils.isBlank(reqId)) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, reqId); + map.put(JsonKey.TYPE, TelemetryEnvKey.REQUEST_UPPER_CAMEL); + eventContext.getCdata().add(map); + } + + Map edata = generateAuditEdata(params); + + Telemetry telemetry = + new Telemetry(TelemetryEvents.AUDIT.getName(), actor, eventContext, edata, targetObject); + telemetry.setMid(reqId); + return getTelemetry(telemetry); + } + + private static void setCorrelatedDataToContext(Object correlatedObjects, Context eventContext) { + ArrayList> list = (ArrayList>) correlatedObjects; + ArrayList> targetList = new ArrayList<>(); + if (null != list && !list.isEmpty()) { + for (Map m : list) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, m.get(JsonKey.ID)); + map.put(JsonKey.TYPE, StringUtils.capitalize((String) m.get(JsonKey.TYPE))); + targetList.add(map); + } + } + eventContext.setCdata(targetList); + } + + private static Target generateTargetObject(Map targetObject) { + + Target target = + new Target( + (String) targetObject.get(JsonKey.ID), + StringUtils.capitalize((String) targetObject.get(JsonKey.TYPE))); + if (targetObject.get(JsonKey.ROLLUP) != null) { + target.setRollup((Map) targetObject.get(JsonKey.ROLLUP)); + } + return target; + } + + private static Map generateAuditEdata(Map params) { + + Map edata = new HashMap<>(); + Map props = (Map) params.get(JsonKey.PROPS); + // TODO: need to rethink about this one .. if map is null then what to do + if (null != props) { + edata.put(JsonKey.PROPS, getProps(props)); + } + + Map target = (Map) params.get(JsonKey.TARGET_OBJECT); + if (target.get(JsonKey.CURRENT_STATE) != null) { + edata.put(JsonKey.STATE, StringUtils.capitalize((String) target.get(JsonKey.CURRENT_STATE))); + if (JsonKey.UPDATE.equalsIgnoreCase((String) target.get(JsonKey.CURRENT_STATE)) + && edata.get(props) != null) { + removeAttributes((Map) edata.get(props), JsonKey.ID); + } + } + return edata; + } + + private static void removeAttributes(Map map, String... properties) { + for (String property : properties) { + map.remove(property); + } + } + + private static List getProps(Map map) { + try { + return map.entrySet() + .stream() + .map(entry -> entry.getKey()) + .map( + key -> { + if (map.get(key) instanceof Map) { + List keys = getProps((Map) map.get(key)); + return keys.stream() + .map(childKey -> key + "." + childKey) + .collect(Collectors.toList()); + } else { + return Arrays.asList(key); + } + }) + .flatMap(List::stream) + .collect(Collectors.toList()); + } catch (Exception e) { + ProjectLogger.log("TelemetryGenerator:getProps error =" + e, LoggerEnum.ERROR.name()); + } + return new ArrayList<>(); + } + + private static Context getContext(Map context) { + String channel = (String) context.get(JsonKey.CHANNEL); + String env = (String) context.get(JsonKey.ENV); + String did = (String) context.get(JsonKey.DEVICE_ID); + Producer producer = getProducer(context); + Context eventContext = new Context(channel, StringUtils.capitalize(env), producer); + eventContext.setDid(did); + if (context.get(JsonKey.ROLLUP) != null + && !((Map) context.get(JsonKey.ROLLUP)).isEmpty()) { + eventContext.setRollup((Map) context.get(JsonKey.ROLLUP)); + } + return eventContext; + } + + private static Producer getProducer(Map context) { + String id = ""; + if (context != null && context.size() != 0) { + if (StringUtils.isNotBlank((String) context.get(JsonKey.APP_ID))) { + id = (String) context.get(JsonKey.APP_ID); + } else { + id = (String) context.get(JsonKey.PDATA_ID); + } + String pid = (String) context.get(JsonKey.PDATA_PID); + String ver = (String) context.get(JsonKey.PDATA_VERSION); + return new Producer(id, pid, ver); + } else { + return new Producer("", "", ""); + } + } + + private static String getTelemetry(Telemetry telemetry) { + String event = ""; + try { + event = mapper.writeValueAsString(telemetry); + ProjectLogger.log( + "TelemetryGenerator:getTelemetry = Telemetry Event : " + event, LoggerEnum.DEBUG.name()); + } catch (Exception e) { + ProjectLogger.log( + "TelemetryGenerator:getTelemetry = Telemetry Event: failed to generate audit events:" + e, + LoggerEnum.ERROR.name()); + } + return event; + } + + /** + * Method to generate the search type telemetry event. + * + * @param context Map contains the telemetry context info like actor info, env info etc. + * @param params Map contains the telemetry event data info + * @return Search Telemetry event + */ + public static String search(Map context, Map params) { + + if (!validateRequest(context, params)) { + return ""; + } + String actorId = (String) context.get(JsonKey.ACTOR_ID); + String actorType = (String) context.get(JsonKey.ACTOR_TYPE); + Actor actor = new Actor(actorId, StringUtils.capitalize(actorType)); + + Context eventContext = getContext(context); + + String reqId = (String) context.get(JsonKey.REQUEST_ID); + if (!StringUtils.isBlank(reqId)) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, reqId); + map.put(JsonKey.TYPE, TelemetryEnvKey.REQUEST_UPPER_CAMEL); + eventContext.getCdata().add(map); + } + Map edata = generateSearchEdata(params); + Telemetry telemetry = + new Telemetry(TelemetryEvents.SEARCH.getName(), actor, eventContext, edata); + telemetry.setMid(reqId); + return getTelemetry(telemetry); + } + + private static Map generateSearchEdata(Map params) { + + Map edata = new HashMap<>(); + String type = (String) params.get(JsonKey.TYPE); + String query = (String) params.get(JsonKey.QUERY); + Map filters = (Map) params.get(JsonKey.FILTERS); + Map sort = (Map) params.get(JsonKey.SORT); + List topn = (List) params.get(JsonKey.TOPN); + + edata.put(JsonKey.TYPE, StringUtils.capitalize(type)); + if (null == query) { + query = ""; + } + edata.put(JsonKey.QUERY, query); + edata.put(JsonKey.FILTERS, filters); + edata.put(JsonKey.SORT, sort); + edata.put(JsonKey.SIZE, params.get(JsonKey.SIZE)); + edata.put(JsonKey.TOPN, topn); + return edata; + } + + /** + * Method to generate the log type telemetry event. + * + * @param context Map contains the telemetry context info like actor info, env info etc. + * @param params Map contains the telemetry event data info + * @return Search Telemetry event + */ + public static String log(Map context, Map params) { + + if (!validateRequest(context, params)) { + return ""; + } + String actorId = (String) context.get(JsonKey.ACTOR_ID); + String actorType = (String) context.get(JsonKey.ACTOR_TYPE); + Actor actor = new Actor(actorId, StringUtils.capitalize(actorType)); + + Context eventContext = getContext(context); + + // assign request id into context cdata ... + String reqId = (String) context.get(JsonKey.REQUEST_ID); + if (!StringUtils.isBlank(reqId)) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, reqId); + map.put(JsonKey.TYPE, TelemetryEnvKey.REQUEST_UPPER_CAMEL); + eventContext.getCdata().add(map); + } + + Map edata = generateLogEdata(params); + Telemetry telemetry = new Telemetry(TelemetryEvents.LOG.getName(), actor, eventContext, edata); + telemetry.setMid(reqId); + return getTelemetry(telemetry); + } + + private static Map generateLogEdata(Map params) { + + Map edata = new HashMap<>(); + String logType = (String) params.get(JsonKey.LOG_TYPE); + String logLevel = (String) params.get(JsonKey.LOG_LEVEL); + String message = (String) params.get(JsonKey.MESSAGE); + + edata.put(JsonKey.TYPE, StringUtils.capitalize(logType)); + edata.put(JsonKey.LEVEL, logLevel); + edata.put(JsonKey.MESSAGE, message != null ? message : ""); + + edata.put( + JsonKey.PARAMS, + getParamsList(params, Arrays.asList(JsonKey.LOG_TYPE, JsonKey.LOG_LEVEL, JsonKey.MESSAGE))); + return edata; + } + + private static List> getParamsList( + Map params, List ignore) { + List> paramsList = new ArrayList>(); + if (null != params && !params.isEmpty()) { + for (Entry entry : params.entrySet()) { + if (!ignore.contains(entry.getKey())) { + Map param = new HashMap(); + param.put(entry.getKey(), entry.getValue()); + paramsList.add(param); + } + } + } + return paramsList; + } + + /** + * Method to generate the error type telemetry event. + * + * @param context Map contains the telemetry context info like actor info, env info etc. + * @param params Map contains the error event data info + * @return Search Telemetry event + */ + public static String error(Map context, Map params) { + + if (!validateRequest(context, params)) { + return ""; + } + String actorId = (String) context.get(JsonKey.ACTOR_ID); + String actorType = (String) context.get(JsonKey.ACTOR_TYPE); + Actor actor = new Actor(actorId, StringUtils.capitalize(actorType)); + + Context eventContext = getContext(context); + + // assign request id into context cdata ... + String reqId = (String) context.get(JsonKey.REQUEST_ID); + if (!StringUtils.isBlank(reqId)) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, reqId); + map.put(JsonKey.TYPE, TelemetryEnvKey.REQUEST_UPPER_CAMEL); + eventContext.getCdata().add(map); + } + + Map edata = generateErrorEdata(params); + Telemetry telemetry = + new Telemetry(TelemetryEvents.ERROR.getName(), actor, eventContext, edata); + telemetry.setMid(reqId); + return getTelemetry(telemetry); + } + + private static Map generateErrorEdata(Map params) { + Map edata = new HashMap<>(); + String error = (String) params.get(JsonKey.ERROR); + String errorType = (String) params.get(JsonKey.ERR_TYPE); + String stackTrace = (String) params.get(JsonKey.STACKTRACE); + edata.put(JsonKey.ERROR, error); + edata.put(JsonKey.ERR_TYPE, errorType); + edata.put(JsonKey.STACKTRACE, ProjectUtil.getFirstNCharacterString(stackTrace, 100)); + return edata; + } + + private static boolean validateRequest(Map context, Map params) { + + boolean flag = true; + if (null == context || context.isEmpty() || params == null || params.isEmpty()) { + flag = false; + } + return flag; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryParams.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryParams.java new file mode 100644 index 0000000000..82df24f791 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryParams.java @@ -0,0 +1,7 @@ +package org.sunbird.telemetry.util; + +public enum TelemetryParams { + CHANNEL, + ENV, + ACTOR; +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryUtil.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryUtil.java new file mode 100644 index 0000000000..be787f58d8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryUtil.java @@ -0,0 +1,75 @@ +package org.sunbird.telemetry.util; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; + +/** @author arvind */ +public final class TelemetryUtil { + + private TelemetryUtil() {} + + public static Map generateTargetObject( + String id, String type, String currentState, String prevState) { + + Map target = new HashMap<>(); + target.put(JsonKey.ID, id); + target.put(JsonKey.TYPE, StringUtils.capitalize(type)); + target.put(JsonKey.CURRENT_STATE, currentState); + target.put(JsonKey.PREV_STATE, prevState); + return target; + } + + public static Map genarateTelemetryRequest( + Map targetObject, + List> correlatedObject, + String eventType, + Map params, + Map context) { + + Map map = new HashMap<>(); + map.put(JsonKey.TARGET_OBJECT, targetObject); + map.put(JsonKey.CORRELATED_OBJECTS, correlatedObject); + map.put(JsonKey.TELEMETRY_EVENT_TYPE, eventType); + map.put(JsonKey.PARAMS, params); + map.put(JsonKey.CONTEXT, context); + return map; + } + + public static void generateCorrelatedObject( + String id, String type, String corelation, List> correlationList) { + + Map correlatedObject = new HashMap<>(); + correlatedObject.put(JsonKey.ID, id); + correlatedObject.put(JsonKey.TYPE, StringUtils.capitalize(type)); + correlatedObject.put(JsonKey.RELATION, corelation); + + correlationList.add(correlatedObject); + } + + public static void addTargetObjectRollUp( + Map rollUpMap, Map targetObject) { + targetObject.put(JsonKey.ROLLUP, rollUpMap); + } + + public static void telemetryProcessingCall( + Map request, + Map targetObject, + List> correlatedObject, + Map context) { + Map params = new HashMap<>(); + params.put(JsonKey.PROPS, request); + Request req = new Request(); + req.setRequest( + TelemetryUtil.genarateTelemetryRequest( + targetObject, correlatedObject, TelemetryEvents.AUDIT.getName(), params, context)); + generateTelemetry(req); + } + + private static void generateTelemetry(Request request) { + TelemetryWriter.write(request); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryWriter.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryWriter.java new file mode 100644 index 0000000000..24b9e6dfc6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/util/TelemetryWriter.java @@ -0,0 +1,106 @@ +package org.sunbird.telemetry.util; + +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.telemetry.collector.TelemetryAssemblerFactory; +import org.sunbird.telemetry.collector.TelemetryDataAssembler; +import org.sunbird.telemetry.validator.TelemetryObjectValidator; +import org.sunbird.telemetry.validator.TelemetryObjectValidatorV3; + +public class TelemetryWriter { + + private static TelemetryDataAssembler telemetryDataAssembler = TelemetryAssemblerFactory.get(); + private static TelemetryObjectValidator telemetryObjectValidator = + new TelemetryObjectValidatorV3(); + private static Logger telemetryEventLogger = LoggerFactory.getLogger("TelemetryEventLogger"); + + public static void write(Request request) { + try { + String eventType = (String) request.getRequest().get(JsonKey.TELEMETRY_EVENT_TYPE); + + if (TelemetryEvents.AUDIT.getName().equalsIgnoreCase(eventType)) { + processAuditEvent(request); + } else if (TelemetryEvents.SEARCH.getName().equalsIgnoreCase(eventType)) { + processSearchEvent(request); + } else if (TelemetryEvents.ERROR.getName().equalsIgnoreCase(eventType)) { + processErrorEvent(request); + } else if (TelemetryEvents.LOG.getName().equalsIgnoreCase(eventType)) { + processLogEvent(request); + } + } catch (Exception ex) { + ProjectLogger.log( + "TelemetryWriter:write: Exception occurred while writting telemetry: " + + " exception = " + + ex, + LoggerEnum.ERROR.name()); + } + } + + private static void processLogEvent(Request request) { + Map context = (Map) request.getRequest().get(JsonKey.CONTEXT); + Map params = (Map) request.getRequest().get(JsonKey.PARAMS); + String telemetry = telemetryDataAssembler.log(context, params); + if (StringUtils.isNotBlank(telemetry) && telemetryObjectValidator.validateLog(telemetry)) { + telemetryEventLogger.info(telemetry); + } else { + ProjectLogger.log( + "TelemetryWriter:processLogEvent: Audit Telemetry validation failed: ", + telemetry, + LoggerEnum.ERROR.name()); + } + } + + private static void processErrorEvent(Request request) { + Map context = (Map) request.get(JsonKey.CONTEXT); + Map params = (Map) request.get(JsonKey.PARAMS); + String telemetry = telemetryDataAssembler.error(context, params); + if (StringUtils.isNotBlank(telemetry) && telemetryObjectValidator.validateError(telemetry)) { + telemetryEventLogger.info(telemetry); + } else { + ProjectLogger.log( + "TelemetryWriter:processLogEvent: Error Telemetry validation failed: ", + telemetry, + LoggerEnum.ERROR.name()); + } + } + + private static void processSearchEvent(Request request) { + Map context = (Map) request.get(JsonKey.CONTEXT); + Map params = (Map) request.get(JsonKey.PARAMS); + String telemetry = telemetryDataAssembler.search(context, params); + if (StringUtils.isNotBlank(telemetry) && telemetryObjectValidator.validateSearch(telemetry)) { + telemetryEventLogger.info(telemetry); + } else { + ProjectLogger.log( + "TelemetryWriter:processLogEvent: Search Telemetry validation failed: ", + telemetry, + LoggerEnum.ERROR.name()); + } + } + + private static void processAuditEvent(Request request) { + Map context = (Map) request.get(JsonKey.CONTEXT); + Map targetObject = (Map) request.get(JsonKey.TARGET_OBJECT); + List> correlatedObjects = + (List>) request.get(JsonKey.CORRELATED_OBJECTS); + Map params = (Map) request.get(JsonKey.PARAMS); + params.put(JsonKey.TARGET_OBJECT, targetObject); + params.put(JsonKey.CORRELATED_OBJECTS, correlatedObjects); + String telemetry = telemetryDataAssembler.audit(context, params); + if (StringUtils.isNotBlank(telemetry) && telemetryObjectValidator.validateAudit(telemetry)) { + telemetryEventLogger.info(telemetry); + } else { + ProjectLogger.log( + "TelemetryWriter:processLogEvent: Audit Telemetry validation failed: ", + telemetry, + LoggerEnum.ERROR.name()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/validator/TelemetryObjectValidator.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/validator/TelemetryObjectValidator.java new file mode 100644 index 0000000000..fe5a281d5c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/validator/TelemetryObjectValidator.java @@ -0,0 +1,13 @@ +package org.sunbird.telemetry.validator; + +/** @author arvind */ +public interface TelemetryObjectValidator { + + public boolean validateAudit(String jsonString); + + public boolean validateSearch(String jsonString); + + public boolean validateLog(String jsonString); + + public boolean validateError(String jsonString); +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/validator/TelemetryObjectValidatorV3.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/validator/TelemetryObjectValidatorV3.java new file mode 100644 index 0000000000..3624e81178 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/java/org/sunbird/telemetry/validator/TelemetryObjectValidatorV3.java @@ -0,0 +1,209 @@ +package org.sunbird.telemetry.validator; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.telemetry.dto.Telemetry; +import org.sunbird.telemetry.util.TelemetryEvents; + +/** @author arvind */ +public class TelemetryObjectValidatorV3 implements TelemetryObjectValidator { + + ObjectMapper mapper = new ObjectMapper(); + + @Override + public boolean validateAudit(String jsonString) { + + boolean validationSuccess = true; + List missingFields = new ArrayList<>(); + Telemetry telemetryObj = null; + try { + telemetryObj = mapper.readValue(jsonString, Telemetry.class); + validateBasics(telemetryObj, missingFields); + validateAuditEventData(telemetryObj.getEdata(), missingFields); + if (!missingFields.isEmpty()) { + ProjectLogger.log( + "Telemetry Object Creation Error for event : " + + TelemetryEvents.AUDIT.getName() + + " missing required fields :" + + String.join(",", missingFields)); + validationSuccess = false; + } + } catch (IOException e) { + validationSuccess = false; + ProjectLogger.log(e.getMessage(), e); + } + return validationSuccess; + } + + @Override + public boolean validateSearch(String jsonString) { + + boolean validationSuccess = true; + List missingFields = new ArrayList<>(); + Telemetry telemetryObj = null; + try { + telemetryObj = mapper.readValue(jsonString, Telemetry.class); + validateBasics(telemetryObj, missingFields); + validateSearchEventData(telemetryObj.getEdata(), missingFields); + if (!missingFields.isEmpty()) { + ProjectLogger.log( + "Telemetry Object Creation Error for event : " + + TelemetryEvents.SEARCH.getName() + + " missing required fields :" + + String.join(",", missingFields)); + validationSuccess = false; + } + } catch (IOException e) { + validationSuccess = false; + ProjectLogger.log(e.getMessage(), e); + } + return validationSuccess; + } + + private void validateSearchEventData(Map edata, List missingFields) { + + if (edata == null || edata.isEmpty()) { + missingFields.add("edata"); + } else { + if (null == edata.get(JsonKey.QUERY)) { + missingFields.add(JsonKey.QUERY); + } + if (null == edata.get(JsonKey.SIZE)) { + missingFields.add(JsonKey.SIZE); + } + if (null == edata.get(JsonKey.TOPN)) { + missingFields.add(JsonKey.TOPN); + } + } + } + + private void validateAuditEventData(Map edata, List missingFields) { + if (edata == null) { + missingFields.add("edata"); + } + } + + private void validateBasics(Telemetry telemetryObj, List missingFields) { + + if (StringUtils.isBlank(telemetryObj.getEid())) { + missingFields.add("eid"); + } + if (StringUtils.isBlank(telemetryObj.getMid())) { + missingFields.add("mid"); + } + if (StringUtils.isBlank(telemetryObj.getVer())) { + missingFields.add("ver"); + } + + if (null == telemetryObj.getActor()) { + missingFields.add("actor"); + } else { + if (StringUtils.isBlank(telemetryObj.getActor().getId())) { + missingFields.add("actor.id"); + } + if (StringUtils.isBlank(telemetryObj.getActor().getType())) { + missingFields.add("actor.type"); + } + } + + if (null == telemetryObj.getContext()) { + missingFields.add(JsonKey.CONTEXT); + } else { + if (StringUtils.isBlank(telemetryObj.getContext().getChannel())) { + missingFields.add(JsonKey.CONTEXT + "." + JsonKey.CHANNEL); + } + if (StringUtils.isBlank(telemetryObj.getContext().getEnv())) { + missingFields.add(JsonKey.CONTEXT + "." + JsonKey.ENV); + } + } + } + + @Override + public boolean validateLog(String jsonString) { + + boolean validationSuccess = true; + List missingFields = new ArrayList<>(); + Telemetry telemetryObj = null; + try { + telemetryObj = mapper.readValue(jsonString, Telemetry.class); + validateBasics(telemetryObj, missingFields); + validateLogEventData(telemetryObj.getEdata(), missingFields); + if (!missingFields.isEmpty()) { + ProjectLogger.log( + "Telemetry Object Creation Error for event : " + + TelemetryEvents.LOG.getName() + + " missing required fields :" + + String.join(",", missingFields)); + validationSuccess = false; + } + } catch (IOException e) { + validationSuccess = false; + ProjectLogger.log(e.getMessage(), e); + } + return validationSuccess; + } + + private void validateLogEventData(Map edata, List missingFields) { + if (edata == null || edata.isEmpty()) { + missingFields.add("edata"); + } else { + if (StringUtils.isBlank((String) edata.get(JsonKey.TYPE))) { + missingFields.add(JsonKey.TYPE); + } + if (StringUtils.isBlank((String) edata.get(JsonKey.LEVEL))) { + missingFields.add(JsonKey.LEVEL); + } + // TODO: remember and make this change at the time of re-factoring. + if (StringUtils.isBlank((String) edata.get(JsonKey.MESSAGE))) { + edata.remove(JsonKey.MESSAGE); + } + } + } + + @Override + public boolean validateError(String jsonString) { + + boolean validationSuccess = true; + List missingFields = new ArrayList<>(); + Telemetry telemetryObj = null; + try { + telemetryObj = mapper.readValue(jsonString, Telemetry.class); + validateBasics(telemetryObj, missingFields); + validateErrorEventData(telemetryObj.getEdata(), missingFields); + if (!missingFields.isEmpty()) { + ProjectLogger.log( + "Telemetry Object Creation Error for event : " + + TelemetryEvents.ERROR.getName() + + " missing required fields :" + + String.join(",", missingFields)); + validationSuccess = false; + } + } catch (IOException e) { + validationSuccess = false; + ProjectLogger.log(e.getMessage(), e); + } + return validationSuccess; + } + + private void validateErrorEventData(Map edata, List missingFields) { + if (edata == null || edata.isEmpty()) { + missingFields.add("edata"); + } else { + if (StringUtils.isBlank((String) edata.get(JsonKey.ERROR))) { + missingFields.add(JsonKey.ERROR); + } + if (StringUtils.isBlank((String) edata.get(JsonKey.ERR_TYPE))) { + missingFields.add(JsonKey.ERR_TYPE); + } + if (StringUtils.isBlank((String) edata.get(JsonKey.STACKTRACE))) { + missingFields.add(JsonKey.STACKTRACE); + } + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/OTPSMSTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/OTPSMSTemplate.vm new file mode 100644 index 0000000000..3273ff3663 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/OTPSMSTemplate.vm @@ -0,0 +1 @@ +One time password to verify your phone number on $installationName is $otp. This is valid for $otpExpiryInMinutes minutes only. \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/acceptFlagMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/acceptFlagMailTemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/acceptFlagMailTemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/cassandra.config.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/cassandra.config.properties new file mode 100644 index 0000000000..d673fd5541 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/cassandra.config.properties @@ -0,0 +1,8 @@ +coreConnectionsPerHostForLocal=4 +coreConnectionsPerHostForRemote=2 +maxConnectionsPerHostForLocal=10 +maxConnectionsPerHostForRemote=4 +maxRequestsPerConnection=32768 +heartbeatIntervalSeconds=60 +poolTimeoutMillis=0 +queryLoggerConstantThreshold=300 \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/cassandratablecolumn.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/cassandratablecolumn.properties new file mode 100644 index 0000000000..3b5d614f74 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/cassandratablecolumn.properties @@ -0,0 +1,250 @@ +id=id +courseid=courseId +coursename=courseName +userid=userId +enrolleddate=enrolledDate +description=description +tocurl=tocUrl +status=status +active=active +delta=delta +courseversion=courseVersion +grade=grade +progress=progress +lastreadcontentid=lastReadContentId +lastreadcontentstatus=lastReadContentStatus +lastreadcontentversion=lastReadContentVersion +datetime=dateTime +contentid=contentId +viewposition=viewPosition +viewcount=viewCount +lastaccesstime=lastAccessTime +completedcount=completedCount +position=position +result=result +score= score +contentversion=contentVersion +lastupdatedtime=lastUpdatedTime +lastcompletedtime=lastCompletedTime +facultyid=facultyId +facultyname=facultyName +organisationid=organisationId +organisationname=organisationName +enrollementstartdate=enrollementStartDate +enrollmentenddate=enrollmentEndDate +courseduration=courseDuration +addedbyid=addedById +addedbyname=addedByName +publishedbyid=publishedById +publishedbyname=publishedByName +createddate=createdDate +publisheddate=publishedDate +updateddate=updatedDate +updatedbyid=updatedById +updatedbyname=updatedByName +createdfor=createdFor +tutor=tutor +email=email +phone=phone +aadhaarno=aadhaarNo +updatedby=updatedBy +lastlogintime=lastLoginTime +firstname=firstName +lastname=lastName +password=password +avatar=avatar +gender=gender +language=language +state=state +city=city +zipcode=zipcode +username=userName +pagename=pageName +pagesectionname=pageSectionName +sectionorder=sectionOrder +description=description +imgurl=imgUrl +searchquery=searchQuery +searchurl=searchUrl +applicablefor=applicableFor +createdby=createdBy +courselogourl=courseLogoUrl +name=name +portalmap=portalMap +appmap=appMap +sectiondatatype=sectionDataType +addedby=addedBy +updatedby=updatedBy +usercount=userCount +timetaken=timeTaken +assessmentitemid=assessmentItemId +maxscore=maxScore +attemptid=attemptId +assessmenttype=assessmentType +attempteddate=attemptedDate +evaluationstatus=evaluationStatus +processingstatus=processingStatus +attemptedcount=attemptedCount +rootorgid=rootOrgId +regorgid=regOrgId +addtype=addType +addressline1=addressLine1 +addressline2=addressLine2 +yearofpassing=yearOfPassing +boardoruniversity=boardOrUniversity +jobname=jobName +joiningdate=joiningDate +enddate=endDate +orgid=orgId +orgname=orgName +boardname=boardName +addressid=addressId +isrejected=isRejected +isverified=isVerified +verifiedby=verifiedBy +verifieddate=verifiedDate +externalidvalue=externalIdValue +externalid=externalId +loginid=loginId +parentorgid=parentOrgId +isrootorg=isRootOrg +orgidone=orgIdOne +orgidtwo=orgIdTwo +parentof=parentOf +orgtype=orgType +childof=childOf +rootorg=rootOrg +approveddate=approvedDate +approvedbyname=approvedByName +iscurrentjob=isCurrentJob +noofmembers=noOfMembers +homeurl=homeUrl +isapproved=isApproved +orgcode=orgCode +approvedby=approvedBy +preferredlanguage=preferredLanguage +communityid=communityId +isdeleted=isDeleted +profilesummary=profileSummary +orgleftdate=orgLeftDate +isdefault=isDefault +leafnodescount=leafNodesCount +processstarttime=processStartTime +successresult=successResult +failureresult=failureResult +objecttype=objectType +uploadedby=uploadedBy +uploadeddate=uploadedDate +processendtime=processEndTime +enrollmenttype=enrollmentType +participant=participant +enrolmenttype=enrolmentType +startdate=startDate +enddate=endDate +lastupdatedon=lastUpdatedOn +createdfor=createdFor +coursecreator=courseCreator +courseadditionalinfo=courseAdditionalInfo +submitdate=submitDate +objectids=objectIds +countincrementstatus=countIncrementStatus +countincrementdate=countIncrementDate +countdecrementstatus=countDecrementStatus +countdecrementdate=countDecrementDate +contactdetail=contactDetail +hashtagid=hashTagId +theme =theme +batchid=batchId +isactive=isActive +badgetypeid=badgeTypeId +receiveddate=receivedDate +receiverid=receiverId +providerid=providerId +providername=providerName +provideremail=providerEmail +providerphone=providerPhone +validitydate=validityDate +expirydate=expiryDate +isverified=isVerified +isexpired=isExpired +isrevoked=isRevoked +revocationreason=revocationReason +revocationdate=revocationDate +revokedby=revokedBy +verifiedby=verifiedBy +verifieddate=verifiedDate +fileurl=fileUrl +trycount=tryCount +resourceid=resourceId +missingfields=missingFields +webpages=webPages +temppassword=tempPassword +currentlogintime=currentLoginTime +skillname=skillName +skillnametolowercase=skillNameToLowercase +addedby=addedBy +addedat=addedAt +endorsementcount=endorsementCount +endorsers=endorsers +profilevisibility=profileVisibility +orgtypeid=orgTypeId +retrycount=retryCount +tcstatus=tcStatus +tcupdatedat=tcUpdatedAt +tcupdateddate=tcUpdatedDate +clientname=clientName +masterkey=masterKey +locationid=locationId +countrycode=countryCode +endorserslist=endorsersList +emailverified=emailVerified +locationids=locationIds +userlistreq=userListReq +estimatedcountreq=estimatedCountReq +usercountttl=userCountTTL +issuerid=issuerId +resourcename=resourceName +badgeid=badgeId +badgeclassimage=badgeClassImage +assertionid=assertionId +badgeclassname=badgeClassName +parentid=parentId +taskcount=taskCount +sequenceid=sequenceId +iterationid=iterationId +processid=processId +createdon=createdOn +registryid=registryId +lastupdatedby=lastUpdatedBy +idtype=idType +originalexternalid=originalExternalId +originalprovider=originalProvider +originalidtype=originalIdType +rolegroupid=roleGroupId +url_action_ids=url_Action_Ids +usertype=userType +storagedetails=storageDetails +completedon=completedOn +tncacceptedon=tncAcceptedOn +tncacceptedversion=tncAcceptedVersion +phoneverified=phoneVerified +datasource=dataSource +maskedemail=maskedEmail +maskedphone=maskedPhone +prevusedemail=prevUsedEmail +prevusedphone=prevUsedPhone +otherlink=otherLink +recoveryemail=recoveryEmail +recoveryphone=recoveryPhone +userextid=userExtId +orgextid=orgExtId +userstatus=userStatus +claimstatus=claimStatus +claimedon=claimedOn +updatedon=updatedOn +flagsvalue=flagsValue +userids=userIds +telemetrycontext=telemetryContext +isssoenabled=isSSOEnabled +dynamicfilters=dynamicFilters +managedby=managedBy diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/contentFlaggedMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/contentFlaggedMailTemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/contentFlaggedMailTemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/contentReviewMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/contentReviewMailTemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/contentReviewMailTemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/dbconfig.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/dbconfig.properties new file mode 100644 index 0000000000..564bec9208 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/dbconfig.properties @@ -0,0 +1,6 @@ +db.ip=127.0.0.1 +db.port=9042 +db.username= +db.password= +db.keyspace=sunbird + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/elasticsearch.config.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/elasticsearch.config.properties new file mode 100644 index 0000000000..564aaedcb2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/elasticsearch.config.properties @@ -0,0 +1,3 @@ +es.cluster.name= +es.host.name=localhost +es.host.port=9300 \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/emailtemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/emailtemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/emailtemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/externalresource.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/externalresource.properties new file mode 100644 index 0000000000..5f1d519659 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/externalresource.properties @@ -0,0 +1,205 @@ +content_url=/content/v3/hierarchy/ +ekstep_content_search_url=/v3/search +ekstep_telemetry_api_url=/data/v3/telemetry +ekstep_authorization= +ekstep_course_publish_url=/content/v3/publish +ekstep_metrics_api_url=/metrics/consumption/content-usage +ekstep_es_metrics_api_url=/metrics/creation/content-snapshot +ekstep.tag.api.url=/tag/register +ekstep.content.update.url=/system/v3/content/update/ +sunbird.content.badge.assign.url=/v1/content/badge/assign/ +sunbird.content.badge.revoke.url=/v1/content/badge/revoke/ +sunbird_installation=sunbird +sunbird_analytics_api_base_url=https://dev.ekstep.in/api/data/v3 +sunbird_search_service_api_base_url=https://dev.ekstep.in/api/search +ekstep_api_base_url=https://dev.ekstep.in/api +sunbird_user_org_api_base_url=https://dev.sunbirded.org/api +sunbird_search_organisation_api=/v1/org/search +sunbird_read_user_api=/v1/user/read +sunbird_search_user_api=/v1/user/search +sunbird_send_email_notifictaion_api=/v1/notification/email +sunbird_mail_server_host= +sunbird_mail_server_port= +sunbird_mail_server_username= +sunbird_mail_server_password= +sunbird_mail_server_from_email=support@open-sunbird.org +sunbird_username_num_digits=4 +ekstep_concept_base_url=/domain/v3/{domain}/concepts/list +ekstep_domain_url=/domain/v3/list +quartz_course_batch_timer=0 0 0/4 1/1 * ? * +quartz_upload_timer=0 0 23 1/1 * ? * +quartz_course_publish_timer=0 0 0/1 1/1 * ? * +quartz_matrix_report_timer=0 0 0/4 1/1 * ? * +quartz_shadow_user_migration_timer=0 0 2 1/1 * ? * +sunbird_account_name= +sunbird_account_key= +download_link_expiry_timeout=300 +sunbird_encryption_key=SunBird +sunbird_encryption_mode=local +quartz_metrics_timer =0 0 0/4 * * ? * +sunbird_encryption=ON +sunbird_allowed_login=You can use your cellphone number to login +#size of bulk upload data is 1001 including header in csv file +sunbird_user_bulk_upload_size=1001 +bulk_upload_org_data_size=300 +bulk_upload_batch_data_size=200 +user_relations=address,education,jobProfile,orgUser +org_relations=orgUser,address +batch_relations= +default_date_range=7 +sunbird_web_url=https://dev.sunbirded.org +sunbird_app_url= +sunbird_channel_read_api=/v1/channel/read +sunbird_framework_read_api=/v1/framework/read +# background actor modes {local,remote} +background_actor_provider=remote +# actor modes {local,remote} +api_actor_provider=local +# cassandra modes {standalone,embedded} +sunbird_cassandra_mode=standalone +embeddedCassandra_TimeOut=20000000000 +embedded_cassandra_host=127.0.0.1 +embedded_cassandra_port=9142 +#file to load cassandra DB into memory. +embedded_cql_file_name=cassandra.cql +fcm.url=https://fcm.googleapis.com/fcm/send +sunbird_default_country_code=+91 +#put the default evn logo url here or System Env variable with +#same key. code will first search from EVN then here. +sunbird_env_logo_url=http://via.placeholder.com/100x50 +es_search_url=http://localhost:9200 +es_metrics_port=9200 +system_settings_properties=phoneUnique,emailUnique +sunbird_default_welcome_sms=Welcome to DIKSHA. +quartz_update_user_count_timer=0 0 2 1/1 * ? * +sunbird_url_shortner_base_url=https://api-ssl.bitly.com/v3/shorten?access_token= +sunbird_url_shortner_access_token= +ekstep.channel.reg.api.url=/channel/v3/create +ekstep.channel.list.api.url=/channel/v3/list +quartz_channel_reg_timer=0 0 1 1/1 * ? * +sunbird_otp_allowed_attempt=2 + +#Telemetry producer related info +telemetry_pdata_id=local.sunbird.learning.service +telemetry_pdata_pid=learning-service +telemetry_pdata_ver=2.10.0 +#elastic search top n result count for telemetry +searchTopN=5 +telemetry_queue_threshold_value=200 +ekstep.channel.update.api.url=/channel/v3/update +sunbird_badger_baseurl=http://localhost:8000 +# badge related info. +badging_authorization_key= +badging_assertion_list_size=5 +sunbird_valid_badge_subtypes=award,certificate,endorsement,authorization +sunbird_valid_badge_roles=TEACHER_BADGE_ISSUER,OFFICIAL_TEXTBOOK_BADGE_ISSUER +sunbird_learner_service_url=http://localhost:9000 +sunbird_content_read=/content/v3/read +# Sunbird lms telemetry url +sunbird_lms_base_url=http://localhost:9000 +sunbird_telemetry_api_path=/v1/telemetry +sunbird_lms_authorization= +# Sunbird Installation mail +sunbird_installation_email=dummy@dummy.org +sunbird_valid_location_types=state,district,block;cluster +# Bulk upload file max size in MB +file_upload_max_size=10 +sunbird_default_channel= +# Batch size for cassandra batch operation +cassandra_write_batch_size=100 +sunbird_telemetry_base_url=http://localhost:9000 +sunbird_cs_search_path=/composite/v1/search +# Sunbird OpenSaber Integration +sunbird_open_saber_bridge_enable=false +sunbird_default_user_type=teacher +sunbird_installation_display_name=sunbird +sunbird_app_name= +sunbird_email_max_recipients_limit=100 +sunbird_user_max_encryption_limit=100 +sunbird_sso_client_id= +sunbird_sso_username= +sunbird_sso_password= +sunbird_sso_url= +sunbird_sso_realm= +sunbird_keycloak_required_action_link_expiration_seconds=155520000 +sunbird_url_shortner_enable=false +sunbird_user_profile_field_default_visibility=public +sunbird_api_request_lower_case_fields=source,externalId,userName,provider,loginId,email,prevUsedEmail +# Textbook TOC Api +sunbird_content_read_api=/content/v3/read +textbook_toc_allowed_content_types=TextBook,Collection,LessonPlan +sunbird_get_hierarchy_api=/content/v3/hierarchy +sunbird_update_hierarchy_api=/content/v3/hierarchy/update +textbook_toc_max_csv_rows=6500 +textbook_toc_input_mapping={\"identifier\":\"Identifier\",\"frameworkCategories\":{\"board\":\"Board\",\"medium\":\"Medium\",\"gradeLevel\":\"Grade\",\"subject\":\"Subject\"},\"hierarchy\":{\"Textbook\":\"Textbook Name\",\"L:1\":\"Level 1 Textbook Unit\",\"L:2\":\"Level 2 Textbook Unit\",\"L:3\":\"Level 3 Textbook Unit\",\"L:4\":\"Level 4 Textbook Unit\"},\"metadata\":{\"description\":\"Description\",\"topic\":\"Mapped Topics\",\"keywords\":\"Keywords\",\"purpose\":\"Purpose of Content to be linked\",\"dialcodeRequired\":\"QR Code Required?\",\"dialcodes\":\"QR Code\"}} +textbook_toc_file_suppress_column_names=true +sunbird_texbook_toc_csv_ttl=86400 +textbook_toc_mandatory_fields={\"Textbook\":\"Textbook Name\",\"L:1\":\"Level 1 Textbook Unit\"} +sunbird_toc_linked_content_column_name=Linked Content {0} +sunbird_toc_max_first_level_units=30 +sunbird_content_cloud_storage_type=azure +sunbird_content_azure_storage_container=sunbird-content-dev +sunbird_cloud_content_folder=content +sunbird_otp_expiration=1800 +sunbird_otp_length=6 +sunbird_otp_hour_rate_limit=5 +sunbird_otp_day_rate_limit=20 +sunbird_rate_limit_enabled=true +framework_read_api_url=/framework/v3/read +sunbird_link_dial_code_api=/collection/v3/dialcode/link +sunbird_linked_content_base_url=https://dev.sunbirded.org/play/content/ +textbook_toc_output_mapping={\"identifier\":\"Identifier\",\"frameworkCategories\":{\"board\":\"Board\",\"medium\":\"Medium\",\"gradeLevel\":\"Grade\",\"subject\":\"Subject\"},\"hierarchy\":{\"Textbook\":\"Textbook Name\",\"L:1\":\"Level 1 Textbook Unit\",\"L:2\":\"Level 2 Textbook Unit\",\"L:3\":\"Level 3 Textbook Unit\",\"L:4\":\"Level 4 Textbook Unit\"},\"metadata\":{\"description\":\"Description\",\"topic\":\"Mapped Topics\",\"keywords\":\"Keywords\",\"purpose\":\"Purpose of Content to be linked\",\"dialcodeRequired\":\"QR Code Required?\",\"dialcodes\":\"QR Code\"},\"linkedContent\":{\"Linked Content 1\":\"Linked Content 1\",\"Linked Content 2\":\"Linked Content 2\",\"Linked Content 3\":\"Linked Content 3\",\"Linked Content 4\":\"Linked Content 4\",\"Linked Content 5\":\"Linked Content 5\",\"Linked Content 6\":\"Linked Content 6\",\"Linked Content 7\":\"Linked Content 7\",\"Linked Content 8\":\"Linked Content 8\",\"Linked Content 9\":\"Linked Content 9\",\"Linked Content 10\":\"Linked Content 10\",\"Linked Content 11\":\"Linked Content 11\",\"Linked Content 12\":\"Linked Content 12\",\"Linked Content 13\":\"Linked Content 13\",\"Linked Content 14\":\"Linked Content 14\",\"Linked Content 15\":\"Linked Content 15\",\"Linked Content 16\":\"Linked Content 16\",\"Linked Content 17\":\"Linked Content 17\",\"Linked Content 18\":\"Linked Content 18\",\"Linked Content 19\":\"Linked Content 19\",\"Linked Content 20\":\"Linked Content 20\",\"Linked Content 21\":\"Linked Content 21\",\"Linked Content 22\":\"Linked Content 22\",\"Linked Content 23\":\"Linked Content 23\",\"Linked Content 24\":\"Linked Content 24\",\"Linked Content 25\":\"Linked Content 25\"},\"Linked Content 26\":\"Linked Content 26\",\"Linked Content 27\":\"Linked Content 27\",\"Linked Content 28\":\"Linked Content 28\",\"Linked Content 29\":\"Linked Content 29\",\"Linked Content 30\":\"Linked Content 30\"} +# For other environments +sunbird_content_search_url=/v1/content/search +# For Local +# sunbird_content_search_url=/content/v1/search +sunbird_time_zone=Asia/Kolkata +# For other environments +sunbird_dialcode_search_api=/v1/dialcode/list +# For Local +# sunbird_dialcode_search_api=/dialcode/v1/list +sunbird_cs_base_url=https://dev.sunbirded.org/api +sunbird_health_check_enable=true +sunbird_sync_read_wait_time=1500 +sunbird_course_metrics_container=reports +sunbird_course_metrics_report_folder=course-progress-reports +sunbird_assessment_report_folder=assessment-reports +sunbird_gzip_size_threshold=262144 +sunbird_analytics_blob_account_name= +sunbird_analytics_blob_account_key= +sunbird_redis_port=6379 +sunbird_redis_host=127.0.0.1 +sunbird_redis_scan_interval=2000 +sunbird_cache_enable=false +sunbird_redis_connection_pool_size=250 +kafka_topics_instruction=local.coursebatch.job.request +kafka_urls=localhost:9092 +sunbird_audit_event_batch_allowed=false +sunbird_fuzzy_search_threshold=0.5 +sunbird_state_img_url=https://sunbirddev.blob.core.windows.net/orgemailtemplate/img/File-0128212938260643843.png +sunbird_diksha_img_url=https://sunbirddev.blob.core.windows.net/orgemailtemplate/img/File-0128212989820190722.png +sunbird_cert_completion_img_url=https://sunbirddev.blob.core.windows.net/orgemailtemplate/img/File-0128212919987568641.png +sunbird_reset_pass_msg=Your have requested to reset password. Click on the link to set a password: {0} +sunbird_reset_pass_mail_subject=Reset Password +sunbird_subdomain_keycloak_base_url=https://merge.dev.sunbirded.org/auth/ +kafka_topics_certificate_instruction=local.certificate.job.request +kafka_linger_ms=5 +sunbird_cert_service_base_url= +sunbird_cert_download_uri=/v1/user/certs/download +#{0} instancename , {1} toaccountemail or phone in mask , {2} from account email/phone in mask +sunbird_account_merge_body=All your {0} usage details are merged into your account {1} . The account {2} has been deleted +sunbird_user_upload_error_visualization_threshold=20001 +sunbird_course_completion_certificate_name=100PercentCompletionCertificate +sunbird_migrate_user_body=You can now access your {0} state teacher account using {1}. Please log out and login once again to see updated details. +kafka_assessment_topic=local.telemetry.assess +sunbird_account_merge_subject=Account merged successfully +sunbird_pass_regex=(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!\"#$%&'()*+,-./:;<=>?@\\[\\]^_`{|}~])(?=\\S+$).{8,} +sunbird_cert_template_url=/cert/v1/template/read +sunbird_user_create_sync_type=ES +sunbird_user_create_sync_topic=local.user.events +sigterm_stop_delay=40 +sunbird_batch_content_types=Course,CurriculumCourse +limit_managed_user_creation=true +managed_user_limit=30 +adminutil_base_url = http://adminutil:4000/ +adminutil_sign_endpoint = v1/sign/payload \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/forgotPasswordWithOTP.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/forgotPasswordWithOTP.vm new file mode 100644 index 0000000000..66325cf607 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/forgotPasswordWithOTP.vm @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + +
  +
+ + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + +
+

Someone just requested to change your $realmName account's credentials. If this was you, use below OTP to reset your credentials. +

+
+

OTP : $otp

+
+

This OTP will expire within $ttl Minute.

+ +
+

If you don't want to reset your credentials, just ignore this message and nothing will be changed.

+
+
+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/forgotpassword.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/forgotpassword.vm new file mode 100644 index 0000000000..d772a3a526 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/forgotpassword.vm @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + +
  +
+ + + + + + + + + + +
+ + + + + + +
+

Hi $name,

+ + + + + + + + + +
+

Please find the temporary password below, do the password change after first login: +

+ +

Password : $tempPassword

+ +
+

+ + + + + + + +
+

+ #if ($webUrl) + Web acccess URL : Click here + #end +

+

+ #if ($appUrl) + Download App : Click here + #end +

+ +
+
+

Thank You,

+

Team $orgName

+

#if ($note) + $note $fromEmail. + #end +

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/mailTemplates.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/mailTemplates.properties new file mode 100644 index 0000000000..0a2f67f88b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/mailTemplates.properties @@ -0,0 +1,5 @@ +orgName=Diksha +onboarding_mail_subject=Welcome to {0} +onboarding_welcome_message=Welcome to {0} +onboarding_welcome_mail_body=Please ensure that you change your password according to instructions when you log in for the first time. +mail_note=Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/profilecompleteness.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/profilecompleteness.properties new file mode 100644 index 0000000000..4eb3f3ae21 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/profilecompleteness.properties @@ -0,0 +1,6 @@ +user.profile.attribute=firstName,lastName,dob,avatar,gender,grade,language,location,profileSummary,subject,userName,address,education,jobProfile +#if u want equal weighted then don't provide any values here.By default all the key will be equally divided by 100%. +#you can provide your weighted in same attribute order. if you are providing values make sure sum of all values is 100 and either +#provide for all attribute or none. value should be either int or float +#6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25,6.25 +user.profile.weighted= \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/publishContentMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/publishContentMailTemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/publishContentMailTemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/rejectContentMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/rejectContentMailTemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/rejectContentMailTemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/rejectFlagMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/rejectFlagMailTemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/rejectFlagMailTemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/sso.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/sso.properties new file mode 100644 index 0000000000..ce3a6507ae --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/sso.properties @@ -0,0 +1,4 @@ +sso.url= +sso.realm=sunbird +sso.connection.pool.size=20 +sso.enabled=true diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/unlistedPublishContentMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/unlistedPublishContentMailTemplate.vm new file mode 100644 index 0000000000..50ff99ca9f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/unlistedPublishContentMailTemplate.vm @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + +
+ + + + + + + +
+ + #if ($orgImageUrl) +

logo

+ #end +
+ #if ($name) +

Hi $name,

+ #end +

$body

+ + + + + + +
+ + + #if ($actionUrl) + + + + #end + +
#if ($actionName) $actionName #end
+
+

Regards,

+

Team + #if ($orgName) + $orgName + #end +

+

Note: This is an automatic alert email. Replies to this mail box will not be monitored. If you are not the intended recipient of this message, or need to communicate with the team, write to $fromEmail.

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/userencryption.properties b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/userencryption.properties new file mode 100644 index 0000000000..794ad22dec --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/userencryption.properties @@ -0,0 +1,6 @@ +userkey.encryption=email,phone,userName,location,loginId,prevUsedEmail,prevUsedPhone,recoveryEmail,recoveryPhone +addresskey.encryption=addressLine1,addressLine2,city,state,country,zipcode,userId,updatedBy,createdBy +userkey.decryption=encEmail,encPhone,userName,location,loginId,email,phone,prevUsedEmail,prevUsedPhone,recoveryEmail,recoveryPhone +userkey.masked=email,phone,recoveryEmail,recoveryPhone,prevUsedPhone,recoveryEmail,prevUsedEmail +userkey.phonetypeattributes=phone,recoveryPhone,prevUsedPhone +userkey.emailtypeattributes=email,recoveryEmail,prevUsedEmail \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/welcomeMailTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/welcomeMailTemplate.vm new file mode 100644 index 0000000000..0e7ae77969 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/welcomeMailTemplate.vm @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + +
  +
+ + + + + + + + + + +
+ + + + + + +
+

$welcomeMessage,

+ + + + + + + + + +
+

Your user account has now been created. Click on the link below to #if ($setPasswordLink) set a password #else verify your email ID #end and start using your account: +

+

+ + #if ($setPasswordLink) + Set Password + #else + Verify Email + #end + +

+
+
+

Regards,

+

Team $orgName

+

#if ($note) + $note $fromEmail. + #end +

+
+
+ +
+
 
+ + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/welcomeSmsTemplate.vm b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/welcomeSmsTemplate.vm new file mode 100644 index 0000000000..e66670b65d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/main/resources/welcomeSmsTemplate.vm @@ -0,0 +1,2 @@ +Welcome to $instanceName. Your user account has now been created. Click on the link below to #if ($setPasswordLink) set a password #else verify your email ID #end and start using your account:$newline +$link \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/exception/ExceptionTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/exception/ExceptionTest.java new file mode 100644 index 0000000000..f1d3361655 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/exception/ExceptionTest.java @@ -0,0 +1,40 @@ +/** */ +package org.sunbird.common.exception; + +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class ExceptionTest { + + @Test + public void testProjectCommonException() { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.apiKeyRequired.getErrorCode(), + ResponseCode.apiKeyRequired.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + Assert.assertEquals(exception.getCode(), ResponseCode.apiKeyRequired.getErrorCode()); + Assert.assertEquals(exception.getMessage(), ResponseCode.apiKeyRequired.getErrorMessage()); + Assert.assertEquals(exception.getResponseCode(), ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + @Test + public void testProjectCommonExceptionUsingSetters() { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.apiKeyRequired.getErrorCode(), + ResponseCode.apiKeyRequired.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + Assert.assertEquals(exception.getCode(), ResponseCode.apiKeyRequired.getErrorCode()); + Assert.assertEquals(exception.getMessage(), ResponseCode.apiKeyRequired.getErrorMessage()); + Assert.assertEquals(exception.getResponseCode(), ResponseCode.CLIENT_ERROR.getResponseCode()); + exception.setCode(ResponseCode.userAlreadyExists.getErrorCode()); + exception.setMessage(ResponseCode.userAlreadyExists.getErrorMessage()); + exception.setResponseCode(ResponseCode.SERVER_ERROR.getResponseCode()); + Assert.assertEquals(exception.getCode(), ResponseCode.userAlreadyExists.getErrorCode()); + Assert.assertEquals(exception.getMessage(), ResponseCode.userAlreadyExists.getErrorMessage()); + Assert.assertEquals(exception.getResponseCode(), ResponseCode.SERVER_ERROR.getResponseCode()); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/AppTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/AppTest.java new file mode 100644 index 0000000000..880cd41ae8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/AppTest.java @@ -0,0 +1,79 @@ +package org.sunbird.common.models; + +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.sunbird.common.models.util.BaseHttpTest; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; + +public class AppTest extends BaseHttpTest { + private static final String data = + "{\"request\": { \"search\": {\"contentType\": [\"Story\"] }}}"; + private static Map headers = new HashMap(); + + @BeforeClass + public static void init() { + headers.put("content-type", "application/json"); + headers.put("accept", "application/json"); + headers.put("user-id", "mahesh"); + String header = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(header)) { + header = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } + headers.put("authorization", "Bearer " + header); + } + + @Test + public void testSendPostRequestSuccess() throws Exception { + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(ekStepBaseUrl)) { + ekStepBaseUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + String response = HttpUtil.sendPostRequest(ekStepBaseUrl + "/content/v3/list", data, headers); + Assert.assertNotNull(response); + } + + @Test() + public void testSendPostRequestFailureWithWrongUrl() { + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(ekStepBaseUrl)) { + ekStepBaseUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + String response = null; + try { + Map data = new HashMap<>(); + data.put("search", "\"contentType\": [\"Story\"]"); + response = HttpUtil.sendPostRequest(ekStepBaseUrl + "/content/wrong/v3/list", data, headers); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertNull(response); + } + + @Test() + public void testSendPatchRequestSuccess() { + String response = null; + try { + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(ekStepBaseUrl)) { + ekStepBaseUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + response = + HttpUtil.sendPatchRequest( + ekStepBaseUrl + + PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_TAG_API_URL) + + "/" + + "testt123", + "{}", + headers); + } catch (Exception e) { + } + Assert.assertNotNull(response); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ClientErrorResponseTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ClientErrorResponseTest.java new file mode 100644 index 0000000000..8e5d64b884 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ClientErrorResponseTest.java @@ -0,0 +1,42 @@ +package org.sunbird.common.models; + +import java.util.HashMap; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.response.ResponseParams; +import org.sunbird.common.responsecode.ResponseCode; + +public class ClientErrorResponseTest { + + @Test + public void responseCreate() { + org.sunbird.common.models.response.Response response = + new org.sunbird.common.models.response.ClientErrorResponse(); + response.setId("test"); + response.setTs("1233444555"); + response.setVer("v1"); + ResponseParams params = new ResponseParams(); + params.setErr("Server Error"); + params.setErrmsg("test msg"); + params.setMsgid("123"); + params.setResmsgid("4566"); + params.setStatus("OK"); + response.setParams(params); + Assert.assertEquals(response.getId(), "test"); + Assert.assertEquals(response.getTs(), "1233444555"); + Assert.assertEquals(response.getVer(), "v1"); + Assert.assertEquals(response.getParams(), params); + Assert.assertEquals(response.getResponseCode(), ResponseCode.CLIENT_ERROR); + Assert.assertEquals(response.getParams().getErr(), params.getErr()); + Assert.assertEquals(response.getParams().getErrmsg(), params.getErrmsg()); + Assert.assertEquals(response.getParams().getMsgid(), params.getMsgid()); + Assert.assertEquals(response.getParams().getResmsgid(), params.getResmsgid()); + Assert.assertEquals(response.getParams().getStatus(), params.getStatus()); + Assert.assertEquals(response.getResult().size(), 0); + Assert.assertNotEquals(response.get("Test"), "test"); + response.putAll(new HashMap()); + response.put("test", "test123"); + org.sunbird.common.models.response.Response responseClone = response.clone(response); + Assert.assertNotEquals(response, responseClone); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/RequestParamsTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/RequestParamsTest.java new file mode 100644 index 0000000000..3a2178e134 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/RequestParamsTest.java @@ -0,0 +1,29 @@ +/** */ +package org.sunbird.common.models; + +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.request.RequestParams; + +/** @author Manzarul */ +public class RequestParamsTest { + + @Test + public void testResponseParamBean() { + RequestParams params = new RequestParams(); + params.setAuthToken("auth_1233"); + params.setCid("cid"); + params.setDid("deviceId"); + params.setKey("account key"); + params.setMsgid("uniqueMsgId"); + params.setSid("sid"); + params.setUid("UUID"); + Assert.assertEquals(params.getAuthToken(), "auth_1233"); + Assert.assertEquals(params.getCid(), "cid"); + Assert.assertEquals(params.getMsgid(), "uniqueMsgId"); + Assert.assertEquals(params.getDid(), "deviceId"); + Assert.assertEquals(params.getKey(), "account key"); + Assert.assertEquals(params.getSid(), "sid"); + Assert.assertEquals(params.getUid(), "UUID"); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ResponseParamsTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ResponseParamsTest.java new file mode 100644 index 0000000000..36ec08b427 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ResponseParamsTest.java @@ -0,0 +1,29 @@ +/** */ +package org.sunbird.common.models; + +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.response.ResponseParams; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class ResponseParamsTest { + + @Test + public void testResponseParamBean() { + ResponseParams params = new ResponseParams(); + params.setErr(ResponseCode.addressError.getErrorCode()); + params.setErrmsg(ResponseCode.addressError.getErrorMessage()); + params.setMsgid("test"); + params.setResmsgid("test-1"); + params.setStatus("OK"); + Assert.assertEquals(params.getErr(), ResponseCode.addressError.getErrorCode()); + Assert.assertEquals(params.getErrmsg(), ResponseCode.addressError.getErrorMessage()); + Assert.assertEquals(params.getMsgid(), "test"); + Assert.assertEquals(params.getResmsgid(), "test-1"); + Assert.assertEquals(params.getStatus(), "OK"); + Assert.assertEquals(ResponseParams.StatusType.FAILED.name(), "FAILED"); + Assert.assertEquals(ResponseParams.StatusType.SUCCESSFUL.name(), "SUCCESSFUL"); + Assert.assertEquals(ResponseParams.StatusType.WARNING.name(), "WARNING"); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ResponseTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ResponseTest.java new file mode 100644 index 0000000000..484c86487a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/ResponseTest.java @@ -0,0 +1,45 @@ +/** */ +package org.sunbird.common.models; + +import java.util.HashMap; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.response.ResponseParams; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class ResponseTest { + + @Test + public void responseCreate() { + org.sunbird.common.models.response.Response response = + new org.sunbird.common.models.response.Response(); + response.setId("test"); + response.setResponseCode(ResponseCode.SERVER_ERROR); + response.setTs("1233444555"); + response.setVer("v1"); + ResponseParams params = new ResponseParams(); + params.setErr("Server Error"); + params.setErrmsg("test msg"); + params.setMsgid("123"); + params.setResmsgid("4566"); + params.setStatus("OK"); + response.setParams(params); + Assert.assertEquals(response.getId(), "test"); + Assert.assertEquals(response.getTs(), "1233444555"); + Assert.assertEquals(response.getVer(), "v1"); + Assert.assertEquals(response.getParams(), params); + Assert.assertEquals(response.getResponseCode(), ResponseCode.SERVER_ERROR); + Assert.assertEquals(response.getParams().getErr(), params.getErr()); + Assert.assertEquals(response.getParams().getErrmsg(), params.getErrmsg()); + Assert.assertEquals(response.getParams().getMsgid(), params.getMsgid()); + Assert.assertEquals(response.getParams().getResmsgid(), params.getResmsgid()); + Assert.assertEquals(response.getParams().getStatus(), params.getStatus()); + Assert.assertEquals(response.getResult().size(), 0); + Assert.assertNotEquals(response.get("Test"), "test"); + response.putAll(new HashMap()); + response.put("test", "test123"); + org.sunbird.common.models.response.Response responseClone = response.clone(response); + Assert.assertNotEquals(response, responseClone); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ActorOperationTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ActorOperationTest.java new file mode 100644 index 0000000000..5706227979 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ActorOperationTest.java @@ -0,0 +1,155 @@ +/** */ +package org.sunbird.common.models.util; + +import org.junit.Assert; +import org.junit.Test; + +/** @author Manzarul */ +public class ActorOperationTest { + + @Test + public void testActorOperation() { + Assert.assertEquals("enrollCourse", ActorOperations.ENROLL_COURSE.getValue()); + Assert.assertEquals("getCourse", ActorOperations.GET_COURSE.getValue()); + Assert.assertEquals("getContent", ActorOperations.GET_CONTENT.getValue()); + Assert.assertEquals("addContent", ActorOperations.ADD_CONTENT.getValue()); + Assert.assertEquals("createCourse", ActorOperations.CREATE_COURSE.getValue()); + Assert.assertEquals("updateCourse", ActorOperations.UPDATE_COURSE.getValue()); + Assert.assertEquals("publishCourse", ActorOperations.PUBLISH_COURSE.getValue()); + Assert.assertEquals("searchCourse", ActorOperations.SEARCH_COURSE.getValue()); + Assert.assertEquals("deleteCourse", ActorOperations.DELETE_COURSE.getValue()); + Assert.assertEquals("sendNotification", ActorOperations.SEND_NOTIFICATION.getValue()); + Assert.assertEquals("syncKeycloak", ActorOperations.SYNC_KEYCLOAK.getValue()); + Assert.assertEquals("updateSystemSettings", ActorOperations.UPDATE_SYSTEM_SETTINGS.getValue()); + Assert.assertEquals("deleteGeoLocation", ActorOperations.DELETE_GEO_LOCATION.getValue()); + Assert.assertEquals("getUserCount", ActorOperations.GET_USER_COUNT.getValue()); + Assert.assertEquals("updateGeoLocation", ActorOperations.UPDATE_GEO_LOCATION.getValue()); + Assert.assertEquals("getGeoLocation", ActorOperations.GET_GEO_LOCATION.getValue()); + Assert.assertEquals("registerClient", ActorOperations.REGISTER_CLIENT.getValue()); + Assert.assertEquals("updateClientKey", ActorOperations.UPDATE_CLIENT_KEY.getValue()); + Assert.assertEquals("getClientKey", ActorOperations.GET_CLIENT_KEY.getValue()); + Assert.assertEquals("createGeoLocation", ActorOperations.CREATE_GEO_LOCATION.getValue()); + Assert.assertEquals( + "updateTenantPreference", ActorOperations.UPDATE_TENANT_PREFERENCE.getValue()); + Assert.assertEquals("getTenantPreference", ActorOperations.GET_TENANT_PREFERENCE.getValue()); + Assert.assertEquals("addSkill", ActorOperations.ADD_SKILL.getValue()); + Assert.assertEquals("getSkill", ActorOperations.GET_SKILL.getValue()); + Assert.assertEquals("getSkillsList", ActorOperations.GET_SKILLS_LIST.getValue()); + Assert.assertEquals("profileVisibility", ActorOperations.PROFILE_VISIBILITY.getValue()); + Assert.assertEquals( + "createTanentPreference", ActorOperations.CREATE_TENANT_PREFERENCE.getValue()); + Assert.assertEquals("createUser", ActorOperations.CREATE_USER.getValue()); + Assert.assertEquals("updateUser", ActorOperations.UPDATE_USER.getValue()); + Assert.assertEquals("userAuth", ActorOperations.USER_AUTH.getValue()); + Assert.assertEquals("getUserProfile", ActorOperations.GET_USER_PROFILE.getValue()); + Assert.assertEquals("createOrg", ActorOperations.CREATE_ORG.getValue()); + Assert.assertEquals("updateOrg", ActorOperations.UPDATE_ORG.getValue()); + Assert.assertEquals("updateOrgStatus", ActorOperations.UPDATE_ORG_STATUS.getValue()); + Assert.assertEquals("getOrgDetails", ActorOperations.GET_ORG_DETAILS.getValue()); + Assert.assertEquals("userAuth", ActorOperations.USER_AUTH.getValue()); + Assert.assertEquals("createPage", ActorOperations.CREATE_PAGE.getValue()); + Assert.assertEquals("updatePage", ActorOperations.UPDATE_PAGE.getValue()); + Assert.assertEquals("deletePage", ActorOperations.DELETE_PAGE.getValue()); + Assert.assertEquals("getPageSettings", ActorOperations.GET_PAGE_SETTINGS.getValue()); + Assert.assertEquals("getPageData", ActorOperations.GET_PAGE_DATA.getValue()); + Assert.assertEquals("createSection", ActorOperations.CREATE_SECTION.getValue()); + Assert.assertEquals("updateSection", ActorOperations.UPDATE_SECTION.getValue()); + Assert.assertEquals("getAllSection", ActorOperations.GET_ALL_SECTION.getValue()); + Assert.assertEquals("getSection", ActorOperations.GET_SECTION.getValue()); + Assert.assertEquals("getCourseById", ActorOperations.GET_COURSE_BY_ID.getValue()); + Assert.assertEquals("updateUserCount", ActorOperations.UPDATE_USER_COUNT.getValue()); + Assert.assertEquals( + "getRecommendedCourses", ActorOperations.GET_RECOMMENDED_COURSES.getValue()); + Assert.assertEquals( + "updateUserInfoToElastic", ActorOperations.UPDATE_USER_INFO_ELASTIC.getValue()); + Assert.assertEquals("getRoles", ActorOperations.GET_ROLES.getValue()); + Assert.assertEquals("approveOrganisation", ActorOperations.APPROVE_ORGANISATION.getValue()); + Assert.assertEquals( + "addMemberOrganisation", ActorOperations.ADD_MEMBER_ORGANISATION.getValue()); + Assert.assertEquals( + "removeMemberOrganisation", ActorOperations.REMOVE_MEMBER_ORGANISATION.getValue()); + Assert.assertEquals("compositeSearch", ActorOperations.COMPOSITE_SEARCH.getValue()); + Assert.assertEquals( + "getUserDetailsByLoginId", ActorOperations.GET_USER_DETAILS_BY_LOGINID.getValue()); + Assert.assertEquals( + "updateOrgInfoToElastic", ActorOperations.UPDATE_ORG_INFO_ELASTIC.getValue()); + Assert.assertEquals( + "insertOrgInfoToElastic", ActorOperations.INSERT_ORG_INFO_ELASTIC.getValue()); + Assert.assertEquals("downlaodOrg", ActorOperations.DOWNLOAD_ORGS.getValue()); + Assert.assertEquals("blockUser", ActorOperations.BLOCK_USER.getValue()); + Assert.assertEquals("deleteByIdentifier", ActorOperations.DELETE_BY_IDENTIFIER.getValue()); + Assert.assertEquals("bulkUpload", ActorOperations.BULK_UPLOAD.getValue()); + Assert.assertEquals("processBulkUpload", ActorOperations.PROCESS_BULK_UPLOAD.getValue()); + Assert.assertEquals("assignRoles", ActorOperations.ASSIGN_ROLES.getValue()); + Assert.assertEquals("unblockUser", ActorOperations.UNBLOCK_USER.getValue()); + Assert.assertEquals("createBatch", ActorOperations.CREATE_BATCH.getValue()); + Assert.assertEquals("updateBatch", ActorOperations.UPDATE_BATCH.getValue()); + Assert.assertEquals("removeBatch", ActorOperations.REMOVE_BATCH.getValue()); + Assert.assertEquals("addUserBatch", ActorOperations.ADD_USER_TO_BATCH.getValue()); + Assert.assertEquals("removeUserFromBatch", ActorOperations.REMOVE_USER_FROM_BATCH.getValue()); + Assert.assertEquals("getBatch", ActorOperations.GET_BATCH.getValue()); + Assert.assertEquals("insertCourseBatchToEs", ActorOperations.INSERT_COURSE_BATCH_ES.getValue()); + Assert.assertEquals("updateCourseBatchToEs", ActorOperations.UPDATE_COURSE_BATCH_ES.getValue()); + Assert.assertEquals("getBulkOpStatus", ActorOperations.GET_BULK_OP_STATUS.getValue()); + Assert.assertEquals("orgCreationMetrics", ActorOperations.ORG_CREATION_METRICS.getValue()); + Assert.assertEquals( + "orgConsumptionMetrics", ActorOperations.ORG_CONSUMPTION_METRICS.getValue()); + Assert.assertEquals( + "orgCreationMetricsData", ActorOperations.ORG_CREATION_METRICS_DATA.getValue()); + Assert.assertEquals( + "courseProgressMetrics", ActorOperations.COURSE_PROGRESS_METRICS.getValue()); + Assert.assertEquals( + "courseConsumptionMetrics", ActorOperations.COURSE_CREATION_METRICS.getValue()); + Assert.assertEquals("userCreationMetrics", ActorOperations.USER_CREATION_METRICS.getValue()); + Assert.assertEquals( + "userConsumptionMetrics", ActorOperations.USER_CONSUMPTION_METRICS.getValue()); + Assert.assertEquals("getCourseBatchDetail", ActorOperations.GET_COURSE_BATCH_DETAIL.getValue()); + Assert.assertEquals("updateUserOrgES", ActorOperations.UPDATE_USER_ORG_ES.getValue()); + Assert.assertEquals("removeUserOrgES", ActorOperations.REMOVE_USER_ORG_ES.getValue()); + Assert.assertEquals("updateUserRoles", ActorOperations.UPDATE_USER_ROLES_ES.getValue()); + Assert.assertEquals("sync", ActorOperations.SYNC.getValue()); + Assert.assertEquals( + "insertUserCoursesInfoToElastic", + ActorOperations.INSERT_USR_COURSES_INFO_ELASTIC.getValue()); + Assert.assertEquals( + "updateUserCoursesInfoToElastic", + ActorOperations.UPDATE_USR_COURSES_INFO_ELASTIC.getValue()); + Assert.assertEquals("scheduleBulkUpload", ActorOperations.SCHEDULE_BULK_UPLOAD.getValue()); + Assert.assertEquals( + "courseProgressMetricsReport", ActorOperations.COURSE_PROGRESS_METRICS_REPORT.getValue()); + Assert.assertEquals( + "courseConsumptionMetricsReport", + ActorOperations.COURSE_CREATION_METRICS_REPORT.getValue()); + Assert.assertEquals( + "orgCreationMetricsReport", ActorOperations.ORG_CREATION_METRICS_REPORT.getValue()); + Assert.assertEquals( + "orgConsumptionMetricsReport", ActorOperations.ORG_CONSUMPTION_METRICS_REPORT.getValue()); + Assert.assertEquals("fileStorageService", ActorOperations.FILE_STORAGE_SERVICE.getValue()); + Assert.assertEquals("addUserBadgebackground", ActorOperations.ADD_USER_BADGE_BKG.getValue()); + Assert.assertEquals( + "fileGenerationAndUpload", ActorOperations.FILE_GENERATION_AND_UPLOAD.getValue()); + Assert.assertEquals("healthCheck", ActorOperations.HEALTH_CHECK.getValue()); + Assert.assertEquals("sendMail", ActorOperations.SEND_MAIL.getValue()); + Assert.assertEquals("processData", ActorOperations.PROCESS_DATA.getValue()); + Assert.assertEquals("actor", ActorOperations.ACTOR.getValue()); + Assert.assertEquals("cassandra", ActorOperations.CASSANDRA.getValue()); + Assert.assertEquals("es", ActorOperations.ES.getValue()); + Assert.assertEquals("ekstep", ActorOperations.EKSTEP.getValue()); + Assert.assertEquals("getOrgTypeList", ActorOperations.GET_ORG_TYPE_LIST.getValue()); + Assert.assertEquals("createOrgType", ActorOperations.CREATE_ORG_TYPE.getValue()); + Assert.assertEquals("updateOrgType", ActorOperations.UPDATE_ORG_TYPE.getValue()); + Assert.assertEquals("createNote", ActorOperations.CREATE_NOTE.getValue()); + Assert.assertEquals("updateNote", ActorOperations.UPDATE_NOTE.getValue()); + Assert.assertEquals("searchNote", ActorOperations.SEARCH_NOTE.getValue()); + Assert.assertEquals("getNote", ActorOperations.GET_NOTE.getValue()); + Assert.assertEquals("deleteNote", ActorOperations.DELETE_NOTE.getValue()); + Assert.assertEquals( + "insertUserNotesToElastic", ActorOperations.INSERT_USER_NOTES_ES.getValue()); + Assert.assertEquals("encryptUserData", ActorOperations.ENCRYPT_USER_DATA.getValue()); + Assert.assertEquals("decryptUserData", ActorOperations.DECRYPT_USER_DATA.getValue()); + Assert.assertEquals( + "updateUserNotesToElastic", ActorOperations.UPDATE_USER_NOTES_ES.getValue()); + Assert.assertEquals("userCurrentLogin", ActorOperations.USER_CURRENT_LOGIN.getValue()); + Assert.assertEquals("getMediaTypes", ActorOperations.GET_MEDIA_TYPES.getValue()); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/AuditLogTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/AuditLogTest.java new file mode 100644 index 0000000000..88309fb620 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/AuditLogTest.java @@ -0,0 +1,31 @@ +/** */ +package org.sunbird.common.models.util; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; + +/** @author Manzarul */ +public class AuditLogTest { + + @Test + public void createAuditLog() { + AuditLog log = new AuditLog(); + log.setDate("2017-12-29"); + log.setObjectId("objectId"); + log.setObjectType("User"); + log.setOperationType("create"); + log.setRequestId("requesterId"); + log.setUserId("userId"); + Map map = new HashMap<>(); + log.setLogRecord(map); + Assert.assertEquals("2017-12-29", log.getDate()); + Assert.assertEquals("objectId", log.getObjectId()); + Assert.assertEquals("User", log.getObjectType()); + Assert.assertEquals("create", log.getOperationType()); + Assert.assertEquals("requesterId", log.getRequestId()); + Assert.assertEquals("userId", log.getUserId()); + Assert.assertEquals(0, log.getLogRecord().size()); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/BaseHttpTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/BaseHttpTest.java new file mode 100644 index 0000000000..7d79aff5e7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/BaseHttpTest.java @@ -0,0 +1,82 @@ +package org.sunbird.common.models.util; + +import static org.powermock.api.mockito.PowerMockito.doThrow; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; +import static org.powermock.api.mockito.PowerMockito.whenNew; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import org.apache.http.impl.client.HttpClients; +import org.junit.Assert; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.util.KeycloakRequiredActionLinkUtil; +import org.sunbird.services.sso.impl.KeyCloakServiceImpl; + +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +@PrepareForTest({ + OutputStreamWriter.class, + URL.class, + BufferedReader.class, + HttpUtil.class, + HttpClients.class, + KeyCloakConnectionProvider.class, + KeyCloakServiceImpl.class, + KeycloakRequiredActionLinkUtil.class +}) +public abstract class BaseHttpTest { + + @Before + public void addMockRules() { + + mockHttpUrlResponse("content/v3/list", "not-empty-output"); + mockHttpUrlResponse("/search/health", "not-empty-output"); + mockHttpUrlResponse("/content/wrong/v3/list", null, true, null); + mockHttpUrlResponse("v1/issuer/issuers", "{\"message\":\"success\"}"); + mockHttpUrlResponse("https://dev.ekstep.in/api/data/v3", "{\"message\":\"success\"}"); + } + + protected void mockHttpUrlResponse(String urlContains, String outputExpected) { + mockHttpUrlResponse(urlContains, outputExpected, false, null); + } + + protected void mockHttpUrlResponse( + String urlContains, String outputExpected, boolean throwError, String paramContains) { + URL url = mock(URL.class); + HttpURLConnection connection = mock(HttpURLConnection.class); + OutputStream outStream = mock(OutputStream.class); + OutputStreamWriter outStreamWriter = mock(OutputStreamWriter.class); + InputStream inStream = mock(InputStream.class); + BufferedReader reader = mock(BufferedReader.class); + try { + + whenNew(URL.class).withArguments(Mockito.contains(urlContains)).thenReturn(url); + whenNew(OutputStreamWriter.class).withAnyArguments().thenReturn(outStreamWriter); + when(url.openConnection()).thenReturn(connection); + when(connection.getOutputStream()).thenReturn(outStream); + if (paramContains != null && throwError) { + doThrow(new FileNotFoundException()).when(outStreamWriter).write(Mockito.anyString()); + } + if (throwError) { + when(connection.getInputStream()).thenThrow(FileNotFoundException.class); + } else { + when(connection.getInputStream()).thenReturn(inStream); + } + whenNew(BufferedReader.class).withAnyArguments().thenReturn(reader); + when(reader.readLine()).thenReturn(outputExpected, null); + } catch (Exception e) { + Assert.fail("Mock rules addition failed " + e.getMessage()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/EmailTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/EmailTest.java new file mode 100644 index 0000000000..1d62d95fba --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/EmailTest.java @@ -0,0 +1,48 @@ +/** */ +package org.sunbird.common.models.util; + +import javax.mail.PasswordAuthentication; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.jvnet.mock_javamail.Mailbox; +import org.sunbird.common.models.util.mail.GMailAuthenticator; +import org.sunbird.common.models.util.mail.SendMail; + +/** @author Manzarul */ +public class EmailTest { + + private static GMailAuthenticator authenticator = null; + + @BeforeClass + public static void setUp() { + authenticator = new GMailAuthenticator("test123", "test"); + // clear Mock JavaMail box + Mailbox.clearAll(); + } + + @Test + public void createGmailAuthInstance() { + GMailAuthenticator authenticator = new GMailAuthenticator("test123", "test"); + Assert.assertNotEquals(null, authenticator); + } + + @Test + public void passwordAuthTest() { + PasswordAuthentication authentication = authenticator.getPasswordAuthentication(); + Assert.assertEquals("test", authentication.getPassword()); + } + + @Test + public void initialiseFromPropertyTest() { + SendMail.initialiseFromProperty(); + Assert.assertTrue(true); + } + + @AfterClass + public static void tearDown() { + authenticator = null; + Mailbox.clearAll(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ExcelFileUtilTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ExcelFileUtilTest.java new file mode 100644 index 0000000000..38e1078cfb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ExcelFileUtilTest.java @@ -0,0 +1,55 @@ +package org.sunbird.common.models.util; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +public class ExcelFileUtilTest { + + @Test + public void testWriteToFile() { + String fileName = "test"; + List> data = new ArrayList<>(); + List dataObjects = new ArrayList<>(); + dataObjects.add("test1"); + dataObjects.add(new ArrayList<>()); + dataObjects.add(1); + dataObjects.add(2.0D); + data.add(dataObjects); + ExcelFileUtil excelFileUtil = new ExcelFileUtil(); + File file = excelFileUtil.writeToFile(fileName, data); + String[] expectedFileName = StringUtils.split(file.getName(), '.'); + Assert.assertEquals("test", expectedFileName[0]); + Assert.assertEquals("xlsx", expectedFileName[1]); + } + + @Test + public void testgetFileUtil() { + FileUtil util = FileUtil.getFileUtil("Excel"); + Assert.assertNotNull(util); + } + + @Test + public void testgetListValue() { + List list = new ArrayList<>(); + list.add("column1"); + list.add("column2"); + String response = FileUtil.getListValue(list); + Assert.assertEquals("column1,column2", response); + list.clear(); + response = FileUtil.getListValue(list); + Assert.assertEquals("", response); + } + + @After + public void deleteFileGenerated() { + File file = new File("test.xlsx"); + if (file.exists()) { + file.delete(); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/HttpUtilTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/HttpUtilTest.java new file mode 100644 index 0000000000..a48d8fb6fc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/HttpUtilTest.java @@ -0,0 +1,135 @@ +package org.sunbird.common.models.util; + +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.HttpVersion; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicStatusLine; +import org.junit.Test; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.sunbird.common.util.KeycloakRequiredActionLinkUtil; + +public class HttpUtilTest extends BaseHttpTest { + public static final String JSON_STRING_DATA = "asdasasfasfsdfdsfdsfgsd"; + + @Test + public void testPostFormDataSuccess() { + Map reqData = new HashMap<>(); + reqData.put("field1", "value1"); + reqData.put("field2", "value2"); + + Map fileData = new HashMap<>(); + fileData.put("file1", ("asd".getBytes())); + + Map headers = new HashMap<>(); + headers.put("Authorization", "123456"); + String url = "http://localhost:8000/v1/issuer/issuers"; + try { + String response = (String) HttpUtil.postFormData(reqData, fileData, headers, url).getBody(); + assertTrue("{\"message\":\"success\"}".equals(response)); + } catch (IOException e) { + ProjectLogger.log(e.getMessage()); + } + } + + @Test + public void testSendPatchRequestSuccess() { + + Map headers = new HashMap<>(); + headers.put("Authorization", "123456"); + String url = "http://localhost:8000/v1/issuer/issuers"; + try { + CloseableHttpResponse closeableHttpResponseMock = + PowerMockito.mock(CloseableHttpResponse.class); + HttpEntity httpEntity = PowerMockito.mock(HttpEntity.class); + PowerMockito.when(closeableHttpResponseMock.getStatusLine()) + .thenReturn(new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "FINE!")); + + PowerMockito.when(closeableHttpResponseMock.getEntity()).thenReturn(httpEntity); + closeableHttpResponseMock.setEntity(httpEntity); + PowerMockito.when(closeableHttpResponseMock.getEntity()).thenReturn(httpEntity); + PowerMockito.when(closeableHttpResponseMock.getEntity().getContent()) + .thenReturn(new ByteArrayInputStream("{\"message\":\"success\"}".getBytes())); + + CloseableHttpClient closeableHttpClientMocked = PowerMockito.mock(CloseableHttpClient.class); + PowerMockito.mockStatic(HttpClients.class); + PowerMockito.when(HttpClients.createDefault()).thenReturn(closeableHttpClientMocked); + + PowerMockito.when(closeableHttpClientMocked.execute(Mockito.any(HttpPost.class))) + .thenReturn(closeableHttpResponseMock); + + String response = HttpUtil.sendPatchRequest(url, "{\"message\":\"success\"}", headers); + assertTrue("SUCCESS".equals(response)); + } catch (IOException e) { + ProjectLogger.log(e.getMessage()); + } + } + + @Test + public void testSendPostRequestSuccess() { + Map headers = new HashMap<>(); + headers.put("Authorization", "123456"); + String url = "http://localhost:8000/v1/issuer/issuers"; + try { + String response = HttpUtil.sendPostRequest(url, "{\"message\":\"success\"}", headers); + assertTrue("{\"message\":\"success\"}".equals(response)); + } catch (IOException e) { + ProjectLogger.log(e.getMessage()); + } + } + + @Test + public void testSendGetRequestSuccess() { + Map headers = new HashMap<>(); + headers.put("Authorization", "123456"); + String urlString = "http://localhost:8000/v1/issuer/issuers"; + try { + String response = HttpUtil.sendGetRequest(urlString, headers); + assertTrue("{\"message\":\"success\"}".equals(response)); + } catch (Exception e) { + ProjectLogger.log(e.getMessage()); + } + } + + @Test + public void testGetHeaderWithInput() throws Exception { + PowerMockito.mockStatic(KeycloakRequiredActionLinkUtil.class); + when(KeycloakRequiredActionLinkUtil.getAdminAccessToken()).thenReturn("testAuthToken"); + Map input = + new HashMap() { + { + put("x-channel-id", "test-channel"); + put("x-device-id", "test-device"); + } + }; + Map headers = HttpUtil.getHeader(input); + assertTrue(!headers.isEmpty()); + assertTrue(headers.size() == 4); + assertTrue(headers.containsKey("x-authenticated-user-token")); + assertTrue(headers.containsKey("Content-Type")); + assertTrue(headers.containsKey("x-channel-id")); + assertTrue(headers.containsKey("x-device-id")); + } + + @Test + public void testGetHeaderWithoutInput() throws Exception { + PowerMockito.mockStatic(KeycloakRequiredActionLinkUtil.class); + when(KeycloakRequiredActionLinkUtil.getAdminAccessToken()).thenReturn("testAuthToken"); + Map headers = HttpUtil.getHeader(null); + assertTrue(!headers.isEmpty()); + assertTrue(headers.size() == 2); + assertTrue(headers.containsKey("x-authenticated-user-token")); + assertTrue(headers.containsKey("Content-Type")); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ProjectUtilTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ProjectUtilTest.java new file mode 100644 index 0000000000..c397b59cf4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/ProjectUtilTest.java @@ -0,0 +1,469 @@ +package org.sunbird.common.models.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import java.util.TimeZone; +import org.apache.commons.lang3.StringUtils; +import org.apache.velocity.VelocityContext; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; + +/** Created by arvind on 6/10/17. */ +public class ProjectUtilTest extends BaseHttpTest { + + private PropertiesCache propertiesCache = ProjectUtil.propertiesCache; + + private static Map headers = new HashMap(); + + @BeforeClass + public static void init() { + headers.put("content-type", "application/json"); + headers.put("accept", "application/json"); + headers.put("user-id", "mahesh"); + String header = System.getenv(JsonKey.EKSTEP_AUTHORIZATION); + if (StringUtils.isBlank(header)) { + header = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION); + } + headers.put("authorization", "Bearer " + header); + } + + @Ignore + public void testGetContextFailureWithNameAbsent() { + + Map templateMap = new HashMap<>(); + templateMap.put(JsonKey.ACTION_URL, "googli.com"); + + VelocityContext context = ProjectUtil.getContext(templateMap); + assertEquals(false, context.internalContainsKey(JsonKey.NAME)); + } + + @Test + public void testGetContextFailureWithoutActionUrl() { + + Map templateMap = new HashMap<>(); + templateMap.put(JsonKey.NAME, "userName"); + + VelocityContext context = ProjectUtil.getContext(templateMap); + assertEquals(false, context.internalContainsKey(JsonKey.ACTION_URL)); + } + + @Test + public void testGetContextSuccessWithFromMail() { + + Map templateMap = new HashMap<>(); + templateMap.put(JsonKey.ACTION_URL, "googli.com"); + templateMap.put(JsonKey.NAME, "userName"); + + boolean envVal = !StringUtils.isBlank(System.getenv(JsonKey.EMAIL_SERVER_FROM)); + boolean cacheVal = propertiesCache.getProperty(JsonKey.EMAIL_SERVER_FROM) != null; + + VelocityContext context = ProjectUtil.getContext(templateMap); + if (envVal) { + assertEquals( + System.getenv(JsonKey.EMAIL_SERVER_FROM), context.internalGet(JsonKey.FROM_EMAIL)); + } else if (cacheVal) { + assertEquals( + propertiesCache.getProperty(JsonKey.EMAIL_SERVER_FROM), + context.internalGet(JsonKey.FROM_EMAIL)); + } + } + + @Test + public void testGetContextSuccessWithOrgImageUrl() { + + Map templateMap = new HashMap<>(); + templateMap.put(JsonKey.ACTION_URL, "googli.com"); + templateMap.put(JsonKey.NAME, "userName"); + + boolean envVal = !StringUtils.isBlank(System.getenv(JsonKey.SUNBIRD_ENV_LOGO_URL)); + boolean cacheVal = propertiesCache.getProperty(JsonKey.SUNBIRD_ENV_LOGO_URL) != null; + + VelocityContext context = ProjectUtil.getContext(templateMap); + if (envVal) { + assertEquals( + System.getenv(JsonKey.SUNBIRD_ENV_LOGO_URL), context.internalGet(JsonKey.ORG_IMAGE_URL)); + } else if (cacheVal) { + assertEquals( + propertiesCache.getProperty(JsonKey.SUNBIRD_ENV_LOGO_URL), + context.internalGet(JsonKey.ORG_IMAGE_URL)); + } + } + + @Test + public void testCreateAuthTokenSuccess() { + String authToken = ProjectUtil.createAuthToken("test", "tset1234"); + assertNotNull(authToken); + } + + @Test + public void testValidatePhoneNumberFailureWithInvalidPhoneNumber() { + assertFalse(ProjectUtil.validatePhoneNumber("312")); + } + + @Test + public void testValidatePhoneNumberSuccess() { + assertTrue(ProjectUtil.validatePhoneNumber("9844016699")); + } + + @Test + public void testGenerateRandomPasswordSuccess() { + assertNotNull(ProjectUtil.generateRandomPassword()); + } + + @Test + public void testCreateCheckResponseSuccess() { + Map responseMap = + ProjectUtil.createCheckResponse("LearnerService", false, null); + assertEquals(true, responseMap.get(JsonKey.Healthy)); + } + + @Test + public void testCreateCheckResponseFailureWithException() { + Map responseMap = + ProjectUtil.createCheckResponse( + "LearnerService", + true, + new ProjectCommonException( + ResponseCode.invalidObjectType.getErrorCode(), + ResponseCode.invalidObjectType.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode())); + assertEquals(false, responseMap.get(JsonKey.Healthy)); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), responseMap.get(JsonKey.ERROR)); + assertEquals( + ResponseCode.invalidObjectType.getErrorMessage(), responseMap.get(JsonKey.ERRORMSG)); + } + + @Ignore + public void testSetRequestSuccessWithLowerCaseValues() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SOURCE, "Test"); + requestObj.put(JsonKey.LOGIN_ID, "SunbirdUser"); + requestObj.put(JsonKey.EXTERNAL_ID, "testExternal"); + requestObj.put(JsonKey.USER_NAME, "username"); + requestObj.put(JsonKey.USERNAME, "userName"); + requestObj.put(JsonKey.PROVIDER, "Provider"); + requestObj.put(JsonKey.ID, "TEST123"); + request.setRequest(requestObj); + assertEquals("test", requestObj.get(JsonKey.SOURCE)); + assertEquals("sunbirduser", requestObj.get(JsonKey.LOGIN_ID)); + assertEquals("testexternal", requestObj.get(JsonKey.EXTERNAL_ID)); + assertEquals("username", requestObj.get(JsonKey.USER_NAME)); + assertEquals("username", requestObj.get(JsonKey.USERNAME)); + assertEquals("provider", requestObj.get(JsonKey.PROVIDER)); + assertEquals("TEST123", requestObj.get(JsonKey.ID)); + } + + @Test + public void testFormatMessageSuccess() { + String msg = ProjectUtil.formatMessage("Hello {0}", "user"); + assertEquals("Hello user", msg); + } + + @Test + public void testFormatMessageFailureWithInvalidVariable() { + String msg = ProjectUtil.formatMessage("Hello ", "user"); + assertNotEquals("Hello user", msg); + } + + @Test + public void testIsEmailValidFailureWithWrongEmail() { + boolean msg = ProjectUtil.isEmailvalid("Hello "); + assertFalse(msg); + } + + @Test + public void testIsDateValidFormatSuccess() { + boolean bool = ProjectUtil.isDateValidFormat("yyyy-MM-dd", "2017-12-18"); + assertTrue(bool); + } + + @Test + public void testIsDateValidFormatFailureWithEmptyDate() { + boolean bool = ProjectUtil.isDateValidFormat("yyyy-MM-dd", ""); + assertFalse(bool); + } + + @Test + public void testIsDateValidFormatFailureWithInvalidDate() { + boolean bool = ProjectUtil.isDateValidFormat("yyyy-MM-dd", "2017-12-18"); + assertTrue(bool); + } + + @Test + public void testIsDateValidFormatFailureWithEmptyDateTime() { + boolean bool = ProjectUtil.isDateValidFormat("yyyy-MM-dd HH:mm:ss:SSSZ", ""); + assertFalse(bool); + } + + @Test + public void testGetEkstepHeaderSuccess() { + Map map = ProjectUtil.getEkstepHeader(); + assertEquals(map.get("Content-Type"), "application/json"); + assertNotNull(map.get(JsonKey.AUTHORIZATION)); + } + + @Test + public void testRegisterTagSuccess() { + String response = null; + try { + response = ProjectUtil.registertag("testTag", "{}", ProjectUtil.getEkstepHeader()); + } catch (IOException e) { + + } + assertNotNull(response); + } + + @Test + public void testReportTrackingStatusSuccess() { + assertEquals(0, ProjectUtil.ReportTrackingStatus.NEW.getValue()); + assertEquals(1, ProjectUtil.ReportTrackingStatus.GENERATING_DATA.getValue()); + assertEquals(2, ProjectUtil.ReportTrackingStatus.UPLOADING_FILE.getValue()); + assertEquals(3, ProjectUtil.ReportTrackingStatus.UPLOADING_FILE_SUCCESS.getValue()); + assertEquals(4, ProjectUtil.ReportTrackingStatus.SENDING_MAIL.getValue()); + assertEquals(5, ProjectUtil.ReportTrackingStatus.SENDING_MAIL_SUCCESS.getValue()); + assertEquals(9, ProjectUtil.ReportTrackingStatus.FAILED.getValue()); + } + + @Test + public void testEsTypeSuccess() { + assertEquals("content", ProjectUtil.EsType.content.getTypeName()); + assertEquals("cbatch", ProjectUtil.EsType.course.getTypeName()); + assertEquals("course-batch", ProjectUtil.EsType.courseBatch.getTypeName()); + assertEquals("user", ProjectUtil.EsType.user.getTypeName()); + assertEquals("org", ProjectUtil.EsType.organisation.getTypeName()); + assertEquals("user-courses", ProjectUtil.EsType.usercourses.getTypeName()); + assertEquals("usernotes", ProjectUtil.EsType.usernotes.getTypeName()); + assertEquals("userprofilevisibility", ProjectUtil.EsType.userprofilevisibility.getTypeName()); + } + + @Test + public void testEsIndexSuccess() { + assertEquals("searchindex", ProjectUtil.EsIndex.sunbird.getIndexName()); + } + + @Test + public void testUserRoleSuccess() { + assertEquals("PUBLIC", ProjectUtil.UserRole.PUBLIC.getValue()); + assertEquals("CONTENT_CREATOR", ProjectUtil.UserRole.CONTENT_CREATOR.getValue()); + assertEquals("CONTENT_REVIEWER", ProjectUtil.UserRole.CONTENT_REVIEWER.getValue()); + assertEquals("ORG_ADMIN", ProjectUtil.UserRole.ORG_ADMIN.getValue()); + assertEquals("ORG_MEMBER", ProjectUtil.UserRole.ORG_MEMBER.getValue()); + } + + @Test + public void testBulkProcessStatusSuccess() { + assertEquals(0, ProjectUtil.BulkProcessStatus.NEW.getValue()); + assertEquals(1, ProjectUtil.BulkProcessStatus.IN_PROGRESS.getValue()); + assertEquals(2, ProjectUtil.BulkProcessStatus.INTERRUPT.getValue()); + assertEquals(3, ProjectUtil.BulkProcessStatus.COMPLETED.getValue()); + assertEquals(9, ProjectUtil.BulkProcessStatus.FAILED.getValue()); + } + + @Test + public void testOrgStatusSuccess() { + assertEquals(new Integer(0), ProjectUtil.OrgStatus.INACTIVE.getValue()); + assertEquals(new Integer(1), ProjectUtil.OrgStatus.ACTIVE.getValue()); + assertEquals(new Integer(2), ProjectUtil.OrgStatus.BLOCKED.getValue()); + assertEquals(new Integer(3), ProjectUtil.OrgStatus.RETIRED.getValue()); + } + + @Test + public void testCourseMgmtStatusSuccess() { + assertEquals("draft", ProjectUtil.CourseMgmtStatus.DRAFT.getValue()); + assertEquals("live", ProjectUtil.CourseMgmtStatus.LIVE.getValue()); + assertEquals("retired", ProjectUtil.CourseMgmtStatus.RETIRED.getValue()); + } + + @Test + public void testProgressStatusSuccess() { + assertEquals(0, ProjectUtil.ProgressStatus.NOT_STARTED.getValue()); + assertEquals(1, ProjectUtil.ProgressStatus.STARTED.getValue()); + assertEquals(2, ProjectUtil.ProgressStatus.COMPLETED.getValue()); + } + + @Test + public void testEnvironmentSuccess() { + assertEquals(1, ProjectUtil.Environment.dev.getValue()); + assertEquals(2, ProjectUtil.Environment.qa.getValue()); + assertEquals(3, ProjectUtil.Environment.prod.getValue()); + } + + @Test + public void testObjectTypesSuccess() { + assertEquals("batch", ProjectUtil.ObjectTypes.batch.getValue()); + assertEquals("user", ProjectUtil.ObjectTypes.user.getValue()); + assertEquals("organisation", ProjectUtil.ObjectTypes.organisation.getValue()); + } + + @Test + public void testSourceSuccess() { + assertEquals("web", ProjectUtil.Source.WEB.getValue()); + assertEquals("android", ProjectUtil.Source.ANDROID.getValue()); + assertEquals("ios", ProjectUtil.Source.IOS.getValue()); + } + + @Test + public void testSectionDataTypeSuccess() { + assertEquals("course", ProjectUtil.SectionDataType.course.getTypeName()); + assertEquals("content", ProjectUtil.SectionDataType.content.getTypeName()); + } + + @Test + public void testStatusSuccess() { + assertEquals(1, ProjectUtil.Status.ACTIVE.getValue()); + assertEquals(0, ProjectUtil.Status.INACTIVE.getValue()); + assertEquals(false, ProjectUtil.ActiveStatus.INACTIVE.getValue()); + assertEquals(true, ProjectUtil.ActiveStatus.ACTIVE.getValue()); + assertEquals("orgimg", ProjectUtil.AzureContainer.orgImage.getName()); + assertEquals("userprofileimg", ProjectUtil.AzureContainer.userProfileImg.getName()); + } + + @Test + public void testCreateAndThrowServerErrorSuccess() { + try { + ProjectUtil.createAndThrowServerError(); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.SERVER_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.SERVER_ERROR.getErrorCode(), e.getCode()); + } + } + + @Test + public void testCreateAndThrowInvalidUserDataExceptionSuccess() { + try { + ProjectUtil.createAndThrowInvalidUserDataException(); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidUsrData.getErrorCode(), e.getCode()); + } + } + + @Test + public void testGetDateRangeSuccess() { + int noOfDays = 7; + Map map = ProjectUtil.getDateRange(noOfDays); + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + cal.add(Calendar.DATE, -noOfDays); + assertEquals(map.get("startDate"), new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime())); + cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + cal.add(Calendar.DATE, -1); + assertEquals(map.get("endDate"), new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime())); + } + + @Test + public void testGetDateRangeFailure() { + int noOfDays = 14; + Map map = ProjectUtil.getDateRange(noOfDays); + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + cal.add(Calendar.DATE, -noOfDays); + assertEquals(map.get("startDate"), new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime())); + cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + cal.add(Calendar.DATE, noOfDays); + assertNotEquals(map.get("endDate"), new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime())); + } + + @Test + public void testGetDateRangeFailureWithZeroDays() { + int noOfDays = 0; + Map map = ProjectUtil.getDateRange(noOfDays); + assertNull(map.get("startDate")); + assertNull(map.get("endDate")); + } + + @Test + public void testGetDateRangeFailureWithNegativeValue() { + int noOfDays = -100; + Map map = ProjectUtil.getDateRange(noOfDays); + assertNull(map.get("startDate")); + assertNull(map.get("endDate")); + } + + @Test + public void testIsEmailValidFailureWithInvalidFormat() { + boolean bool = ProjectUtil.isEmailvalid("amit.kumartarento.com"); + Assert.assertFalse(bool); + } + + @Test + public void testIsEmailValidSuccess() { + boolean bool = ProjectUtil.isEmailvalid("amit.kumar@tarento.com"); + assertTrue(bool); + } + + @Test + public void testSendGetRequestSuccessWithEkStepBaseUrl() throws Exception { + String ekStepBaseUrl = System.getenv(JsonKey.EKSTEP_BASE_URL); + if (StringUtils.isBlank(ekStepBaseUrl)) { + ekStepBaseUrl = PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_BASE_URL); + } + String response = HttpUtil.sendGetRequest(ekStepBaseUrl + "/search/health", headers); + assertNotNull(response); + } + + @Test + public void testGetLmsUserIdSuccessWithoutFedUserId() { + String userid = ProjectUtil.getLmsUserId("1234567890"); + assertEquals("1234567890", userid); + } + + @Test + public void testGetLmsUserIdSuccessWithFedUserId() { + String userid = + ProjectUtil.getLmsUserId( + "f:" + + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_KEYCLOAK_USER_FEDERATION_PROVIDER_ID) + + ":" + + "1234567890"); + assertEquals("1234567890", userid); + } + + @Test + public void testMigrateActionAcceptValueFailure() { + Assert.assertNotEquals("ok", ProjectUtil.MigrateAction.ACCEPT.getValue()); + } + + @Test + public void testMigrateActionRejectValueFailure() { + Assert.assertNotEquals("no", ProjectUtil.MigrateAction.REJECT.getValue()); + } + + @Test + public void testMigrateActionAcceptValueSuccess() { + Assert.assertEquals("accept", ProjectUtil.MigrateAction.ACCEPT.getValue()); + } + + @Test + public void testMigrateActionRejectValueSuccess() { + Assert.assertEquals("reject", ProjectUtil.MigrateAction.REJECT.getValue()); + } + + @Test + public void testValidateCountryCode() { + boolean isValid = ProjectUtil.validateCountryCode("+91"); + assertTrue(isValid); + isValid = ProjectUtil.validateCountryCode("9a"); + assertFalse(isValid); + } + + @Test + public void testValidateUUID() { + boolean isValid = ProjectUtil.validateUUID("1df03f56-ceba-4f2d-892c-2b1609e7b05f"); + assertTrue(isValid); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/SlugTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/SlugTest.java new file mode 100644 index 0000000000..e5b8196628 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/SlugTest.java @@ -0,0 +1,26 @@ +package org.sunbird.common.models.util; + +import org.junit.Assert; +import org.junit.Test; + +public class SlugTest { + + @Test + public void createSlugWithNullValue() { + String slug = Slug.makeSlug(null, true); + Assert.assertEquals(null, slug); + } + + @Test + public void createSlug() { + String val = "NTP@#Test"; + String slug = Slug.makeSlug(val, true); + Assert.assertEquals("ntptest", slug); + } + + @Test + public void removeDuplicateChar() { + String val = Slug.removeDuplicateChars("ntpntest"); + Assert.assertEquals("ntpes", val); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/URLShortnerImplTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/URLShortnerImplTest.java new file mode 100644 index 0000000000..bec50deaf3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/URLShortnerImplTest.java @@ -0,0 +1,32 @@ +package org.sunbird.common.models.util; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.util.url.URLShortner; +import org.sunbird.common.models.util.url.URLShortnerImpl; + +public class URLShortnerImplTest { + + @Test + public void urlShortTest() { + URLShortner shortner = new URLShortnerImpl(); + String url = shortner.shortUrl("https://staging.open-sunbird.org/"); + Assert.assertNotNull(url); + } + + @Test + public void getShortUrlTest() { + + String SUNBIRD_WEB_URL = "sunbird_web_url"; + + String webUrl = System.getenv(SUNBIRD_WEB_URL); + if (StringUtils.isBlank(webUrl)) { + webUrl = PropertiesCache.getInstance().getProperty(SUNBIRD_WEB_URL); + } + + URLShortnerImpl shortnerImpl = new URLShortnerImpl(); + String url = shortnerImpl.getUrl(); + Assert.assertEquals(url, webUrl); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/azure/AzureServiceFactoryTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/azure/AzureServiceFactoryTest.java new file mode 100644 index 0000000000..f51ff5845c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/azure/AzureServiceFactoryTest.java @@ -0,0 +1,176 @@ +/** */ +package org.sunbird.common.models.util.azure; + +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import com.microsoft.azure.storage.CloudStorageAccount; +import com.microsoft.azure.storage.blob.CloudBlobClient; +import com.microsoft.azure.storage.blob.CloudBlobContainer; +import com.microsoft.azure.storage.blob.ListBlobItem; +import java.io.File; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +/** @author Manzarul */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CloudStorageAccount.class, + CloudBlobClient.class, + CloudBlobContainer.class, + ListBlobItem.class +}) +@PowerMockIgnore({ + "javax.management.*", + "javax.net.ssl.*", + "javax.security.*", + "com.microsoft.azure.storage.*" +}) +public class AzureServiceFactoryTest { + + private static Object obj = null; + private static CloudBlobContainer container = null; + private static CloudBlobContainer container1 = null; + private static String containerName = "testcontainerxyz"; + + @BeforeClass + public static void getObject() { + obj = CloudServiceFactory.get("Azure"); + Assert.assertTrue(obj instanceof CloudService); + Assert.assertNotNull(obj); + } + + @Before + public void addMockRules() { + CloudStorageAccount cloudStorageAccount = mock(CloudStorageAccount.class); + CloudBlobClient cloudBlobClient = mock(CloudBlobClient.class); + CloudBlobContainer cloudBlobContainer = mock(CloudBlobContainer.class); + + ListBlobItem listBlobItem = mock(ListBlobItem.class); + List lst = new ArrayList<>(); + lst.add(listBlobItem); + PowerMockito.mockStatic(CloudStorageAccount.class); + try { + doReturn(cloudStorageAccount).when(CloudStorageAccount.class, "parse", Mockito.anyString()); + doReturn(cloudBlobClient).when(cloudStorageAccount).createCloudBlobClient(); + doReturn(cloudBlobContainer).when(cloudBlobClient).getContainerReference(Mockito.anyString()); + doReturn(true).when(cloudBlobContainer).exists(); + when(cloudBlobContainer.listBlobs()).thenReturn(lst); + when(listBlobItem.getUri()).thenReturn(new URI("http://www.google.com")); + + } catch (Exception e) { + Assert.fail("Could not initalize mocks, underlying reason " + e.getLocalizedMessage()); + } + } + + @Test + public void testGetFailureWithWrongType() { + Object obj = CloudServiceFactory.get("Azure12"); + Assert.assertNull(obj); + } + + @Test + public void testGetSuccess() { + Object obj1 = CloudServiceFactory.get("Azure"); + Assert.assertNotNull(obj1); + Assert.assertTrue(obj.equals(obj1)); + } + + @Test + public void testGetContainerSuccessWithAccessPublic() { + container = AzureConnectionManager.getContainer(containerName, true); + Assert.assertNotNull(container); + } + + @Test + public void testGetContainerReferenceSuccess() { + container1 = AzureConnectionManager.getContainerReference(containerName); + Assert.assertNotNull(container1); + } + + @Test + public void testUploadFileSuccess() { + CloudService service = (CloudService) obj; + String url = service.uploadFile(containerName, new File("test.txt")); + Assert.assertEquals(null, url); + } + + @Test + public void testUploadFileFailureWithoutContainerName() { + CloudService service = (CloudService) obj; + String url = service.uploadFile("", new File("test.txt")); + Assert.assertEquals(null, url); + } + + @Test + public void testUploadFileSuccessWithMultiplePath() { + CloudService service = (CloudService) obj; + String url = service.uploadFile("/tez/po/" + containerName, new File("test.txt")); + Assert.assertEquals(null, url); + } + + @Test + public void testUploadFileSuccessWithFileLocation() { + CloudService service = (CloudService) obj; + String url = service.uploadFile(containerName, "test.txt", ""); + Assert.assertEquals(null, url); + } + + @Test + public void testListAllFilesSuccess() { + CloudService service = (CloudService) obj; + List filesList = service.listAllFiles(containerName); + Assert.assertEquals(1, filesList.size()); + } + + @Test + public void testDownloadFileSuccess() { + CloudService service = (CloudService) obj; + Boolean isFileDeleted = service.downLoadFile(containerName, "test1.txt", ""); + Assert.assertFalse(isFileDeleted); + } + + @Test + public void testDeleteFileSuccess() { + CloudService service = (CloudService) obj; + Boolean isFileDeleted = service.deleteFile(containerName, "test1.txt"); + Assert.assertFalse(isFileDeleted); + } + + @Test + public void testDeleteFileSuccessWithoutContainerName() { + CloudService service = (CloudService) obj; + Boolean isFileDeleted = service.deleteFile("", "test.abc"); + Assert.assertFalse(isFileDeleted); + } + + @Test + public void testDeleteContainerSuccess() { + CloudService service = (CloudService) obj; + boolean response = service.deleteContainer(containerName); + Assert.assertTrue(response); + } + + @AfterClass + public static void shutDown() { + container1 = null; + container = null; + obj = null; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/EncryptionDecriptionServiceTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/EncryptionDecriptionServiceTest.java new file mode 100644 index 0000000000..d6af627891 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/EncryptionDecriptionServiceTest.java @@ -0,0 +1,252 @@ +package org.sunbird.common.models.util.datasecurity.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; + +/** @author Amit Kumar */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class EncryptionDecriptionServiceTest { + + private static String data = "hello sunbird"; + private static String encryptedData = ""; + private static String decryptedData = ""; + private static EncryptionService encryptionService = null; + private static DecryptionService decryptionService = null; + private static DataMaskingService maskingService = null; + private static Map map = null; + private static List> mapList = null; + private static Map map2 = null; + private static List> mapList2 = null; + private static String sunbirdEncryption = ""; + + @BeforeClass + public static void setUp() { + sunbirdEncryption = System.getenv(JsonKey.SUNBIRD_ENCRYPTION); + if (StringUtils.isBlank(sunbirdEncryption)) { + sunbirdEncryption = PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_ENCRYPTION); + } + map = new HashMap<>(); + map.put(JsonKey.FIRST_NAME, "Amit"); + map.put(JsonKey.LAST_NAME, "KUMAR"); + mapList = new ArrayList<>(); + mapList.add(map); + map2 = new HashMap<>(); + map2.put(JsonKey.EMAIL, "amit.ec006@gmail.com"); + map2.put(JsonKey.FIRST_NAME, "Amit"); + map2.put(JsonKey.LAST_NAME, "KUMAR"); + mapList2 = new ArrayList<>(); + mapList2.add(map2); + encryptionService = ServiceFactory.getEncryptionServiceInstance(null); + decryptionService = ServiceFactory.getDecryptionServiceInstance(null); + maskingService = ServiceFactory.getMaskingServiceInstance(null); + try { + encryptedData = encryptionService.encryptData(data); + decryptedData = decryptionService.decryptData(encryptedData); + } catch (Exception e) { + } + } + + @Test + public void testDataDecryptionFrMap() { + try { + assertEquals( + decryptionService + .decryptData(encryptionService.encryptData(map2)) + .get(JsonKey.FIRST_NAME), + "Amit"); + } catch (Exception e) { + } + } + + @Test + public void testDataDecryptionFrMapWithNullValue() { + try { + map2.put(JsonKey.LOCATION, null); + assertEquals( + decryptionService.decryptData(encryptionService.encryptData(map2)).get(JsonKey.LOCATION), + null); + } catch (Exception e) { + } + } + + @Test + public void testDataDecryptionFrMapWithEmptyValue() { + try { + map2.put(JsonKey.LOCATION, ""); + assertEquals( + decryptionService.decryptData(encryptionService.encryptData(map2)).get(JsonKey.LOCATION), + ""); + } catch (Exception e) { + } + } + + @Test + public void testDataDecryptionFrMapWithMapList() { + try { + map2.put(JsonKey.LOCATION, ""); + assertEquals( + decryptionService + .decryptData(encryptionService.encryptData(mapList2)) + .get(0) + .get(JsonKey.LOCATION), + ""); + } catch (Exception e) { + } + } + + @Test + public void testDataEncryptionFrMap() { + try { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + assertNotEquals(encryptionService.encryptData(map).get(JsonKey.FIRST_NAME), "Amit"); + } + } catch (Exception e) { + } + } + + @Test + public void testDataEncryptionFrListMap() { + try { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + assertNotEquals( + encryptionService.encryptData(mapList).get(0).get(JsonKey.FIRST_NAME), "Amit"); + } + } catch (Exception e) { + } + } + + @Test + public void testDataEncryptionFrMapWithNullValue() { + try { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + map.put(JsonKey.LAST_NAME, null); + assertEquals(encryptionService.encryptData(map).get(JsonKey.LAST_NAME), null); + } + } catch (Exception e) { + } + } + + @Test + public void testDataEncryptionFrMapWithEmptyValue() { + try { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + map.put(JsonKey.LAST_NAME, ""); + assertNotEquals(encryptionService.encryptData(map).get(JsonKey.LAST_NAME), ""); + } + } catch (Exception e) { + } + } + + @Test + public void testDataEncryption() { + try { + assertEquals(encryptedData, encryptionService.encryptData(data)); + } catch (Exception e) { + } + } + + @Test + public void testDataDecryption() { + try { + assertEquals(decryptedData, decryptionService.decryptData(encryptedData)); + } catch (Exception e) { + } + } + + @Test + public void testADataEncryption() { + try { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + assertNotEquals("Hello", encryptionService.encryptData("Hello")); + } else { + assertEquals("Hello", encryptionService.encryptData("Hello")); + } + } catch (Exception e) { + } + } + + @Test + public void testADataDecryption() { + try { + assertEquals("Hello", decryptionService.decryptData(encryptionService.encryptData("Hello"))); + } catch (Exception e) { + } + } + + @Test + public void testBDataDecryption() { + try { + if (JsonKey.ON.equalsIgnoreCase(sunbirdEncryption)) { + assertNotEquals( + encryptionService.encryptData("Hello"), + decryptionService.decryptData(encryptionService.encryptData("Hello"))); + } + } catch (Exception e) { + } + } + + @Test + public void testEmptyPhoneMasking() { + assertEquals(maskingService.maskPhone(""), ""); + } + + @Test + public void testNullPhoneMasking() { + assertEquals(maskingService.maskPhone(null), null); + } + + @Test + public void testPhoneMasking() { + assertEquals(maskingService.maskPhone("1234567890"), "******7890"); + } + + @Test + public void testEmptyEmailMasking() { + assertEquals(maskingService.maskEmail(""), ""); + } + + @Test + public void testNullEmailMasking() { + assertEquals(maskingService.maskEmail(null), null); + } + + @Test + public void testEmailMasking() { + assertEquals(maskingService.maskEmail("amit.ec006@gmail.com"), "am********@gmail.com"); + } + + @Test + public void testEmptyDataMasking() { + assertEquals(maskingService.maskData(""), ""); + } + + @Test + public void testNullDataMasking() { + assertEquals(maskingService.maskData(null), null); + } + + @Test + public void testDataMasking() { + assertEquals(maskingService.maskData("qwerty"), "**erty"); + } + + @Test + public void testDataOfLengthLessThanEqualTo4Masking() { + assertEquals(maskingService.maskData("qwer"), "qwer"); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/LogMaskServiceImplTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/LogMaskServiceImplTest.java new file mode 100644 index 0000000000..780e1b668f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/LogMaskServiceImplTest.java @@ -0,0 +1,60 @@ +package org.sunbird.common.models.util.datasecurity.impl; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import org.junit.Test; + +public class LogMaskServiceImplTest { + private LogMaskServiceImpl logMaskService = new LogMaskServiceImpl(); + + @Test + public void maskEmail() { + HashMap emailMaskExpectations = + new HashMap() { + { + put("abc@gmail.com", "ab*@gmail.com"); + put("abcd@yahoo.com", "ab**@yahoo.com"); + put("abcdefgh@testmail.org", "abcd****@testmail.org"); + } + }; + emailMaskExpectations.forEach( + (email, expectedResult) -> { + assertEquals(expectedResult, logMaskService.maskEmail(email)); + }); + } + + @Test + public void maskPhone() { + HashMap phoneMaskExpectations = + new HashMap() { + { + put("0123456789", "012345678*"); + put("123-456-789", "123-456-7**"); + put("123", "123"); + } + }; + phoneMaskExpectations.forEach( + (phone, expectedResult) -> { + assertEquals(expectedResult, logMaskService.maskPhone(phone)); + }); + } + + @Test + public void maskOTP() { + HashMap phoneMaskExpectations = + new HashMap() { + { + put("123456", "12345*"); + put("1234567", "12345**"); + + put("1234", "123*"); + put("123", "123"); + } + }; + phoneMaskExpectations.forEach( + (otp, expectedResult) -> { + assertEquals(expectedResult, logMaskService.maskOTP(otp)); + }); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/OnWayhashingTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/OnWayhashingTest.java new file mode 100644 index 0000000000..3af48865a7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/datasecurity/impl/OnWayhashingTest.java @@ -0,0 +1,30 @@ +/** */ +package org.sunbird.common.models.util.datasecurity.impl; + +import static org.junit.Assert.assertEquals; + +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.util.datasecurity.OneWayHashing; + +/** @author Manzarul */ +public class OnWayhashingTest { + public static String data = "test1234$5"; + + @Test + public void validateDataHashingSuccess() { + String encryptval = OneWayHashing.encryptVal("test1234$5"); + Assert.assertNotEquals(encryptval.length(), 0); + assertEquals(encryptval, OneWayHashing.encryptVal(data)); + } + + @Test + public void validateDataHashingFailure() { + assertEquals(OneWayHashing.encryptVal(null).length(), 0); + } + + @Test + public void validateDataHashingWithEmptyKey() { + Assert.assertNotEquals((OneWayHashing.encryptVal("")).length(), 0); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/fcm/FCMNotificationTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/fcm/FCMNotificationTest.java new file mode 100644 index 0000000000..39a661cc07 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/models/util/fcm/FCMNotificationTest.java @@ -0,0 +1,127 @@ +/** */ +package org.sunbird.common.models.util.fcm; + +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; +import static org.powermock.api.mockito.PowerMockito.whenNew; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.http.impl.client.HttpClients; +import org.junit.Assert; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.AdditionalMatchers; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; + +/** + * Test cases for FCM notification service. + * + * @author Manzarul + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + HttpClients.class, + URL.class, + BufferedReader.class, + HttpUtil.class, + System.class, + Notification.class +}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class FCMNotificationTest { + + @Test + public void testSendNotificationSuccessWithListAndStringData() { + Map map = new HashMap<>(); + map.put("title", "some title"); + map.put("summary", "some value"); + List list = new ArrayList<>(); + list.add("test12"); + list.add("test45"); + map.put("extra", list); + Map innerMap = new HashMap<>(); + innerMap.put("title", "some value"); + innerMap.put("link", "https://google.com"); + map.put("map", innerMap); + + String val = Notification.sendNotification("nameOFTopic", map, Notification.FCM_URL); + Assert.assertNotEquals(JsonKey.FAILURE, val); + } + + @Test + public void testSendNotificationSuccessWithStringData() { + Map map = new HashMap<>(); + map.put("title", "some title"); + map.put("summary", "some value"); + String val = Notification.sendNotification("nameOFTopic", map, Notification.FCM_URL); + Assert.assertNotEquals(JsonKey.FAILURE, val); + } + + @Test + public void testSendNotificationFailureWithEmptyFcmUrl() { + Map map = new HashMap<>(); + map.put("title", "some title"); + map.put("summary", "some value"); + String val = Notification.sendNotification("nameOFTopic", map, ""); + Assert.assertEquals(JsonKey.FAILURE, val); + } + + @Test + public void testSendNotificationFailureWithNullData() { + Map map = null; + String val = Notification.sendNotification("nameOFTopic", map, ""); + Assert.assertEquals(JsonKey.FAILURE, val); + } + + @Test + public void testSendNotificationFailureWithEmptyTopic() { + Map map = new HashMap<>(); + map.put("title", "some title"); + map.put("summary", "some value"); + String val = Notification.sendNotification("", map, ""); + Assert.assertEquals(JsonKey.FAILURE, val); + } + + @Before + public void addMockRules() { + PowerMockito.mockStatic(System.class); + URL url = mock(URL.class); + HttpURLConnection connection = mock(HttpURLConnection.class); + OutputStream outStream = mock(OutputStream.class); + InputStream inStream = mock(InputStream.class); + BufferedReader reader = mock(BufferedReader.class); + try { + when(System.getenv(JsonKey.SUNBIRD_FCM_ACCOUNT_KEY)).thenReturn("FCM_KEY"); + when(System.getenv(AdditionalMatchers.not(Mockito.eq(JsonKey.SUNBIRD_FCM_ACCOUNT_KEY)))) + .thenCallRealMethod(); + + whenNew(URL.class).withAnyArguments().thenReturn(url); + when(url.openConnection()).thenReturn(connection); + when(connection.getOutputStream()).thenReturn(outStream); + when(connection.getInputStream()).thenReturn(inStream); + whenNew(BufferedReader.class).withAnyArguments().thenReturn(reader); + when(reader.readLine()).thenReturn("{\"" + JsonKey.MESSAGE_Id + "\": 123}", (String) null); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail("Mock rules addition failed " + e.getMessage()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/BaseRequestValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/BaseRequestValidatorTest.java new file mode 100644 index 0000000000..ba0d20c27f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/BaseRequestValidatorTest.java @@ -0,0 +1,132 @@ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; + +import java.text.MessageFormat; +import java.util.*; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +/** Created by rajatgupta on 20/03/19. */ +public class BaseRequestValidatorTest { + private static final BaseRequestValidator baseRequestValidator = new BaseRequestValidator(); + + @Test + public void testValidateSearchRequestFailureWithInvalidFieldType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.FILTERS, new HashMap<>()); + requestObj.put(JsonKey.FIELDS, "invalid"); + request.setRequest(requestObj); + try { + baseRequestValidator.validateSearchRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + assertEquals( + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.FIELDS, "List"), + e.getMessage()); + } + } + + @Test + public void testValidateSearchRequestFailureWithInvalidFieldsValueInList() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.FILTERS, new HashMap<>()); + requestObj.put(JsonKey.FIELDS, Arrays.asList(1)); + request.setRequest(requestObj); + try { + baseRequestValidator.validateSearchRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + assertEquals( + MessageFormat.format( + ResponseCode.dataTypeError.getErrorMessage(), JsonKey.FIELDS, "List of String"), + e.getMessage()); + } + } + + @Test + public void testValidateSearchRequestFailureWithInvalidFiltersKeyAsNull() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + Map filterMap = new HashMap<>(); + filterMap.put(null, "data"); + requestObj.put(JsonKey.FILTERS, filterMap); + + request.setRequest(requestObj); + try { + baseRequestValidator.validateSearchRequest(request); + } catch (ProjectCommonException e) { + assertEquals( + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), null, JsonKey.FILTERS), + e.getMessage()); + } + } + + @Test + public void testValidateSearchRequestFailureWithInvalidFiltersNullValueInList() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + Map filterMap = new HashMap<>(); + List data = new ArrayList<>(); + data.add(null); + filterMap.put(JsonKey.FIRST_NAME, data); + requestObj.put(JsonKey.FILTERS, filterMap); + + request.setRequest(requestObj); + try { + baseRequestValidator.validateSearchRequest(request); + } catch (ProjectCommonException e) { + assertEquals( + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), null, JsonKey.FIRST_NAME), + e.getMessage()); + } + } + + @Test + public void testValidateSearchRequestFailureWithInvalidFiltersNullValueInMap() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + Map filterMap = new HashMap<>(); + Map data = new HashMap<>(); + data.put(JsonKey.FIRST_NAME, null); + filterMap.put(JsonKey.FIELD, data); + requestObj.put(JsonKey.FILTERS, filterMap); + + request.setRequest(requestObj); + try { + baseRequestValidator.validateSearchRequest(request); + } catch (ProjectCommonException e) { + assertEquals( + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), null, JsonKey.FIRST_NAME), + e.getMessage()); + } + } + + @Test + public void testValidateSearchRequestFailureWithInvalidFiltersNullValueInString() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + Map data = new HashMap<>(); + data.put(JsonKey.FIRST_NAME, null); + + requestObj.put(JsonKey.FILTERS, data); + + request.setRequest(requestObj); + try { + baseRequestValidator.validateSearchRequest(request); + } catch (ProjectCommonException e) { + assertEquals( + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), null, JsonKey.FIRST_NAME), + e.getMessage()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/CourseBatchValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/CourseBatchValidatorTest.java new file mode 100644 index 0000000000..d7ae70a35f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/CourseBatchValidatorTest.java @@ -0,0 +1,440 @@ +/** */ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class CourseBatchValidatorTest { + + private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + + @Test + public void validateCreateBatchSuccess() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.STATUS, 1); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.NAME, "TestCourse"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.START_DATE, format.format(new Date())); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validateUpdateCourseBatch() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.NAME, "TestCourse"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.START_DATE, format.format(new Date())); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateUpdateCourseBatchReq(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validateCreateBatchWithOutCourseId() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, ""); + requestObj.put(JsonKey.NAME, "TestCourse"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.START_DATE, format.format(new Date())); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidCourseId.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateCreateBatchWithOutName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.NAME, "TestCourse"); + requestObj.put(JsonKey.START_DATE, format.format(new Date())); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.courseNameRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateCreateBatchWithOutStartDate() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.NAME, "TestCourse"); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.courseBatchStartDateRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateCreateBatchWithPastStartDate() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.START_DATE, "2017-01-05"); + requestObj.put(JsonKey.NAME, "TestCourse"); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.courseBatchStartDateError.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateCreateBatchWithInvalidStartDateFormat() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.START_DATE, format.format(new Date()) + " 23:58:59"); + requestObj.put(JsonKey.NAME, "TestCourse"); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dateFormatError.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateCreateBatchWithEmptyEndDate() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.NAME, "TestCourse"); + requestObj.put(JsonKey.START_DATE, "2017-01-05"); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, ""); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.courseBatchStartDateError.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateCreateBatchWithPastEndDate() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.NAME, "TestCourse"); + requestObj.put(JsonKey.START_DATE, format.format(new Date())); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, -2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime())); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.endDateError.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateCreateBatchWithInvalidEndDateFormat() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "do_123233434"); + requestObj.put(JsonKey.ENROLLMENT_TYPE, "Open"); + requestObj.put(JsonKey.NAME, "TestCourse"); + requestObj.put(JsonKey.START_DATE, format.format(new Date())); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 2); + requestObj.put(JsonKey.END_DATE, format.format(cal.getTime()) + " 23:59:59+Z:50"); + List userIds = new ArrayList(); + userIds.add("test123345"); + request.put(JsonKey.COURSE_CREATED_FOR, userIds); + request.setRequest(requestObj); + try { + RequestValidator.validateCreateBatchReq(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dateFormatError.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateAddBatchCourse() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.BATCH_ID, "cassandra batch id"); + List list = new ArrayList<>(); + list.add("user id whome need to join"); + requestObj.put(JsonKey.USER_IDs, list); + request.setRequest(requestObj); + try { + RequestValidator.validateAddBatchCourse(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validateAddBatchCourseWithEmptyBatchId() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + List list = new ArrayList<>(); + list.add("user id whome need to join"); + requestObj.put(JsonKey.USER_IDs, list); + request.setRequest(requestObj); + try { + RequestValidator.validateAddBatchCourse(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.courseBatchIdRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, response); + } + + @Test + public void validateAddBatchCourseWithEmptyUserId() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.BATCH_ID, "cassandra batch id"); + request.setRequest(requestObj); + try { + RequestValidator.validateAddBatchCourse(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.userIdRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, response); + } + + @Test + public void validateGetBatchCourse() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.BATCH_ID, "cassandra batch id"); + request.setRequest(requestObj); + try { + RequestValidator.validateGetBatchCourse(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validateGetBatchCourseWithOutBatchId() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + request.setRequest(requestObj); + try { + RequestValidator.validateGetBatchCourse(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.courseBatchIdRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, response); + } + + @Test + public void validateUpdateCourse() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "cassandra batch id"); + request.setRequest(requestObj); + try { + RequestValidator.validateUpdateCourse(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validateUpdateCourseWithOurBatchId() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + request.setRequest(requestObj); + try { + RequestValidator.validateUpdateCourse(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.courseIdRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, response); + } + + @Test + public void validatePublishedCourse() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "cassandra batch id"); + request.setRequest(requestObj); + try { + RequestValidator.validatePublishCourse(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validatePublishedCourseWithOutCourseId() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + request.setRequest(requestObj); + try { + RequestValidator.validatePublishCourse(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.courseIdRequiredError.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, response); + } + + @Test + public void validateDeleteCourse() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.COURSE_ID, "cassandra batch id"); + request.setRequest(requestObj); + try { + RequestValidator.validateDeleteCourse(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validateDeleteCourseWithOutCourseId() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + request.setRequest(requestObj); + try { + RequestValidator.validateDeleteCourse(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.courseIdRequiredError.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, response); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/NotesRequestValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/NotesRequestValidatorTest.java new file mode 100644 index 0000000000..a0ded13285 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/NotesRequestValidatorTest.java @@ -0,0 +1,133 @@ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +/** Test class for notes request validation */ +public class NotesRequestValidatorTest { + + /** Method to test create note when userId in request is empty */ + @Test + public void testCreateNoteBlankUserId() { + try { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, ""); + requestObj.put(JsonKey.TITLE, "test title"); + requestObj.put(JsonKey.NOTE, "This is a test Note"); + requestObj.put(JsonKey.COURSE_ID, "org.ekstep.test"); + requestObj.put(JsonKey.CONTENT_ID, "org.ekstep.test"); + request.setRequest(requestObj); + RequestValidator.validateNote(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.userIdRequired.getErrorCode(), e.getCode()); + } + } + + /** Method to test create note when title in request is empty */ + @Test + public void testCreateNoteBlankTitle() { + try { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "testUser"); + requestObj.put(JsonKey.TITLE, ""); + requestObj.put(JsonKey.NOTE, "This is a test Note"); + requestObj.put(JsonKey.COURSE_ID, "org.ekstep.test"); + requestObj.put(JsonKey.CONTENT_ID, "org.ekstep.test"); + request.setRequest(requestObj); + RequestValidator.validateNote(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.titleRequired.getErrorCode(), e.getCode()); + } + } + + /** Method to test create note when note in request is empty */ + @Test + public void testCreateNoteBlankNote() { + try { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "testUser"); + requestObj.put(JsonKey.TITLE, "test title"); + requestObj.put(JsonKey.NOTE, ""); + requestObj.put(JsonKey.COURSE_ID, "org.ekstep.test"); + requestObj.put(JsonKey.CONTENT_ID, "org.ekstep.test"); + request.setRequest(requestObj); + RequestValidator.validateNote(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.noteRequired.getErrorCode(), e.getCode()); + } + } + + /** Method to test create note without courseId and contentId in request */ + @Test + public void testCreateNoteWithoutCourseAndContentId() { + try { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "testUser"); + requestObj.put(JsonKey.TITLE, "test title"); + requestObj.put(JsonKey.NOTE, "This is a test Note"); + requestObj.put(JsonKey.COURSE_ID, ""); + requestObj.put(JsonKey.CONTENT_ID, ""); + request.setRequest(requestObj); + RequestValidator.validateNote(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.contentIdError.getErrorCode(), e.getCode()); + } + } + + /** Method to test create note when tags in request is string */ + @Test + public void testCreateNoteWithTagsAsString() { + try { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "testUser"); + requestObj.put(JsonKey.TITLE, "test title"); + requestObj.put(JsonKey.NOTE, "This is a test Note"); + requestObj.put(JsonKey.COURSE_ID, "org.ekstep.test"); + requestObj.put(JsonKey.TAGS, "test tag"); + request.setRequest(requestObj); + RequestValidator.validateNote(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidTags.getErrorCode(), e.getCode()); + } + } + + /** Method to test validate node id when note id is empty */ + @Test + public void testValidateNoteOperationWithOutNoteId() { + try { + String noteId = ""; + RequestValidator.validateNoteId(noteId); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidNoteId.getErrorCode(), e.getCode()); + } + } + + /** Method to test validate node id when note id is null */ + @Test + public void testValidateNoteOperationWithNoteIdAsNull() { + try { + String noteId = null; + RequestValidator.validateNoteId(noteId); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidNoteId.getErrorCode(), e.getCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/NotificationRequestValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/NotificationRequestValidatorTest.java new file mode 100644 index 0000000000..ccc09d11ff --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/NotificationRequestValidatorTest.java @@ -0,0 +1,140 @@ +/** */ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class NotificationRequestValidatorTest { + + @Test + public void validateSendNotificationSuccess() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.TO, "test"); + requestObj.put(JsonKey.TYPE, "FCM"); + Map data = new HashMap<>(); + data.put("url", "www.google.com"); + requestObj.put(JsonKey.DATA, data); + request.setRequest(requestObj); + try { + RequestValidator.validateSendNotification(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void validateSendNotificationWithOutTOParam() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.TYPE, "FCM"); + Map data = new HashMap<>(); + data.put("url", "www.google.com"); + requestObj.put(JsonKey.DATA, data); + request.setRequest(requestObj); + try { + RequestValidator.validateSendNotification(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidTopic.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateSendNotificationWithOutType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.TO, "test"); + Map data = new HashMap<>(); + data.put("url", "www.google.com"); + requestObj.put(JsonKey.DATA, data); + request.setRequest(requestObj); + try { + RequestValidator.validateSendNotification(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidNotificationType.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateSendNotificationWithWrongType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.TO, "test"); + requestObj.put(JsonKey.TYPE, "GCM"); + Map data = new HashMap<>(); + data.put("url", "www.google.com"); + requestObj.put(JsonKey.DATA, data); + request.setRequest(requestObj); + try { + RequestValidator.validateSendNotification(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.notificationTypeSupport.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateSendNotificationWithEmptyData() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.TO, "test"); + requestObj.put(JsonKey.TYPE, "FCM"); + request.setRequest(requestObj); + try { + RequestValidator.validateSendNotification(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidTopicData.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateSendNotificationWithWrongObjectType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.TO, "test"); + requestObj.put(JsonKey.TYPE, "FCM"); + List data = new ArrayList(); + data.add("www.google.com"); + requestObj.put(JsonKey.DATA, data); + request.setRequest(requestObj); + try { + RequestValidator.validateSendNotification(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidTopicData.getErrorCode(), e.getCode()); + } + } + + @Test + public void validateSendNotificationWithEmptyDataMap() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.TO, "test"); + requestObj.put(JsonKey.TYPE, "FCM"); + Map data = new HashMap<>(); + requestObj.put(JsonKey.DATA, data); + request.setRequest(requestObj); + try { + RequestValidator.validateSendNotification(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidTopicData.getErrorCode(), e.getCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/OrgValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/OrgValidatorTest.java new file mode 100644 index 0000000000..d41dfa8a93 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/OrgValidatorTest.java @@ -0,0 +1,228 @@ +/** */ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.orgvalidator.OrgRequestValidator; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class OrgValidatorTest { + + @Test + public void validateCreateOrgSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, "tpp"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateCreateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", requestObj.get("ext")); + } + + @Test + public void validateCreateRootOrgWithLicenseSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, "tpp"); + requestObj.put(JsonKey.LICENSE, "Test license"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateCreateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", requestObj.get("ext")); + } + + @Test + public void validateCreateRootOrgWithEmptyLicenseFailure() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, "tpp"); + requestObj.put(JsonKey.LICENSE, ""); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateCreateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNotNull(e); + } + assertEquals(requestObj.get("ext"), null); + } + + @Test + public void validateCreateOrgWithOutName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, "tpp"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateCreateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.mandatoryParamsMissing.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, requestObj.get("ext")); + } + + @Test + public void validateCreateOrgWithRootOrgTrueAndWithOutChannel() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, ""); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateCreateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.dependentParamsMissing.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, requestObj.get("ext")); + } + + @Test + public void validateUpdateCreateOrgSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.ORGANISATION_ID, "test12344"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, "tpp"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateUpdateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", requestObj.get("ext")); + } + + @Test + public void validateUpdateOrgFailure() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORGANISATION_ID, "test2344"); + requestObj.put(JsonKey.ROOT_ORG_ID, ""); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, "tpp"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateUpdateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.invalidRootOrganisationId.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, requestObj.get("ext")); + } + + @Test + public void validateUpdateOrgWithStatus() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.STATUS, "true"); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, "tpp"); + requestObj.put(JsonKey.ORGANISATION_ID, "test123444"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateUpdateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.invalidRequestParameter.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, requestObj.get("ext")); + } + + @Test + public void validateUpdateOrgWithEmptyChannel() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.IS_ROOT_ORG, true); + requestObj.put(JsonKey.CHANNEL, ""); + requestObj.put(JsonKey.ORGANISATION_ID, "test123444"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateUpdateOrgRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.dependentParamsMissing.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, requestObj.get("ext")); + } + + @Test + public void validateUpdateOrgStatus() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.STATUS, 2); + requestObj.put(JsonKey.ORGANISATION_ID, "test-12334"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateUpdateOrgStatusRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", requestObj.get("ext")); + } + + @Test + public void validateUpdateOrgStatusWithInvalidStatus() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORG_NAME, "test"); + requestObj.put(JsonKey.STATUS, "true"); + requestObj.put(JsonKey.ORGANISATION_ID, "test-12334"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + new OrgRequestValidator().validateUpdateOrgStatusRequest(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.invalidRequestData.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, requestObj.get("ext")); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/PageSectionValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/PageSectionValidatorTest.java new file mode 100644 index 0000000000..9f0d387bd9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/PageSectionValidatorTest.java @@ -0,0 +1,284 @@ +/** */ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class PageSectionValidatorTest { + + @Test + public void testValidateGetPageDataSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SOURCE, "web"); + requestObj.put(JsonKey.PAGE_NAME, "resource"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateGetPageData(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", (String) requestObj.get("ext")); + } + + @Test + public void testValidateGetPageDataFailureWithoutSource() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PAGE_NAME, "resource"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateGetPageData(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.sourceRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, (String) requestObj.get("ext")); + } + + @Test + public void testValidateGetPageDataFailureWithoutPageName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SOURCE, "web"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateGetPageData(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.pageNameRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, (String) requestObj.get("ext")); + } + + @Test + public void testValidateCreateSectionSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SECTION_NAME, "latest resource"); + requestObj.put( + JsonKey.SECTION_DATA_TYPE, "{\"request\": { \"search\": {\"contentType\": [\"Story\"] }}}"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateCreateSection(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", (String) requestObj.get("ext")); + } + + @Test + public void testValidateCreateSectionFailureWithoutSectionName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put( + JsonKey.SECTION_DATA_TYPE, "{\"request\": { \"search\": {\"contentType\": [\"Story\"] }}}"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateCreateSection(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.sectionNameRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, (String) requestObj.get("ext")); + } + + @Test + public void testValidateCreateSectionFailureWithoutSectionDataType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SECTION_NAME, "latest resource"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateCreateSection(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.sectionDataTypeRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, (String) requestObj.get("ext")); + } + + @Test + public void testValidateUpdateSectionSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SECTION_NAME, "latest resource"); + requestObj.put( + JsonKey.SECTION_DATA_TYPE, "{\"request\": { \"search\": {\"contentType\": [\"Story\"] }}}"); + requestObj.put(JsonKey.ID, "some section id"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateUpdateSection(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", (String) requestObj.get("ext")); + } + + @Test + public void testValidateUpdateSectionFailureWithoutId() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SECTION_NAME, "latest resource"); + requestObj.put( + JsonKey.SECTION_DATA_TYPE, "{\"request\": { \"search\": {\"contentType\": [\"Story\"] }}}"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateUpdateSection(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.sectionIdRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, (String) requestObj.get("ext")); + } + + @Test + public void testValidateUpdateSectionFailureWithoutSectioName() { + Request request = new Request(); + boolean reqSuccess = false; + Map requestObj = new HashMap<>(); + requestObj.put( + JsonKey.SECTION_DATA_TYPE, "{\"request\": { \"search\": {\"contentType\": [\"Story\"] }}}"); + requestObj.put(JsonKey.ID, "some section id"); + requestObj.put(JsonKey.SECTION_NAME, ""); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateUpdateSection(request); + reqSuccess = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.sectionNameRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, reqSuccess); + } + + @Test + public void testValidateUpdateSectionFailureWithoutSectioData() { + Request request = new Request(); + boolean reqSuccess = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SECTION_NAME, "latest resource"); + requestObj.put(JsonKey.SECTION_DATA_TYPE, ""); + requestObj.put(JsonKey.ID, "some section id"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateUpdateSection(request); + reqSuccess = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.sectionDataTypeRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, reqSuccess); + } + + @Test + public void testValidateCreatePageSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PAGE_NAME, "some page name that need to be build"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateCreatePage(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", (String) requestObj.get("ext")); + } + + @Test + public void testValidateCreatePageFailureWithoutPageName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateCreatePage(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.pageNameRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, (String) requestObj.get("ext")); + } + + @Test + public void testValidateUpdatePageSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PAGE_NAME, "some page name that need to be build"); + requestObj.put(JsonKey.ID, "identifier of the page"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateUpdatepage(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals("success", requestObj.get("ext")); + } + + @Test + public void testValidateUpdatePageFailureWithoutPageName() { + boolean reqSuccess = false; + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ID, "identifier of the page"); + requestObj.put(JsonKey.PAGE_NAME, null); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateUpdatepage(request); + reqSuccess = false; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.pageNameRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(false, reqSuccess); + } + + @Test + public void testValidateUpdatePageFailureWithoutId() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PAGE_NAME, "some page name that need to be build"); + request.setRequest(requestObj); + try { + // this method will either throw projectCommonException or it return void + RequestValidator.validateUpdatepage(request); + requestObj.put("ext", "success"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.pageIdRequired.getErrorCode(), e.getCode()); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + assertEquals(null, (String) requestObj.get("ext")); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/RequestTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/RequestTest.java new file mode 100644 index 0000000000..db29d28dc4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/RequestTest.java @@ -0,0 +1,37 @@ +/** */ +package org.sunbird.common.request; + +import java.util.HashMap; +import org.junit.Assert; +import org.junit.Test; + +/** @author Manzarul */ +public class RequestTest { + + @Test + public void testRequestBeanWithDefaultConstructor() { + Request request = new Request(); + request.setEnv(1); + long val = System.currentTimeMillis(); + request.setId(val + ""); + request.setManagerName("name"); + request.setOperation("operation name"); + request.setRequestId("unique req id"); + request.setTs(val + ""); + request.setVer("v1"); + request.setContext(new HashMap<>()); + request.setRequest(new HashMap<>()); + request.setParams(new RequestParams()); + Assert.assertEquals(request.getEnv(), 1); + Assert.assertEquals(request.getId(), val + ""); + Assert.assertEquals(request.getManagerName(), "name"); + Assert.assertEquals(request.getOperation(), "operation name"); + Assert.assertEquals(request.getRequestId(), "unique req id"); + Assert.assertEquals(request.getTs(), val + ""); + Assert.assertEquals(request.getVer(), "v1"); + Assert.assertEquals(request.getContext().size(), 0); + Assert.assertEquals(request.getRequest().size(), 0); + Assert.assertNotNull(request.getParams()); + Assert.assertNotNull(request.toString()); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/RequestValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/RequestValidatorTest.java new file mode 100644 index 0000000000..b5de217b54 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/RequestValidatorTest.java @@ -0,0 +1,476 @@ +/** */ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; + +/** @author Manzarul */ +public class RequestValidatorTest { + + @Test + public void testValidateUpdateContentSuccess() { + Request request = new Request(); + boolean response = false; + List> listOfMap = new ArrayList<>(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.CONTENT_ID, "do_1233343"); + requestObj.put(JsonKey.STATUS, "Completed"); + listOfMap.add(requestObj); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.CONTENTS, listOfMap); + request.setRequest(innerMap); + try { + RequestValidator.validateUpdateContent(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValdateUpdateContentFailureWithNullContentId() { + Request request = new Request(); + boolean response = false; + List> listOfMap = new ArrayList<>(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.CONTENT_ID, null); + requestObj.put(JsonKey.STATUS, "Completed"); + listOfMap.add(requestObj); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.CONTENTS, listOfMap); + request.setRequest(innerMap); + try { + RequestValidator.validateUpdateContent(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNotNull(e); + } + assertEquals(false, response); + } + + @Test + public void testValidteUpdateContentFailureWithoutContentId() { + Request request = new Request(); + List> listOfMap = new ArrayList<>(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.STATUS, "Completed"); + listOfMap.add(requestObj); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.CONTENTS, listOfMap); + request.setRequest(innerMap); + try { + RequestValidator.validateUpdateContent(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.contentIdRequiredError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidteUpdateContentFailureWithoutStatus() { + Request request = new Request(); + List> listOfMap = new ArrayList<>(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.CONTENT_ID, "do_1233343"); + listOfMap.add(requestObj); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.CONTENTS, listOfMap); + request.setRequest(innerMap); + try { + RequestValidator.validateUpdateContent(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.contentStatusRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidteUpdateContentFailureWithEmptyContents() { + Request request = new Request(); + List> listOfMap = new ArrayList<>(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.CONTENT_ID, "do_1233343"); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.CONTENTS, listOfMap); + request.setRequest(innerMap); + try { + RequestValidator.validateUpdateContent(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.contentIdRequiredError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateRegisterClientFailureWithEmptyClientName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.CLIENT_NAME, ""); + request.setRequest(requestObj); + try { + RequestValidator.validateRegisterClient(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidClientName.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateRegisterClientSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.CLIENT_NAME, "1234"); + request.setRequest(requestObj); + try { + RequestValidator.validateRegisterClient(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidClientName.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateUpdateClientKeyFailureWithEmptyToken() { + try { + RequestValidator.validateUpdateClientKey("1234", ""); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidRequestData.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateUpdateClientKeySuccess() { + try { + RequestValidator.validateUpdateClientKey("1234", "test123"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidRequestData.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateClientIdFailureWithEmptyId() { + try { + RequestValidator.validateClientId(""); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidClientId.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateFileUploadFailureWithoutContainerName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.CONTAINER, ""); + request.setRequest(requestObj); + try { + RequestValidator.validateFileUpload(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.storageContainerNameMandatory.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateSendEmailSuccess() { + boolean response = false; + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SUBJECT, "test123"); + requestObj.put(JsonKey.BODY, "test"); + List data = new ArrayList<>(); + data.add("test123@gmail.com"); + requestObj.put(JsonKey.RECIPIENT_EMAILS, data); + requestObj.put(JsonKey.RECIPIENT_USERIDS, new ArrayList<>()); + request.setRequest(requestObj); + try { + RequestValidator.validateSendMail(request); + response = true; + } catch (ProjectCommonException e) { + + } + assertTrue(response); + } + + @Test + public void testValidateSendMailFailureWithNullRecipients() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SUBJECT, "test123"); + requestObj.put(JsonKey.BODY, "test"); + requestObj.put(JsonKey.RECIPIENT_EMAILS, null); + request.setRequest(requestObj); + try { + RequestValidator.validateSendMail(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.mandatoryParamsMissing.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateSendMailFailureWithEmptyBody() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SUBJECT, "test123"); + requestObj.put(JsonKey.BODY, ""); + request.setRequest(requestObj); + try { + RequestValidator.validateSendMail(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.emailBodyError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateSendMailFailureWithEmptySubject() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.SUBJECT, ""); + request.setRequest(requestObj); + try { + RequestValidator.validateSendMail(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.emailSubjectError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateEnrolmentTypeFailureWithEmptyType() { + try { + RequestValidator.validateEnrolmentType(""); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.enrolmentTypeRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateEnrolmentTypeFailureWithWrongType() { + try { + RequestValidator.validateEnrolmentType("test"); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.enrolmentIncorrectValue.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateEnrolmentTypeSuccessWithOpenType() { + boolean response = false; + try { + RequestValidator.validateEnrolmentType(ProjectUtil.EnrolmentType.open.getVal()); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateEnrolmentTypeSuccessWithInviteType() { + boolean response = false; + try { + RequestValidator.validateEnrolmentType(ProjectUtil.EnrolmentType.inviteOnly.getVal()); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateSyncRequestSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.OPERATION_FOR, "keycloak"); + requestObj.put(JsonKey.OBJECT_TYPE, JsonKey.USER); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateSyncRequest(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateSyncRequestFailureWithNullObjectType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.OPERATION_FOR, "not keycloack"); + requestObj.put(JsonKey.OBJECT_TYPE, null); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateSyncRequest(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateSyncRequestFailureWithInvalidObjectType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.OPERATION_FOR, "not keycloack"); + List objectLsit = new ArrayList<>(); + objectLsit.add("testval"); + requestObj.put(JsonKey.OBJECT_TYPE, objectLsit); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateSyncRequest(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidObjectType.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateUserOrgTypeSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NAME, "orgtypeName"); + requestObj.put(JsonKey.ID, "orgtypeId"); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateUpdateOrgType(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateUserOrgTypeFailureWithEmptyName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NAME, ""); + requestObj.put(JsonKey.ID, "orgtypeId"); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateUpdateOrgType(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.orgTypeMandatory.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateUserOrgTypeFailureWithEmptyId() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NAME, "orgTypeName"); + requestObj.put(JsonKey.ID, ""); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateUpdateOrgType(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.orgTypeIdRequired.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateCreateOrgTypeSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NAME, "OrgTypeName"); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateCreateOrgType(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateCreateOrgTypeFailureWithNullName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NAME, null); + request.setRequest(requestObj); + boolean response = false; + try { + RequestValidator.validateCreateOrgType(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.orgTypeMandatory.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateGetClientKeySuccess() { + boolean response = false; + try { + RequestValidator.validateGetClientKey("clientId", "clientType"); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateGetClientKeyFailureWithEmptyClientId() { + boolean response = false; + try { + RequestValidator.validateGetClientKey("", "clientType"); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidClientId.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateGetClientKeyFailureWithEmptyClientType() { + boolean response = false; + try { + RequestValidator.validateGetClientKey("clientId", ""); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidRequestData.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/UserProfileRequestValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/UserProfileRequestValidatorTest.java new file mode 100644 index 0000000000..19cc0ff2b8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/UserProfileRequestValidatorTest.java @@ -0,0 +1,76 @@ +package org.sunbird.common.request; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; + +public class UserProfileRequestValidatorTest { + + private static final UserProfileRequestValidator userProfileRequestValidator = + new UserProfileRequestValidator(); + + @Test + public void testValidateProfileVisibilityFailureWithFieldInPrivateAndPublic() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "9878888888"); + List publicList = new ArrayList<>(); + publicList.add("Education"); + requestObj.put(JsonKey.PUBLIC, publicList); + List privateList = new ArrayList<>(); + privateList.add("Education"); + requestObj.put(JsonKey.PRIVATE, privateList); + request.setRequest(requestObj); + try { + userProfileRequestValidator.validateProfileVisibility(request); + } catch (ProjectCommonException e) { + Assert.assertNotNull(e); + } + } + + @Test + public void testValidateProfileVisibilityFailureWithEmptyUserId() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, ""); + request.setRequest(requestObj); + try { + userProfileRequestValidator.validateProfileVisibility(request); + } catch (ProjectCommonException e) { + Assert.assertNotNull(e); + } + } + + @Test + public void testValidateProfileVisibilityFailureWithInvalidPrivateType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "123"); + requestObj.put(JsonKey.PRIVATE, ""); + request.setRequest(requestObj); + try { + userProfileRequestValidator.validateProfileVisibility(request); + } catch (ProjectCommonException e) { + Assert.assertNotNull(e); + } + } + + @Test + public void testValidateProfileVisibilityFailureWithInvalidPublicType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "123"); + requestObj.put(JsonKey.PUBLIC, ""); + request.setRequest(requestObj); + try { + userProfileRequestValidator.validateProfileVisibility(request); + } catch (ProjectCommonException e) { + Assert.assertNotNull(e); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/UserRequestValidatorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/UserRequestValidatorTest.java new file mode 100644 index 0000000000..41a53bcafe --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/request/UserRequestValidatorTest.java @@ -0,0 +1,1443 @@ +/** */ +package org.sunbird.common.request; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; + +public class UserRequestValidatorTest { + + private static final UserRequestValidator userRequestValidator = new UserRequestValidator(); + + @Test + public void testValidatePasswordFailure() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.PASSWORD, "password"); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.passwordValidation.getErrorCode(), e.getCode()); + } + } + + @Test + public void testIsGoodPassword() { + HashMap passwordExpectations = + new HashMap() { + { + // Bad ones. + put("Test 1234", false); // space is not a valid char + put("hello1234", false); // no uppercase + put("helloABCD", false); // no numeral + put("hello#$%&'", false); // no uppercase/numeral + put("sho!1", false); // too short, not 8 char + put("B1!\"#$%&'()*+,-./:;<=>?@[]^_`{|}~", false); // no lowercase + put("Test @1234", false); // contains space + + // Good ones. + put("Test123!", true); // good + put("ALongPassword@123", true); // more than 8 char + put("Abc1!\"#$%&'()*+,-./:;<=>?@[]^_`{|}~", true); // with all spl char, PASS + } + }; + + passwordExpectations.forEach( + (pwd, expectedResult) -> { + assertEquals(expectedResult, UserRequestValidator.isGoodPassword(pwd)); + }); + } + + @Test + public void testValidateCreateUserBasicValidationFailure() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.ROLES, "admin"); + request.setRequest(requestObj); + try { + userRequestValidator.createUserBasicValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateFieldsNotAllowedFailure() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.PROVIDER, "AP"); + request.setRequest(requestObj); + try { + userRequestValidator.fieldsNotAllowed( + Arrays.asList( + JsonKey.REGISTERED_ORG_ID, + JsonKey.ROOT_ORG_ID, + JsonKey.PROVIDER, + JsonKey.EXTERNAL_ID, + JsonKey.EXTERNAL_ID_PROVIDER, + JsonKey.EXTERNAL_ID_TYPE, + JsonKey.ID_TYPE), + request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidRequestParameter.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateValidateCreateUserV3RequestSuccess() { + boolean response = false; + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.PASSWORD, "Password@1"); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserV3Request(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidatePasswordSuccess() { + boolean response = false; + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.PASSWORD, "Password@1"); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateUserCreateV3Success() { + boolean response = false; + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.PASSWORD, "Password@1"); + request.setRequest(requestObj); + try { + userRequestValidator.validateUserCreateV3(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateUserCreateV3Failure() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.FIRST_NAME, ""); + request.setRequest(requestObj); + try { + userRequestValidator.validateUserCreateV3(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.mandatoryParamsMissing.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateUserNameFailure() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.put(JsonKey.USERNAME, ""); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserV1Request(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.mandatoryParamsMissing.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateLocationCodesSuccess() { + boolean response = false; + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + List location = new ArrayList<>(); + location.add("KA"); + location.add("AP"); + requestObj.put(JsonKey.LOCATION_CODES, location); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + assertEquals(true, response); + } + + @Test + public void testValidateLocationCodesFailure() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + + requestObj.put(JsonKey.LOCATION_CODES, "AP"); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateForgotPasswordSuccess() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, "manzarul07"); + request.setRequest(requestObj); + try { + userRequestValidator.validateForgotPassword(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateForgotPasswordFailureWithEmptyName() { + try { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, ""); + request.setRequest(requestObj); + userRequestValidator.validateForgotPassword(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.userNameRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateForgotPasswordFailureWithoutName() { + try { + Request request = new Request(); + Map requestObj = new HashMap<>(); + request.setRequest(requestObj); + userRequestValidator.validateForgotPassword(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.userNameRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateChangePasswordSuccess() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NEW_PASSWORD, "password1"); + requestObj.put(JsonKey.PASSWORD, "password"); + request.setRequest(requestObj); + try { + userRequestValidator.validateChangePassword(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateChangePasswordFailureWithEmptyNewPassword() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NEW_PASSWORD, ""); + requestObj.put(JsonKey.PASSWORD, "password"); + request.setRequest(requestObj); + try { + userRequestValidator.validateChangePassword(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.newPasswordEmpty.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateChangePasswordFailureWithoutNewPassword() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PASSWORD, "password"); + request.setRequest(requestObj); + try { + userRequestValidator.validateChangePassword(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.newPasswordRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateChangePasswordFailureWithSameOldPassword() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NEW_PASSWORD, "password"); + requestObj.put(JsonKey.PASSWORD, "password"); + request.setRequest(requestObj); + try { + userRequestValidator.validateChangePassword(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.samePasswordError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateChangePasswordFailureWithPasswordMissing() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.NEW_PASSWORD, "password"); + request.setRequest(requestObj); + try { + userRequestValidator.validateChangePassword(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.passwordRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testCreateUserSuccess() { + boolean response = false; + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + List roles = new ArrayList(); + roles.add("PUBLIC"); + roles.add("CONTENT-CREATOR"); + requestObj.put(JsonKey.ROLE, roles); + List language = new ArrayList<>(); + language.add("English"); + requestObj.put(JsonKey.LANGUAGE, language); + List> addressList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ADDRESS_LINE1, "test"); + map.put(JsonKey.CITY, "Bangalore"); + map.put(JsonKey.COUNTRY, "India"); + map.put(JsonKey.ADD_TYPE, "current"); + addressList.add(map); + requestObj.put(JsonKey.ADDRESS, addressList); + + List> educationList = new ArrayList<>(); + Map map1 = new HashMap<>(); + map1.put(JsonKey.COURSE_NAME, "M.C.A"); + map1.put(JsonKey.DEGREE, "Master"); + map1.put(JsonKey.NAME, "CUSAT"); + educationList.add(map1); + requestObj.put(JsonKey.EDUCATION, educationList); + + List> jobProfileList = new ArrayList<>(); + map1 = new HashMap<>(); + map1.put(JsonKey.JOB_NAME, "SE"); + map1.put(JsonKey.ORGANISATION_NAME, "Tarento"); + jobProfileList.add(map1); + requestObj.put(JsonKey.JOB_PROFILE, jobProfileList); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateCreateUserFailureWithWrongAddType() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + List roles = new ArrayList(); + roles.add("PUBLIC"); + roles.add("CONTENT-CREATOR"); + requestObj.put(JsonKey.ROLE, roles); + List language = new ArrayList<>(); + language.add("English"); + requestObj.put(JsonKey.LANGUAGE, language); + List> addressList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ADDRESS_LINE1, "test"); + map.put(JsonKey.CITY, "Bangalore"); + map.put(JsonKey.COUNTRY, "India"); + map.put(JsonKey.ADD_TYPE, "lmlkmkl"); + addressList.add(map); + requestObj.put(JsonKey.ADDRESS, addressList); + + List> educationList = new ArrayList<>(); + Map map1 = new HashMap<>(); + map1.put(JsonKey.COURSE_NAME, "M.C.A"); + map1.put(JsonKey.DEGREE, "Master"); + map1.put(JsonKey.NAME, "CUSAT"); + educationList.add(map1); + requestObj.put(JsonKey.EDUCATION, educationList); + + List> jobProfileList = new ArrayList<>(); + map1 = new HashMap<>(); + map1.put(JsonKey.JOB_NAME, "SE"); + map1.put(JsonKey.ORGANISATION_NAME, "Tarento"); + jobProfileList.add(map1); + requestObj.put(JsonKey.JOB_PROFILE, jobProfileList); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.addressTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyAddType() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + List roles = new ArrayList(); + roles.add("PUBLIC"); + roles.add("CONTENT-CREATOR"); + requestObj.put(JsonKey.ROLE, roles); + List language = new ArrayList<>(); + language.add("English"); + requestObj.put(JsonKey.LANGUAGE, language); + List> addressList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ADDRESS_LINE1, "test"); + map.put(JsonKey.CITY, "Bangalore"); + map.put(JsonKey.COUNTRY, "India"); + map.put(JsonKey.ADD_TYPE, ""); + addressList.add(map); + requestObj.put(JsonKey.ADDRESS, addressList); + + List> educationList = new ArrayList<>(); + Map map1 = new HashMap<>(); + map1.put(JsonKey.COURSE_NAME, "M.C.A"); + map1.put(JsonKey.DEGREE, "Master"); + map1.put(JsonKey.NAME, "CUSAT"); + educationList.add(map1); + requestObj.put(JsonKey.EDUCATION, educationList); + + List> jobProfileList = new ArrayList<>(); + map1 = new HashMap<>(); + map1.put(JsonKey.JOB_NAME, "SE"); + map1.put(JsonKey.ORGANISATION_NAME, "Tarento"); + jobProfileList.add(map1); + requestObj.put(JsonKey.JOB_PROFILE, jobProfileList); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.addressError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testPhoneValidationSuccess() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.COUNTRY_CODE, "+91"); + requestObj.put(JsonKey.PROVIDER, "sunbird"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + request.setRequest(requestObj); + try { + userRequestValidator.phoneValidation(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testPhoneValidationFailureWithInvalidPhone() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "+9321234123"); + requestObj.put(JsonKey.COUNTRY_CODE, "+91"); + requestObj.put(JsonKey.PROVIDER, "sunbird"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + request.setRequest(requestObj); + try { + userRequestValidator.phoneValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.invalidPhoneNumber.getErrorCode(), e.getCode()); + } + } + + @Test + public void testPhoneValidationFailureWithInvalidCountryCode() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "+9321234123"); + requestObj.put(JsonKey.COUNTRY_CODE, "+91968"); + requestObj.put(JsonKey.PROVIDER, "sunbird"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + request.setRequest(requestObj); + try { + userRequestValidator.phoneValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.invalidCountryCode.getErrorCode(), e.getCode()); + } + } + + @Test + public void testPhoneValidationFailureWithEmptyPhoneVerified() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.COUNTRY_CODE, "+91"); + requestObj.put(JsonKey.PROVIDER, "sunbird"); + requestObj.put(JsonKey.PHONE_VERIFIED, ""); + request.setRequest(requestObj); + try { + userRequestValidator.phoneValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.phoneVerifiedError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testPhoneValidationFailureWithPhoneVerifiedFalse() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.COUNTRY_CODE, "+91"); + requestObj.put(JsonKey.PROVIDER, "sunbird"); + requestObj.put(JsonKey.PHONE_VERIFIED, false); + request.setRequest(requestObj); + try { + userRequestValidator.phoneValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.phoneVerifiedError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testPhoneValidationFailureWithPhoneVerifiedNull() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.COUNTRY_CODE, "+91"); + requestObj.put(JsonKey.PROVIDER, "sunbird"); + requestObj.put(JsonKey.PHONE_VERIFIED, null); + request.setRequest(requestObj); + try { + userRequestValidator.phoneValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.phoneVerifiedError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testUpdateUserSuccess() { + Request request = initailizeRequest(); + Map requestObj = request.getRequest(); + requestObj.remove(JsonKey.USERNAME); + requestObj.put(JsonKey.USER_ID, "userId"); + + List roles = new ArrayList(); + roles.add("PUBLIC"); + roles.add("CONTENT-CREATOR"); + requestObj.put(JsonKey.ROLE, roles); + List language = new ArrayList<>(); + language.add("English"); + requestObj.put(JsonKey.LANGUAGE, language); + List> addressList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ADDRESS_LINE1, "test"); + map.put(JsonKey.CITY, "Bangalore"); + map.put(JsonKey.COUNTRY, "India"); + map.put(JsonKey.ADD_TYPE, "current"); + addressList.add(map); + requestObj.put(JsonKey.ADDRESS, addressList); + + List> educationList = new ArrayList<>(); + Map map1 = new HashMap<>(); + map1.put(JsonKey.COURSE_NAME, "M.C.A"); + map1.put(JsonKey.DEGREE, "Master"); + map1.put(JsonKey.NAME, "CUSAT"); + educationList.add(map1); + requestObj.put(JsonKey.EDUCATION, educationList); + + List> jobProfileList = new ArrayList<>(); + map1 = new HashMap<>(); + map1.put(JsonKey.JOB_NAME, "SE"); + map1.put(JsonKey.ORGANISATION_NAME, "Tarento"); + jobProfileList.add(map1); + requestObj.put(JsonKey.JOB_PROFILE, jobProfileList); + boolean response = false; + request.setRequest(requestObj); + try { + userRequestValidator.validateUpdateUserRequest(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateUploadUserSuccessWithOrgId() { + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.ORGANISATION_ID, "ORG-1233"); + requestObj.put(JsonKey.EXTERNAL_ID_PROVIDER, "EXT_ID_PROVIDER"); + requestObj.put(JsonKey.FILE, "EXT_ID_PROVIDER"); + + try { + RequestValidator.validateUploadUser(requestObj); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateUploadUserSuccessWithExternalId() { + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PROVIDER, "ORG-provider"); + requestObj.put(JsonKey.EXTERNAL_ID, "ORG-1233"); + requestObj.put(JsonKey.ORGANISATION_ID, "ORG-1233"); + requestObj.put(JsonKey.ORG_PROVIDER, "ORG-Provider"); + requestObj.put(JsonKey.FILE, "ORG-Provider"); + try { + RequestValidator.validateUploadUser(requestObj); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateAssignRoleSuccess() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USER_ID, "ORG-provider"); + requestObj.put(JsonKey.EXTERNAL_ID, "EXT_ID"); + requestObj.put(JsonKey.ORGANISATION_ID, "ORG_ID"); + requestObj.put(JsonKey.ORG_PROVIDER, "ORG_PROVIDER"); + List roles = new ArrayList<>(); + roles.add("PUBLIC"); + requestObj.put(JsonKey.ROLES, roles); + request.setRequest(requestObj); + try { + userRequestValidator.validateAssignRole(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateAssignRoleSuccessWithProviderAndExternalId() { + Request request = new Request(); + boolean response = false; + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PROVIDER, "ORG-provider"); + requestObj.put(JsonKey.EXTERNAL_ID, "ORG-1233"); + requestObj.put(JsonKey.USER_ID, "User1"); + List roles = new ArrayList<>(); + roles.add("PUBLIC"); + requestObj.put(JsonKey.ROLES, roles); + request.setRequest(requestObj); + try { + userRequestValidator.validateAssignRole(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + assertEquals(true, response); + } + + @Test + public void testValidateWebPagesFailureWithEmptyWebPages() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.WEB_PAGES, new ArrayList<>()); + request.setRequest(requestObj); + try { + userRequestValidator.validateWebPages(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidWebPageData.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateWebPagesFailureWithNullWebPages() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.WEB_PAGES, null); + request.setRequest(requestObj); + try { + userRequestValidator.validateWebPages(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidWebPageData.getErrorCode(), e.getCode()); + } + } + + @Ignore + public void testCreateUserBasicValidationFailureWithEmptyFirstName() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.FIRST_NAME, ""); + request.setRequest(requestObj); + try { + userRequestValidator.createUserBasicValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.firstNameRequired.getErrorCode(), e.getCode()); + } + } + + @Ignore + public void testCreateUserBasicValidationFailureWithInvalidDOB() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.DOB, "20-10-15"); + request.setRequest(requestObj); + try { + userRequestValidator.createUserBasicValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dateFormatError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testCreateUserBasicValidationFailureWithoutEmailAndPhone() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.DOB, "2018-10-15"); + request.setRequest(requestObj); + try { + userRequestValidator.createUserBasicValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.emailorPhoneorManagedByRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testCreateUserBasicValidationFailureWithInvalidEmail() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.DOB, "2018-10-15"); + requestObj.put(JsonKey.EMAIL, "asd@as"); + request.setRequest(requestObj); + try { + userRequestValidator.createUserBasicValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.emailFormatError.getErrorCode(), e.getCode()); + } + } + + @Ignore + public void testCreateUserBasicValidationFailureWithInvalidRoles() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.ROLES, ""); + request.setRequest(requestObj); + try { + userRequestValidator.createUserBasicValidation(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserRequestFailureWithInvalidLanguage() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.EMAIL, "test123@test.com"); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.LANGUAGE, ""); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserRequestFailureWithInvalidAddress() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.EMAIL, "test123@test.com"); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.ADDRESS, ""); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidaeCreateUserRequestFailureWithInvalidEducation() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.EMAIL, "test123@test.com"); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.EDUCATION, ""); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserRequestFailureWithInvalidAddressType() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.EMAIL, "test123@test.com"); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + List> addressList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ADDRESS_LINE1, "test"); + map.put(JsonKey.CITY, "Bangalore"); + map.put(JsonKey.COUNTRY, "India"); + map.put(JsonKey.ADD_TYPE, "localr"); + addressList.add(map); + requestObj.put(JsonKey.ADDRESS, addressList); + request.setRequest(requestObj); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.addressTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserRequestFailureWithInvalidCountryCode() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.EMAIL, "test123@test.com"); + requestObj.put(JsonKey.EMAIL_VERIFIED, true); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + request.setRequest(requestObj); + request.getRequest().put(JsonKey.COUNTRY_CODE, "+as"); + + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.invalidCountryCode.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserRequestFailureWithEmptyEmailAndPhone() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + requestObj.put(JsonKey.EMAIL, ""); + requestObj.put(JsonKey.PHONE, ""); + request.setRequest(requestObj); + + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.emailorPhoneorManagedByRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithInvalidEmail() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.EMAIL, "am@ds@cmo"); + + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.emailFormatError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithoutPhoneVerified() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE, "7894561230"); + + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.phoneVerifiedError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserSuccess() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE, "7894561230"); + request.getRequest().put(JsonKey.PHONE_VERIFIED, ""); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.phoneVerifiedError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithPhoneVerifiedFalse() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE, "7894561230"); + request.getRequest().put(JsonKey.PHONE_VERIFIED, false); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.phoneVerifiedError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyEducationName() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE_VERIFIED, true); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, ""); + List> list = new ArrayList<>(); + list.add(map); + + request.getRequest().put(JsonKey.EDUCATION, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.educationNameError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyEducationDegree() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE_VERIFIED, true); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "name"); + map.put(JsonKey.DEGREE, ""); + List> list = new ArrayList<>(); + list.add(map); + + request.getRequest().put(JsonKey.EDUCATION, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.educationDegreeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyEducationAddress() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE_VERIFIED, true); + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "name"); + map.put(JsonKey.DEGREE, "degree"); + Map address = new HashMap<>(); + address.put(JsonKey.ADDRESS_LINE1, ""); + map.put(JsonKey.ADDRESS, address); + List> list = new ArrayList<>(); + list.add(map); + request.getRequest().put(JsonKey.EDUCATION, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.addressError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyEducationCity() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE_VERIFIED, true); + + Map map = new HashMap<>(); + map.put(JsonKey.NAME, "name"); + map.put(JsonKey.DEGREE, "degree"); + Map address = new HashMap<>(); + address.put(JsonKey.ADDRESS_LINE1, "line1"); + address.put(JsonKey.CITY, ""); + map.put(JsonKey.ADDRESS, address); + List> list = new ArrayList<>(); + list.add(map); + request.getRequest().put(JsonKey.EDUCATION, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.addressError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyJobProfile() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.PHONE_VERIFIED, true); + request.getRequest().put(JsonKey.JOB_PROFILE, ""); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyJobName() { + Request request = initailizeRequest(); + Map map = new HashMap<>(); + map.put(JsonKey.JOB_NAME, ""); + map.put(JsonKey.ORG_NAME, "degree"); + List> list = new ArrayList<>(); + list.add(map); + request.getRequest().put(JsonKey.JOB_PROFILE, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.jobNameError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithInvalidJobProfileJoiningDate() { + Request request = initailizeRequest(); + Map map = new HashMap<>(); + map.put(JsonKey.JOB_NAME, "kijklo"); + map.put(JsonKey.ORG_NAME, "degree"); + map.put(JsonKey.JOINING_DATE, "20-15-18"); + List> list = new ArrayList<>(); + list.add(map); + request.getRequest().put(JsonKey.JOB_PROFILE, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dateFormatError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithInvalidJobProfileEndDate() { + Request request = initailizeRequest(); + Map map = new HashMap<>(); + map.put(JsonKey.JOB_NAME, "kijklo"); + map.put(JsonKey.ORG_NAME, "degree"); + map.put(JsonKey.END_DATE, "20-15-18"); + List> list = new ArrayList<>(); + list.add(map); + request.getRequest().put(JsonKey.JOB_PROFILE, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dateFormatError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyJobProfileOrgName() { + Request request = initailizeRequest(); + Map map = new HashMap<>(); + map.put(JsonKey.JOB_NAME, "kijklo"); + map.put(JsonKey.ORG_NAME, ""); + List> list = new ArrayList<>(); + list.add(map); + request.getRequest().put(JsonKey.JOB_PROFILE, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.organisationNameError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithEmptyJobProfileCity() { + Request request = initailizeRequest(); + Map map = new HashMap<>(); + map.put(JsonKey.JOB_NAME, "jabName"); + map.put(JsonKey.ORG_NAME, "orgName"); + Map address = new HashMap<>(); + address.put(JsonKey.ADDRESS_LINE1, "line1"); + address.put(JsonKey.CITY, ""); + map.put(JsonKey.ADDRESS, address); + List> list = new ArrayList<>(); + list.add(map); + request.getRequest().put(JsonKey.JOB_PROFILE, list); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.addressError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateCreateUserFailureWithInvalidPhoneFormat() { + Request request = new Request(); + request.getRequest().put(JsonKey.EMAIL, "asd@asd.com"); + request.getRequest().put(JsonKey.EMAIL_VERIFIED, true); + request.getRequest().put(JsonKey.PHONE, "9874561230"); + request.getRequest().put(JsonKey.COUNTRY_CODE, "+001"); + request.getRequest().put(JsonKey.USERNAME, "98745"); + request.getRequest().put(JsonKey.FIRST_NAME, "98745"); + try { + userRequestValidator.validateCreateUserRequest(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.phoneNoFormatError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateGerUserCountFailureWithInvalidLocationIds() { + Request request = new Request(); + request.getRequest().put(JsonKey.LOCATION_IDS, ""); + + try { + RequestValidator.validateGetUserCount(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateGerUserCountFailureWithEmptyLocationIds() { + Request request = new Request(); + List list = new ArrayList<>(); + list.add(""); + request.getRequest().put(JsonKey.LOCATION_IDS, list); + + try { + RequestValidator.validateGetUserCount(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.locationIdRequired.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateGerUserCountFailureWithInvalidUserLstReq() { + Request request = new Request(); + List list = new ArrayList<>(); + list.add("4645"); + request.getRequest().put(JsonKey.LOCATION_IDS, list); + request.getRequest().put(JsonKey.USER_LIST_REQ, null); + + try { + RequestValidator.validateGetUserCount(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateGerUserCountFailureWithUserLstReqTrue() { + Request request = new Request(); + List list = new ArrayList<>(); + list.add("4645"); + request.getRequest().put(JsonKey.LOCATION_IDS, list); + request.getRequest().put(JsonKey.USER_LIST_REQ, true); + + try { + RequestValidator.validateGetUserCount(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.functionalityMissing.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateGerUserCountFailureWithEmptyEstCntReq() { + Request request = new Request(); + List list = new ArrayList<>(); + list.add("4645"); + request.getRequest().put(JsonKey.LOCATION_IDS, list); + request.getRequest().put(JsonKey.ESTIMATED_COUNT_REQ, ""); + + try { + RequestValidator.validateGetUserCount(request); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + } + + @Test + public void testValidateVerifyUserSuccess() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.LOGIN_ID, "username@provider"); + request.setRequest(requestObj); + boolean response = false; + try { + new UserRequestValidator().validateVerifyUser(request); + response = true; + } catch (ProjectCommonException e) { + Assert.assertNull(e); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateGerUserCountFailureWithEstCntReqTrue() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.LOGIN_ID, ""); + request.setRequest(requestObj); + boolean response = false; + try { + new UserRequestValidator().validateVerifyUser(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.loginIdRequired.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void validateUserCreateV3Sussess() { + boolean response = true; + try { + Request request = new Request(); + request.getRequest().put(JsonKey.FIRST_NAME, "test name"); + request.getRequest().put(JsonKey.EMAIL, "test@test.com"); + request.getRequest().put(JsonKey.EMAIL_VERIFIED, true); + request.getRequest().put(JsonKey.PHONE, "9663890445"); + request.getRequest().put(JsonKey.PHONE_VERIFIED, true); + new UserRequestValidator().validateUserCreateV3(request); + } catch (Exception e) { + response = false; + } + Assert.assertTrue(response); + } + + private Request initailizeRequest() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.USERNAME, "test123"); + requestObj.put(JsonKey.PHONE, "9321234123"); + requestObj.put(JsonKey.PHONE_VERIFIED, true); + requestObj.put(JsonKey.FIRST_NAME, "test123"); + request.setRequest(requestObj); + return request; + } + + @Test + public void testValidateVerifyUserFailureWithEmptyId() { + Request request = new Request(); + Map requestObj = new HashMap<>(); + requestObj.put(JsonKey.LOGIN_ID, ""); + request.setRequest(requestObj); + boolean response = false; + try { + userRequestValidator.validateVerifyUser(request); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.loginIdRequired.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateMandatoryFrameworkFieldsSuccess() { + Request request = initailizeRequest(); + request.getRequest().put(JsonKey.FRAMEWORK, createFrameWork()); + boolean response = false; + try { + new UserRequestValidator() + .validateMandatoryFrameworkFields( + request.getRequest(), getSupportedFileds(), getMandatoryFields()); + response = true; + } catch (Exception e) { + Assert.assertTrue(response); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateMandatoryFrameworkFieldValueAsString() { + Request request = initailizeRequest(); + Map frameworkMap = createFrameWork(); + frameworkMap.put("medium", "hindi"); + request.getRequest().put(JsonKey.FRAMEWORK, frameworkMap); + boolean response = false; + try { + new UserRequestValidator() + .validateMandatoryFrameworkFields( + request.getRequest(), getSupportedFileds(), getMandatoryFields()); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.dataTypeError.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateFrameworkUnknownField() { + Request request = initailizeRequest(); + Map frameworkMap = createFrameWork(); + frameworkMap.put("school", Arrays.asList("school1")); + request.getRequest().put(JsonKey.FRAMEWORK, frameworkMap); + boolean response = false; + try { + new UserRequestValidator() + .validateMandatoryFrameworkFields( + request.getRequest(), getSupportedFileds(), getMandatoryFields()); + response = true; + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + assertEquals(ResponseCode.errorUnsupportedField.getErrorCode(), e.getCode()); + } + Assert.assertFalse(response); + } + + @Test + public void testValidateFrameworkWithEmptyValue() { + Request request = initailizeRequest(); + Map frameworkMap = createFrameWork(); + frameworkMap.put("medium", Arrays.asList()); + request.getRequest().put(JsonKey.FRAMEWORK, frameworkMap); + boolean response = false; + try { + new UserRequestValidator() + .validateMandatoryFrameworkFields( + request.getRequest(), getSupportedFileds(), getMandatoryFields()); + response = true; + } catch (Exception e) { + Assert.assertTrue(response); + } + Assert.assertTrue(response); + } + + @Test + public void testValidateFrameworkWithNullValue() { + Request request = initailizeRequest(); + Map frameworkMap = createFrameWork(); + frameworkMap.put("medium", null); + request.getRequest().put(JsonKey.FRAMEWORK, frameworkMap); + + boolean response = false; + try { + new UserRequestValidator() + .validateMandatoryFrameworkFields( + request.getRequest(), getSupportedFileds(), getMandatoryFields()); + response = true; + } catch (Exception e) { + Assert.assertTrue(response); + } + Assert.assertTrue(response); + } + + private static Map createFrameWork() { + Map frameworkMap = new HashMap(); + frameworkMap.put("gradeLevel", Arrays.asList("Kindergarten")); + frameworkMap.put("subject", Arrays.asList("English")); + frameworkMap.put("id", Arrays.asList("NCF")); + return frameworkMap; + } + + private static List getSupportedFileds() { + List frameworkSupportedFields = new ArrayList(); + frameworkSupportedFields.add("id"); + frameworkSupportedFields.add("gradeLevel"); + frameworkSupportedFields.add("subject"); + frameworkSupportedFields.add("board"); + frameworkSupportedFields.add("medium"); + return frameworkSupportedFields; + } + + private static List getMandatoryFields() { + List frameworkMandatoryFields = new ArrayList(1); + frameworkMandatoryFields.add("id"); + return frameworkMandatoryFields; + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/responsecode/ResponseCodeTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/responsecode/ResponseCodeTest.java new file mode 100644 index 0000000000..fbe99401e7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/responsecode/ResponseCodeTest.java @@ -0,0 +1,53 @@ +package org.sunbird.common.responsecode; + +import static org.junit.Assert.assertEquals; + +import org.junit.Assert; +import org.junit.Test; + +public class ResponseCodeTest { + + @Test + public void testGetHeaderResponseCodeClientError() { + ResponseCode respCode = + ResponseCode.getHeaderResponseCode(ResponseCode.CLIENT_ERROR.getResponseCode()); + assertEquals(ResponseCode.CLIENT_ERROR, respCode); + } + + @Test + public void testGetHeaderResponseCodeServerError() { + ResponseCode respCode = ResponseCode.getHeaderResponseCode(0); + assertEquals(ResponseCode.SERVER_ERROR, respCode); + } + + @Test + public void testGetResponse() { + ResponseCode respCode = ResponseCode.getResponse(ResponseCode.invalidData.getErrorCode()); + assertEquals(ResponseCode.invalidData, respCode); + } + + @Test + public void testGetResponseNullCheck() { + ResponseCode respCode = ResponseCode.getResponse(null); + Assert.assertNull(respCode); + } + + @Test + public void testGetResponseMessage() { + String respMsg = ResponseCode.getResponseMessage(ResponseCode.unAuthorized.getErrorCode()); + assertEquals(ResponseCode.unAuthorized.getErrorMessage(), respMsg); + } + + @Test + public void testGetResponseMessageEmpty() { + String respMsg = ResponseCode.getResponseMessage(""); + assertEquals("", respMsg); + } + + @Test + public void testInvalidElementValueSuccess() { + ResponseCode respCode = + ResponseCode.getResponse(ResponseCode.invalidElementInList.getErrorCode()); + assertEquals(ResponseCode.invalidElementInList, respCode); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/util/CloudStorageUtilTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/util/CloudStorageUtilTest.java new file mode 100644 index 0000000000..eb89419a8f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/util/CloudStorageUtilTest.java @@ -0,0 +1,86 @@ +package org.sunbird.common.util; + +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cloud.storage.BaseStorageService; +import org.sunbird.cloud.storage.factory.StorageServiceFactory; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.util.CloudStorageUtil.CloudStorageType; +import scala.Option; + +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +@PrepareForTest({StorageServiceFactory.class, CloudStorageUtil.class}) +public class CloudStorageUtilTest { + + private static final String SIGNED_URL = "singedUrl"; + private static final String UPLOAD_URL = "uploadUrl"; + + @Before + public void initTest() { + BaseStorageService service = mock(BaseStorageService.class); + mockStatic(StorageServiceFactory.class); + + try { + when(StorageServiceFactory.class, "getStorageService", Mockito.any()).thenReturn(service); + + when(service.upload( + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyString(), + Mockito.any(Option.class), + Mockito.any(Option.class), + Mockito.any(Option.class), + Mockito.any(Option.class))) + .thenReturn(UPLOAD_URL); + + when(service.getSignedURL( + Mockito.anyString(), + Mockito.anyString(), + Mockito.any(Option.class), + Mockito.any(Option.class))) + .thenReturn(SIGNED_URL); + + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + + @Test + public void testGetStorageTypeSuccess() { + CloudStorageType storageType = CloudStorageType.getByName("azure"); + assertTrue(CloudStorageType.AZURE.equals(storageType)); + } + + @Test(expected = ProjectCommonException.class) + public void testGetStorageTypeFailureWithWrongType() { + CloudStorageType.getByName("wrongstorage"); + } + + @Test + @Ignore + public void testUploadSuccess() { + String result = + CloudStorageUtil.upload(CloudStorageType.AZURE, "container", "key", "/file/path"); + assertTrue(UPLOAD_URL.equals(result)); + } + + @Test + @Ignore + public void testGetSignedUrlSuccess() { + String signedUrl = CloudStorageUtil.getSignedUrl(CloudStorageType.AZURE, "container", "key"); + assertTrue(SIGNED_URL.equals(signedUrl)); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/util/ConfigUtilTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/util/ConfigUtilTest.java new file mode 100644 index 0000000000..af5e259357 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/common/util/ConfigUtilTest.java @@ -0,0 +1,67 @@ +package org.sunbird.common.util; + +import static org.junit.Assert.assertTrue; + +import com.typesafe.config.Config; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.responsecode.ResponseCode; + +@PrepareForTest(ConfigUtil.class) +@RunWith(PowerMockRunner.class) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class ConfigUtilTest { + + private String configType = "user"; + private String validJson = "{\"key\" : \"value\"}"; + private static ConfigUtil configUtilMock; + + @BeforeClass + public static void setup() throws Exception { + configUtilMock = Mockito.mock(ConfigUtil.class); + PowerMockito.whenNew(ConfigUtil.class).withAnyArguments().thenReturn(configUtilMock); + } + + @Test(expected = ProjectCommonException.class) + public void testGetConfigFromJsonStringFailureWithNullString() { + try { + ConfigUtil.getConfigFromJsonString(null, configType); + } catch (ProjectCommonException e) { + assertTrue(e.getCode().equals(ResponseCode.errorConfigLoadEmptyString.getErrorCode())); + throw e; + } + } + + @Test(expected = ProjectCommonException.class) + public void testGetConfigFromJsonStringFailureWithEmptyString() { + try { + ConfigUtil.getConfigFromJsonString("", configType); + } catch (ProjectCommonException e) { + assertTrue(e.getCode().equals(ResponseCode.errorConfigLoadEmptyString.getErrorCode())); + throw e; + } + } + + @Test(expected = ProjectCommonException.class) + public void testGetConfigFromJsonStringFailureWithInvalidJsonString() { + try { + ConfigUtil.getConfigFromJsonString("{dummy}", configType); + } catch (ProjectCommonException e) { + assertTrue(e.getCode().equals(ResponseCode.errorConfigLoadParseString.getErrorCode())); + throw e; + } + } + + @Test + public void testGetConfigFromJsonStringSuccess() { + Config config = ConfigUtil.getConfigFromJsonString(validJson, configType); + assertTrue("value".equals(config.getString("key"))); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/service/profile/ProfileCompletenessTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/service/profile/ProfileCompletenessTest.java new file mode 100644 index 0000000000..a00d194b0e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/service/profile/ProfileCompletenessTest.java @@ -0,0 +1,190 @@ +/** */ +package org.sunbird.service.profile; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.services.ProfileCompletenessService; +import org.sunbird.common.services.impl.ProfileCompletenessFactory; + +/** + * This test class have the assumption that each profile attribute have the same weighted. for more + * details look at profilecompleteness.properties. + * + * @author Manzarul + */ +public class ProfileCompletenessTest { + + private ProfileCompletenessService service = ProfileCompletenessFactory.getInstance(); + + @Test + public void allCompleteProfilePercentageTest() { + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.FIRST_NAME, "test"); + requestMap.put(JsonKey.LAST_NAME, "dsj"); + requestMap.put(JsonKey.EMAIL, "test@test.com"); + requestMap.put(JsonKey.PHONE, "3455556656"); + requestMap.put(JsonKey.PROFILE_SUMMARY, "profile is completed"); + requestMap.put(JsonKey.SUBJECT, "Math,Physics"); + requestMap.put(JsonKey.LANGUAGE, "Hindi"); + requestMap.put(JsonKey.DOB, "1995-08-09"); + requestMap.put("avatar", "some img url"); + requestMap.put(JsonKey.GRADE, "5th,6th,7th"); + requestMap.put(JsonKey.GENDER, "MALE"); + requestMap.put(JsonKey.LOCATION, "hdsvdjdjsfkf"); + requestMap.put(JsonKey.USERNAME, "test@test"); + Map address = new HashMap<>(); + address.put(JsonKey.CITY, "Bangalore"); + address.put(JsonKey.STATE, "sdkjdfjks"); + List> list = new ArrayList<>(); + list.add(address); + requestMap.put(JsonKey.ADDRESS, list); + Map edu = new HashMap<>(); + edu.put(JsonKey.COURSE, "M.C.A"); + edu.put(JsonKey.PERCENTAGE, 98); + List> eduList = new ArrayList<>(); + eduList.add(edu); + requestMap.put(JsonKey.EDUCATION, eduList); + Map job = new HashMap<>(); + job.put(JsonKey.JOB_NAME, "teacher"); + List> jobList = new ArrayList<>(); + jobList.add(job); + requestMap.put(JsonKey.JOB_PROFILE, jobList); + Map response = service.computeProfile(requestMap); + int val = (int) response.get(JsonKey.COMPLETENESS); + if (val > 100) { + val = 100; + } + Assert.assertEquals(100, val); + } + + @Test + public void allCompleteProfileErrorFieldTest() { + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.FIRST_NAME, "test"); + requestMap.put(JsonKey.LAST_NAME, "dsj"); + requestMap.put(JsonKey.EMAIL, "test@test.com"); + requestMap.put(JsonKey.PHONE, "3455556656"); + requestMap.put(JsonKey.PROFILE_SUMMARY, "profile is completed"); + requestMap.put(JsonKey.SUBJECT, "Math,Physics"); + requestMap.put(JsonKey.LANGUAGE, "Hindi"); + requestMap.put(JsonKey.DOB, "1995-08-09"); + requestMap.put("avatar", "some img url"); + requestMap.put(JsonKey.GRADE, "5th,6th,7th"); + requestMap.put(JsonKey.GENDER, "MALE"); + requestMap.put(JsonKey.LOCATION, "hdsvdjdjsfkf"); + requestMap.put(JsonKey.USERNAME, "test@test"); + Map address = new HashMap<>(); + address.put(JsonKey.CITY, "Bangalore"); + address.put(JsonKey.STATE, "sdkjdfjks"); + List> list = new ArrayList<>(); + list.add(address); + requestMap.put(JsonKey.ADDRESS, list); + Map edu = new HashMap<>(); + edu.put(JsonKey.COURSE, "M.C.A"); + edu.put(JsonKey.PERCENTAGE, 98); + List> eduList = new ArrayList<>(); + eduList.add(edu); + requestMap.put(JsonKey.EDUCATION, eduList); + Map job = new HashMap<>(); + job.put(JsonKey.JOB_NAME, "teacher"); + List> jobList = new ArrayList<>(); + jobList.add(job); + requestMap.put(JsonKey.JOB_PROFILE, jobList); + Map response = service.computeProfile(requestMap); + List val = (List) response.get(JsonKey.MISSING_FIELDS); + Assert.assertEquals(0, val.size()); + } + + @Test + public void zeroPercentageTest() { + Map requestMap = new HashMap<>(); + Map response = service.computeProfile(requestMap); + int val = + (int) (response.get(JsonKey.COMPLETENESS) != null ? response.get(JsonKey.COMPLETENESS) : 0); + Assert.assertEquals(0, val); + } + + @Test + public void zeroPercentageErrorTest() { + Map requestMap = new HashMap<>(); + Map response = service.computeProfile(requestMap); + List val = (List) response.get(JsonKey.MISSING_FIELDS); + Assert.assertEquals(14, val.size()); + } + + @Test + public void basicProfilePercentageTest() { + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.FIRST_NAME, "test"); + requestMap.put(JsonKey.LAST_NAME, "dsj"); + requestMap.put(JsonKey.EMAIL, "test@test.com"); + requestMap.put(JsonKey.PHONE, "3455556656"); + requestMap.put(JsonKey.PROFILE_SUMMARY, "profile is completed"); + requestMap.put(JsonKey.SUBJECT, "Math,Physics"); + requestMap.put(JsonKey.LANGUAGE, "Hindi"); + requestMap.put(JsonKey.DOB, "1995-08-09"); + requestMap.put("avatar", "some img url"); + requestMap.put(JsonKey.GRADE, "5th,6th,7th"); + requestMap.put(JsonKey.GENDER, "MALE"); + requestMap.put(JsonKey.LOCATION, "hdsvdjdjsfkf"); + requestMap.put(JsonKey.USERNAME, "test@test"); + Map response = service.computeProfile(requestMap); + int val = (int) response.get(JsonKey.COMPLETENESS); + Assert.assertEquals(79, val); + requestMap.remove("avatar"); + response = service.computeProfile(requestMap); + val = (int) response.get(JsonKey.COMPLETENESS); + Assert.assertEquals(72, val); + requestMap.put("avatar", "some value"); + response = service.computeProfile(requestMap); + val = (int) response.get(JsonKey.COMPLETENESS); + Assert.assertEquals(79, val); + Map address = new HashMap<>(); + address.put(JsonKey.CITY, "Bangalore"); + address.put(JsonKey.STATE, "sdkjdfjks"); + List> list = new ArrayList<>(); + list.add(address); + requestMap.put(JsonKey.ADDRESS, list); + response = service.computeProfile(requestMap); + val = (int) response.get(JsonKey.COMPLETENESS); + Assert.assertEquals(86, val); + } + + @Test + public void profileCompletenessWithNullAttribute() { + Map requestMap = null; + Map response = service.computeProfile(requestMap); + int val = + (int) (response.get(JsonKey.COMPLETENESS) != null ? response.get(JsonKey.COMPLETENESS) : 0); + Assert.assertEquals(0, val); + } + + @Test + public void profileCompletenessWithList() { + Map requestMap = new HashMap<>(); + List attribute = new ArrayList<>(); + attribute.add("pro"); + requestMap.put("list", attribute); + Map response = service.computeProfile(requestMap); + int val = + (int) (response.get(JsonKey.COMPLETENESS) != null ? response.get(JsonKey.COMPLETENESS) : 0); + Assert.assertEquals(0, val); + } + + @Test + public void profileCompletenessWithMap() { + Map requestMap = new HashMap<>(); + Map attribute = new HashMap<>(); + attribute.put("pro", "test"); + requestMap.put("list", attribute); + Map response = service.computeProfile(requestMap); + int val = + (int) (response.get(JsonKey.COMPLETENESS) != null ? response.get(JsonKey.COMPLETENESS) : 0); + Assert.assertEquals(0, val); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/services/sso/impl/KeyCloakRsaKeyFetcherTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/services/sso/impl/KeyCloakRsaKeyFetcherTest.java new file mode 100644 index 0000000000..bb923d2e5d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/services/sso/impl/KeyCloakRsaKeyFetcherTest.java @@ -0,0 +1,90 @@ +package org.sunbird.services.sso.impl; + +import static org.powermock.api.mockito.PowerMockito.when; + +import java.security.PublicKey; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.models.util.KeyCloakConnectionProvider; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +// ** @author kirti. Junit test cases *//* + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + HttpClientBuilder.class, + CloseableHttpClient.class, + HttpGet.class, + CloseableHttpResponse.class, + HttpResponse.class, + HttpEntity.class, + EntityUtils.class, +}) +public class KeyCloakRsaKeyFetcherTest { + + public static final String FALSE_REALM = "false-realm"; + private static final HttpClientBuilder httpClientBuilder = + PowerMockito.mock(HttpClientBuilder.class); + private static CloseableHttpClient client = null; + private static CloseableHttpResponse response; + private static HttpEntity httpEntity; + + @Before + public void setUp() throws Exception { + + client = PowerMockito.mock(CloseableHttpClient.class); + PowerMockito.mockStatic(HttpClientBuilder.class); + when(HttpClientBuilder.create()).thenReturn(httpClientBuilder); + when(httpClientBuilder.build()).thenReturn(client); + httpEntity = PowerMockito.mock(HttpEntity.class); + PowerMockito.mockStatic(EntityUtils.class); + } + + @Test + public void testGetPublicKeyFromKeyCloakSuccess() throws Exception { + + response = PowerMockito.mock(CloseableHttpResponse.class); + when(client.execute(Mockito.any())).thenReturn(response); + when(response.getEntity()).thenReturn(httpEntity); + + String jsonString = + "{\"keys\":[{\"kid\":\"YOw4KbDjM0_HIdGkf_QhRfKc9qHc4W_8Bni91nKFyck\",\"kty\":\"RSA\",\"alg\":\"RS256\",\"use\":\"sig\",\"n\":\"" + + "5OwCfx4UZTUfUDSBjOg65HuE4ReOg9GhZyoDJNqbWFrsY3dz7C12lmM3rewBHoY0F5_KW0A7rniS9LcqDg2RODvV8pRtJZ_Ge-jsnPMBY5nDJeEW35PH9ewaBhbY3Dj0bZQda2KdHGwiQ" + + "zItMT4vw0uITKsFq9o1bcYj0QvPq10AE_wOx3T5xsysuTTkcvQ6evbbs6P5yz_SHhQFRTk7_ZhMwhBeTolvg9wF4yl4qwr220A1ORsLAwwydpmfMHU9RD97nzHDlhXTBAOhDoA3Z3wA8KG6V" + + "i3LxqTLNRVS4hgq310fHzWfCX7shFQxygijW9zit-X1WVXaS1NxazuLJw\",\"e\":\"AQAB\"}]}"; + + when(EntityUtils.toString(httpEntity)).thenReturn(jsonString); + + PublicKey key = + new KeyCloakRsaKeyFetcher() + .getPublicKeyFromKeyCloak( + KeyCloakConnectionProvider.SSO_URL, KeyCloakConnectionProvider.SSO_REALM); + + Assert.assertNotNull(key); + } + + @Test + public void testGetPublicKeyFromKeyCloakFailure() throws Exception { + + PublicKey key = + new KeyCloakRsaKeyFetcher() + .getPublicKeyFromKeyCloak(KeyCloakConnectionProvider.SSO_URL, FALSE_REALM); + + Assert.assertEquals(key, null); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/services/sso/impl/KeyCloakServiceImplTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/services/sso/impl/KeyCloakServiceImplTest.java new file mode 100644 index 0000000000..30524cb2b1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/services/sso/impl/KeyCloakServiceImplTest.java @@ -0,0 +1,358 @@ +package org.sunbird.services.sso.impl; + +import static org.powermock.api.mockito.PowerMockito.*; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import javax.ws.rs.core.Response; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.admin.client.resource.UsersResource; +import org.keycloak.representations.idm.UserRepresentation; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.BaseHttpTest; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.KeyCloakConnectionProvider; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; + +public class KeyCloakServiceImplTest extends BaseHttpTest { + + private SSOManager keyCloakService = SSOServiceFactory.getInstance(); + + private static Map userId = new HashMap<>(); + private static final String userName = UUID.randomUUID().toString().replaceAll("-", ""); + private static Class t = null; + + private static final Map USER_SUCCESS = new HashMap<>(); + + static { + USER_SUCCESS.put(JsonKey.USERNAME, userName); + USER_SUCCESS.put(JsonKey.PASSWORD, "password"); + USER_SUCCESS.put(JsonKey.FIRST_NAME, "A"); + USER_SUCCESS.put(JsonKey.LAST_NAME, "B"); + USER_SUCCESS.put(JsonKey.PHONE, "9870060000"); + USER_SUCCESS.put(JsonKey.EMAIL, userName.substring(0, 10)); + } + + private static final Map USER_SAME_EMAIL = new HashMap<>(); + + static { + USER_SAME_EMAIL.put(JsonKey.USERNAME, userName); + USER_SAME_EMAIL.put(JsonKey.PASSWORD, "password"); + USER_SAME_EMAIL.put(JsonKey.FIRST_NAME, "A"); + USER_SAME_EMAIL.put(JsonKey.LAST_NAME, "B"); + USER_SAME_EMAIL.put(JsonKey.PHONE, "9870060000"); + USER_SAME_EMAIL.put(JsonKey.EMAIL, userName.substring(0, 10)); + } + + private static UsersResource usersRes = mock(UsersResource.class); + + @BeforeClass + public static void init() { + try { + t = Class.forName("org.sunbird.services.sso.SSOServiceFactory"); + } catch (ClassNotFoundException e) { + } + Keycloak kcp = mock(Keycloak.class); + RealmResource realmRes = mock(RealmResource.class); + UserResource userRes = mock(UserResource.class); + UserRepresentation userRep = mock(UserRepresentation.class); + Response response = mock(Response.class); + PowerMockito.mockStatic(KeyCloakConnectionProvider.class); + try { + + doReturn(kcp).when(KeyCloakConnectionProvider.class, "getConnection"); + doReturn(realmRes).when(kcp).realm(Mockito.anyString()); + doReturn(usersRes).when(realmRes).users(); + doReturn(response) + .doThrow( + new ProjectCommonException( + ResponseCode.emailANDUserNameAlreadyExistError.getErrorCode(), + ResponseCode.emailANDUserNameAlreadyExistError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode())) + .doReturn(response) + .when(usersRes) + .create(Mockito.any(UserRepresentation.class)); + doReturn(201).when(response).getStatus(); + doReturn("userdata").when(response).getHeaderString(Mockito.eq("Location")); + + doReturn(userRes).when(usersRes).get(Mockito.anyString()); + doReturn(userRep).when(userRes).toRepresentation(); + doNothing().when(userRes).update(Mockito.any(UserRepresentation.class)); + + doNothing().when(userRes).remove(); + + Map map = new HashMap<>(); + map.put(JsonKey.LAST_LOGIN_TIME, Arrays.asList(String.valueOf(System.currentTimeMillis()))); + doReturn(map).when(userRep).getAttributes(); + when(userRep.getUsername()).thenReturn("userName"); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail( + "Failed in initialization of mock rules, underlying error: " + e.getLocalizedMessage()); + } + } + + @Test + public void testNewInstanceSucccess() { + Exception exp = null; + try { + Constructor constructor = t.getDeclaredConstructor(); + constructor.setAccessible(true); + SSOServiceFactory application = constructor.newInstance(); + Assert.assertNotNull(application); + } catch (Exception e) { + exp = e; + } + Assert.assertNull(exp); + } + + @Test + public void testGetUsernameById() { + String result = keyCloakService.getUsernameById("1234-567-890"); + Assert.assertNotNull(result); + } + + @Test + public void testUserUpdateTestSuccessWithAllData() { + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + request.put(JsonKey.FIRST_NAME, userName); + request.put(JsonKey.PHONE, "9870060000"); + request.put(JsonKey.EMAIL, userName.substring(0, 10)); + request.put(JsonKey.USERNAME, userName); + request.put(JsonKey.PROVIDER, "ntp"); + String result = keyCloakService.updateUser(request); + Assert.assertNotNull(result); + } + + @Test + public void testUpdateUserSuccessWithoutProvider() { + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + request.put(JsonKey.FIRST_NAME, userName); + request.put(JsonKey.PHONE, "9870060000"); + request.put(JsonKey.COUNTRY_CODE, "+91"); + request.put(JsonKey.EMAIL, userName.substring(0, 10)); + request.put(JsonKey.USERNAME, userName); + String result = keyCloakService.updateUser(request); + Assert.assertNotNull(result); + } + + @Test + public void testUpdateUserSuccessWithoutProviderAndCountryCode() { + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + request.put(JsonKey.FIRST_NAME, userName); + request.put(JsonKey.PHONE, "9870060000"); + request.put(JsonKey.EMAIL, userName.substring(0, 10)); + request.put(JsonKey.USERNAME, userName); + String result = keyCloakService.updateUser(request); + Assert.assertNotNull(result); + } + + @Test + public void testUpdateUserSuccessWithoutAnyField() { + + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + String result = keyCloakService.updateUser(request); + Assert.assertNotNull(result); + } + + @Test(expected = ProjectCommonException.class) + public void testDeactivateUserSuccess() { + + Map request = new HashMap(); + request.put(JsonKey.USER_ID, "123"); + request.put(JsonKey.FIRST_NAME, userName); + keyCloakService.deactivateUser(request); + } + + @Test(expected = ProjectCommonException.class) + public void testRemoveUserSuccess() { + + Map request = new HashMap(); + request.put(JsonKey.USER_ID, "123"); + keyCloakService.removeUser(request); + } + + @Test(expected = ProjectCommonException.class) + public void testVerifyTokenSuccess() { + keyCloakService.verifyToken( + "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI5emhhVnZDbl81OEtheHpldHBzYXNZQ2lEallkemJIX3U2LV93SDk4SEc0In0.eyJqdGkiOiI5ZmQzNzgzYy01YjZmLTQ3OWQtYmMzYy0yZWEzOGUzZmRmYzgiLCJleHAiOjE1MDUxMTQyNDYsIm5iZiI6MCwiaWF0IjoxNTA1MTEzNjQ2LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoic2VjdXJpdHktYWRtaW4tY29uc29sZSIsInN1YiI6ImIzYTZkMTY4LWJjZmQtNDE2MS1hYzVmLTljZjYyODIyNzlmMyIsInR5cCI6IkJlYXJlciIsImF6cCI6InNlY3VyaXR5LWFkbWluLWNvbnNvbGUiLCJub25jZSI6ImMxOGVlMDM2LTAyMWItNGVlZC04NWVhLTc0MjMyYzg2ZmI4ZSIsImF1dGhfdGltZSI6MTUwNTExMzY0Niwic2Vzc2lvbl9zdGF0ZSI6ImRiZTU2NDlmLTY4MDktNDA3NS05Njk5LTVhYjIyNWMwZTkyMiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOltdLCJyZXNvdXJjZV9hY2Nlc3MiOnt9LCJuYW1lIjoiTWFuemFydWwgaGFxdWUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0MTIzNDU2NyIsImdpdmVuX25hbWUiOiJNYW56YXJ1bCBoYXF1ZSIsImVtYWlsIjoidGVzdDEyM0B0LmNvbSJ9.Xdjqe16MSkiR94g-Uj_pVZ2L3gnIdKpkJ6aB82W_w_c3yEmx1mXYBdkxe4zMz3ks4OX_PWwSFEbJECHcnujUwF6Ula0xtXTfuESB9hFyiWHtVAhuh5UlCCwPnsihv5EqK6u-Qzo0aa6qZOiQK3Zo7FLpnPUDxn4yHyo3mRZUiWf76KTl8PhSMoXoWxcR2vGW0b-cPixILTZPV0xXUZoozCui70QnvTgOJDWqr7y80EWDkS4Ptn-QM3q2nJlw63mZreOG3XTdraOlcKIP5vFK992dyyHlYGqWVzigortS9Ah4cprFVuLlX8mu1cQvqHBtW-0Dq_JlcTMaztEnqvJ6XA"); + } + + @Test + public void testAddUserLoginTimeSuccess() { + boolean response = keyCloakService.addUserLoginTime(userId.get(JsonKey.USER_ID)); + Assert.assertEquals(true, response); + } + + @Test + public void testGetLastLoginTimeSuccess() { + String lastLoginTime = keyCloakService.getLastLoginTime(userId.get(JsonKey.USER_ID)); + Assert.assertNull(lastLoginTime); + } + + @Ignore + public void testActiveUserSuccess() { + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + String response = keyCloakService.activateUser(reqMap); + Assert.assertEquals(JsonKey.SUCCESS, response); + } + + @Test + public void testActivateUserFailureWithEmptyUserId() { + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, ""); + try { + keyCloakService.activateUser(reqMap); + } catch (ProjectCommonException e) { + Assert.assertEquals(ResponseCode.invalidUsrData.getErrorCode(), e.getCode()); + Assert.assertEquals(ResponseCode.invalidUsrData.getErrorMessage(), e.getMessage()); + Assert.assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + } + + @Test + public void testIsEmailVerifiedSuccess() { + boolean response = keyCloakService.isEmailVerified(userId.get(JsonKey.USER_ID)); + Assert.assertEquals(false, response); + } + + @Test + public void testSetEmailVerifiedSuccessWithVerifiedFalse() { + keyCloakService.setEmailVerifiedAsFalse(userId.get(JsonKey.USER_ID)); + boolean response = keyCloakService.isEmailVerified(userId.get(JsonKey.USER_ID)); + Assert.assertNotEquals(true, response); + } + + @Test + public void testSetEmailVerifiedSuccessWithVerifiedUpdateFalse() { + keyCloakService.setEmailVerifiedUpdatedFlag(userId.get(JsonKey.USER_ID), "false"); + String response = keyCloakService.getEmailVerifiedUpdatedFlag(userId.get(JsonKey.USER_ID)); + Assert.assertEquals(false + "", response); + } + + @Test + public void testSetEmailVerifiedTrueSuccessWithVerifiedTrue() { + keyCloakService.setEmailVerifiedUpdatedFlag(userId.get(JsonKey.USER_ID), "true"); + String response = keyCloakService.getEmailVerifiedUpdatedFlag(userId.get(JsonKey.USER_ID)); + Assert.assertEquals(true + "", response); + } + + @Test + public void testSetEmailVerifiedSuccessWithVerifiedTrue() { + String response = keyCloakService.setEmailVerifiedTrue(userId.get(JsonKey.USER_ID)); + Assert.assertEquals(JsonKey.SUCCESS, response); + } + + @Test + public void testSyncUserDataSuccess() { + Map request = new HashMap(); + request.put(JsonKey.USERNAME, userName); + request.put(JsonKey.PROVIDER, "ntp"); + request.put(JsonKey.PASSWORD, "password"); + request.put(JsonKey.FIRST_NAME, "A"); + request.put(JsonKey.LAST_NAME, "B"); + request.put(JsonKey.PHONE, "9870060000"); + request.put(JsonKey.COUNTRY_CODE, "+91"); + request.put(JsonKey.EMAIL, userName.substring(0, 10)); + request.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + String response = keyCloakService.syncUserData(request); + Assert.assertEquals(JsonKey.SUCCESS, response); + } + + @Test + public void testSyncUserDataSuccessWithoutCountryCode() { + Map request = new HashMap(); + request.put(JsonKey.USERNAME, userName); + request.put(JsonKey.PROVIDER, "ntp"); + request.put(JsonKey.PASSWORD, "password"); + request.put(JsonKey.FIRST_NAME, "A"); + request.put(JsonKey.LAST_NAME, "B"); + request.put(JsonKey.PHONE, "9870060000"); + request.put(JsonKey.EMAIL, userName.substring(0, 10)); + request.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + String response = keyCloakService.syncUserData(request); + Assert.assertEquals(JsonKey.SUCCESS, response); + } + + @Test + public void testSyncUserDataSuccessWithoutProvider() { + Map request = new HashMap(); + request.put(JsonKey.USERNAME, userName); + request.put(JsonKey.PASSWORD, "password"); + request.put(JsonKey.FIRST_NAME, "A"); + request.put(JsonKey.LAST_NAME, "B"); + request.put(JsonKey.PHONE, "9870060000"); + request.put(JsonKey.EMAIL, userName.substring(0, 10)); + request.put(JsonKey.USER_ID, userId.get(JsonKey.USER_ID)); + String response = keyCloakService.syncUserData(request); + Assert.assertEquals(JsonKey.SUCCESS, response); + } + + @Test + public void testSyncUserDataSuccessWithInvalidUser() { + Map request = new HashMap(); + request.put(JsonKey.USERNAME, userName); + request.put(JsonKey.PASSWORD, "password"); + request.put(JsonKey.FIRST_NAME, "A"); + request.put(JsonKey.LAST_NAME, "B"); + request.put(JsonKey.PHONE, "9870060000"); + request.put(JsonKey.EMAIL, userName.substring(0, 10)); + request.put(JsonKey.USER_ID, "xey123-23sss-cbdsgdgdg"); + try { + keyCloakService.syncUserData(request); + } catch (ProjectCommonException e) { + Assert.assertEquals(ResponseCode.invalidUsrData.getErrorCode(), e.getCode()); + Assert.assertEquals(ResponseCode.CLIENT_ERROR.getResponseCode(), e.getResponseCode()); + } + } + + @Test + public void testDoPasswordUpdateSuccess() { + boolean response = keyCloakService.doPasswordUpdate(userId.get(JsonKey.USER_ID), "password"); + Assert.assertEquals(true, response); + } + + @Test + public void testGetFederatedUserId() + throws ClassNotFoundException, InstantiationException, IllegalAccessException, + NoSuchMethodException, SecurityException, IllegalArgumentException, + InvocationTargetException { + KeyCloakServiceImpl.class.getDeclaredMethods(); + Method m = KeyCloakServiceImpl.class.getDeclaredMethod("getFederatedUserId", String.class); + m.setAccessible(true); + SSOManager keyCloakService = SSOServiceFactory.getInstance(); + String fedUserId = (String) m.invoke(keyCloakService, "userId"); + Assert.assertEquals( + "f:" + + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_KEYCLOAK_USER_FEDERATION_PROVIDER_ID) + + ":userId", + fedUserId); + } + + @Test + public void testUpdatePassword() throws Exception { + boolean updated = keyCloakService.updatePassword(userId.get(JsonKey.USER_ID), "password"); + Assert.assertTrue(updated); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/telemetry/util/validator/TelemetryGeneratorTest.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/telemetry/util/validator/TelemetryGeneratorTest.java new file mode 100644 index 0000000000..5975eaeecf --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/telemetry/util/validator/TelemetryGeneratorTest.java @@ -0,0 +1,104 @@ +package org.sunbird.telemetry.util.validator; + +import static org.junit.Assert.*; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.telemetry.dto.Context; +import org.sunbird.telemetry.dto.Producer; +import org.sunbird.telemetry.util.TelemetryGenerator; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({TelemetryGenerator.class}) +public class TelemetryGeneratorTest { + + private static Map context; + private static Map rollup; + + @Before + public void setUp() throws Exception { + context = new HashMap(); + rollup = new HashMap(); + context.put("actorType", "consumer"); + context.put("telemetry_pdata_pid", "learning-service"); + context.put("actorId", "X-Consumer-ID"); + context.put("requestId", "8e27cbf5-e299-43b0-bca7-8347f7e5abcf"); + context.put("channel", "ORG_001"); + context.put("telemetry_pdata_ver", "1.15"); + context.put("REQUEST_ID", "8e27cbf5-e299-43b0-bca7-8347f7e5abcf"); + context.put("env", "User"); + context.put("did", "postman"); + } + + @Test + public void testGetContextWithoutRollUp() + throws InvocationTargetException, IllegalAccessException { + Method method = Whitebox.getMethod(TelemetryGenerator.class, "getContext", Map.class); + Context ctx = (Context) method.invoke(null, context); + assertEquals("postman", ctx.getDid()); + assertEquals("ORG_001", ctx.getChannel()); + assertEquals("User", ctx.getEnv()); + } + + @Test + public void testGetContextWithRollUp() throws InvocationTargetException, IllegalAccessException { + rollup.put("id", 1); + context.put("rollup", rollup); + Method method = Whitebox.getMethod(TelemetryGenerator.class, "getContext", Map.class); + Context ctx = (Context) method.invoke(null, context); + assertTrue(rollup.equals(ctx.getRollup())); + } + + @Test + public void testRemoveAttributes() throws InvocationTargetException, IllegalAccessException { + Method method = + Whitebox.getMethod(TelemetryGenerator.class, "removeAttributes", Map.class, String.class); + String[] removableProperty = {JsonKey.DEVICE_ID}; + method.invoke(null, context, removableProperty); + assertFalse(context.containsKey(JsonKey.DEVICE_ID)); + } + + @Test() + public void testGetProducerWithContextNull() + throws InvocationTargetException, IllegalAccessException { + + Map nullContext = null; + Method method = Whitebox.getMethod(TelemetryGenerator.class, "getProducer", Map.class); + Producer producer = (Producer) method.invoke(null, nullContext); + assertEquals("", producer.getId()); + assertEquals("", producer.getPid()); + assertEquals("", producer.getVer()); + } + + @Test + public void testGetProducerWithAppId() throws InvocationTargetException, IllegalAccessException { + context.put("appId", "random"); + Method method = Whitebox.getMethod(TelemetryGenerator.class, "getProducer", Map.class); + Producer producer = (Producer) method.invoke(null, context); + assertEquals("random", producer.getId()); + } + + @Test + public void testGetProducerWithoutAppId() + throws InvocationTargetException, IllegalAccessException { + context.put("telemetry_pdata_id", "local.sunbird.learning.service"); + Method method = Whitebox.getMethod(TelemetryGenerator.class, "getProducer", Map.class); + Producer producer = (Producer) method.invoke(null, context); + assertEquals("local.sunbird.learning.service", producer.getId()); + } + + @AfterClass + public static void tearDown() throws Exception { + context.clear(); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/telemetry/util/validator/TelemetryObjectValidatorV3Test.java b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/telemetry/util/validator/TelemetryObjectValidatorV3Test.java new file mode 100644 index 0000000000..f47bf968d2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/common-util/src/test/java/org/sunbird/telemetry/util/validator/TelemetryObjectValidatorV3Test.java @@ -0,0 +1,385 @@ +package org.sunbird.telemetry.util.validator; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.telemetry.dto.Actor; +import org.sunbird.telemetry.dto.Context; +import org.sunbird.telemetry.dto.Telemetry; +import org.sunbird.telemetry.util.TelemetryEvents; +import org.sunbird.telemetry.validator.TelemetryObjectValidatorV3; + +/** Created by arvind on 30/1/18. */ +public class TelemetryObjectValidatorV3Test { + + private TelemetryObjectValidatorV3 validatorV3 = new TelemetryObjectValidatorV3(); + private ObjectMapper mapper = new ObjectMapper(); + + @Test + public void testAuditWithValidData() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.AUDIT.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + Map auditEdata = new HashMap<>(); + List props = new ArrayList<>(); + props.add("username"); + props.add("org"); + auditEdata.put(JsonKey.PROPS, props); + telemetry.setEdata(auditEdata); + + boolean result = false; + try { + result = validatorV3.validateAudit(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertTrue(result); + } + + @Test + public void testAuditWithoutActor() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.AUDIT.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + Map auditEdata = new HashMap<>(); + List props = new ArrayList<>(); + props.add("username"); + props.add("org"); + auditEdata.put(JsonKey.PROPS, props); + telemetry.setEdata(auditEdata); + + boolean result = true; + try { + result = validatorV3.validateAudit(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertFalse(result); + } + + @Test + public void testAuditWithoutChannel() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.AUDIT.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + // context.setChannel("channel"); + + telemetry.setContext(context); + + Map auditEdata = new HashMap<>(); + List props = new ArrayList<>(); + props.add("username"); + props.add("org"); + auditEdata.put(JsonKey.PROPS, props); + telemetry.setEdata(auditEdata); + + boolean result = true; + try { + result = validatorV3.validateAudit(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertFalse(result); + } + + @Test + public void testAuditWithoutEnv() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.AUDIT.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + // context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + Map auditEdata = new HashMap<>(); + List props = new ArrayList<>(); + props.add("username"); + props.add("org"); + auditEdata.put(JsonKey.PROPS, props); + telemetry.setEdata(auditEdata); + + boolean result = true; + try { + result = validatorV3.validateAudit(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertFalse(result); + } + + @Test + public void testAuditWithoutEData() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.AUDIT.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + boolean result = true; + try { + result = validatorV3.validateAudit(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertFalse(result); + } + + @Test + public void testSearchWithValidData() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.SEARCH.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + Map searchEdata = new HashMap<>(); + searchEdata.put(JsonKey.TYPE, "user"); + searchEdata.put( + JsonKey.QUERY, + "\"filters\":{\n" + " \"lastName\": \"Test\"\n" + " \n" + " }"); + searchEdata.put(JsonKey.SIZE, new Long(10)); + searchEdata.put(JsonKey.TOPN, new ArrayList<>()); + telemetry.setEdata(searchEdata); + + boolean result = false; + try { + result = validatorV3.validateSearch(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertTrue(result); + } + + @Test + public void testSearchWithoutQuerySize() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.SEARCH.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + Map searchEdata = new HashMap<>(); + searchEdata.put(JsonKey.TYPE, "user"); + telemetry.setEdata(searchEdata); + + boolean result = true; + try { + result = validatorV3.validateSearch(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertFalse(result); + } + + @Test + public void testLogWithValidData() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.LOG.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + Map logEdata = new HashMap<>(); + logEdata.put(JsonKey.TYPE, "info"); + logEdata.put(JsonKey.LEVEL, JsonKey.API_ACCESS); + logEdata.put(JsonKey.MESSAGE, ""); + telemetry.setEdata(logEdata); + + boolean result = false; + try { + result = validatorV3.validateLog(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertTrue(result); + } + + @Test + public void testLogWithoutLogLevelType() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.LOG.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + + telemetry.setContext(context); + + Map logEdata = new HashMap<>(); + logEdata.put(JsonKey.MESSAGE, ""); + telemetry.setEdata(logEdata); + + boolean result = true; + try { + result = validatorV3.validateLog(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertFalse(result); + } + + @Test + public void testErrorWithValidData() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.ERROR.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + telemetry.setContext(context); + + Map errorEdata = new HashMap<>(); + errorEdata.put(JsonKey.ERROR, "invalid user"); + errorEdata.put(JsonKey.ERR_TYPE, JsonKey.API_ACCESS); + errorEdata.put(JsonKey.STACKTRACE, "error msg"); + telemetry.setEdata(errorEdata); + + boolean result = false; + try { + result = validatorV3.validateError(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertTrue(result); + } + + @Test + public void testErrorWithoutErrorTypeStackTrace() { + + Telemetry telemetry = new Telemetry(); + telemetry.setEid(TelemetryEvents.ERROR.getName()); + telemetry.setMid("dummy msg id"); + telemetry.setVer("3.0"); + + Actor actor = new Actor(); + actor.setId("1"); + actor.setType(JsonKey.USER); + telemetry.setActor(actor); + + Context context = new Context(); + context.setEnv(JsonKey.ORGANISATION); + context.setChannel("channel"); + telemetry.setContext(context); + + Map errorEdata = new HashMap<>(); + telemetry.setEdata(errorEdata); + + boolean result = true; + try { + result = validatorV3.validateError(mapper.writeValueAsString(telemetry)); + } catch (JsonProcessingException e) { + ProjectLogger.log(e.getMessage(), e); + } + Assert.assertFalse(result); + } +} diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/pom.xml new file mode 100644 index 0000000000..6cdfd1d804 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + org.sunbird + sunbird-platform-core + 1.0-SNAPSHOT + pom + sunbird-platform-core + + + common-util + actor-util + actor-core + sunbird-commons + + diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/sunbird-commons/.gitignore b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/sunbird-commons/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/sunbird-commons/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/sunbird-commons/pom.xml b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/sunbird-commons/pom.xml new file mode 100644 index 0000000000..5b1e492f31 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/sunbird-utils/sunbird-platform-core/sunbird-commons/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + org.sunbird + sunbird-commons + 1.0-SNAPSHOT + jar + Sunbird Commons + + UTF-8 + + + + org.sunbird + actor-core + 1.0-SNAPSHOT + + + org.sunbird + actor-util + 0.0.1-SNAPSHOT + + + org.sunbird + common-util + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.0.0 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + com.google.guava:guava + + + + + reference.conf + + + org.sunbird.middleware.Application + + + + + + + + + + diff --git a/actors/sunbird-lms-mw/actors/systemsettings/pom.xml b/actors/sunbird-lms-mw/actors/systemsettings/pom.xml new file mode 100644 index 0000000000..2ee41746b6 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/systemsettings/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + org.sunbird + mw-actors + 1.0-SNAPSHOT + ../pom.xml + + systemsettings + System Settings + + UTF-8 + + + + org.sunbird + actor-common + 1.0-SNAPSHOT + + + com.typesafe.akka + akka-testkit_2.11 + ${learner.akka.version} + test + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + **/*Spec.java + **/*Test.java + + + + + + diff --git a/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/actors/SystemSettingsActor.java b/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/actors/SystemSettingsActor.java new file mode 100644 index 0000000000..94b332dfae --- /dev/null +++ b/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/actors/SystemSettingsActor.java @@ -0,0 +1,122 @@ +package org.sunbird.systemsettings.actors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections4.MapUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.models.systemsetting.SystemSetting; +import org.sunbird.systemsettings.dao.impl.SystemSettingDaoImpl; + +@ActorConfig( + tasks = {"getSystemSetting", "getAllSystemSettings", "setSystemSetting"}, + asyncTasks = {} +) +public class SystemSettingsActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private final SystemSettingDaoImpl systemSettingDaoImpl = + new SystemSettingDaoImpl(cassandraOperation); + + @Override + public void onReceive(Request request) throws Throwable { + switch (request.getOperation()) { + case "getSystemSetting": + getSystemSetting(request); + break; + case "getAllSystemSettings": + getAllSystemSettings(); + break; + case "setSystemSetting": + setSystemSetting(request); + break; + default: + onReceiveUnsupportedOperation(request.getOperation()); + break; + } + } + + private void getSystemSetting(Request actorMessage) { + String value = + DataCacheHandler.getConfigSettings().get(actorMessage.getContext().get(JsonKey.FIELD)); + ProjectLogger.log( + "SystemSettingsActor:getSystemSetting: got field value from cache.", + LoggerEnum.INFO.name()); + SystemSetting setting = null; + if (value != null) { + setting = + new SystemSetting( + (String) actorMessage.getContext().get(JsonKey.FIELD), + (String) actorMessage.getContext().get(JsonKey.FIELD), + value); + } else { + setting = + systemSettingDaoImpl.readByField((String) actorMessage.getContext().get(JsonKey.FIELD)); + ProjectLogger.log( + "SystemSettingsActor:getSystemSetting:got field value from db", LoggerEnum.INFO.name()); + if (null == setting) { + throw new ProjectCommonException( + ResponseCode.resourceNotFound.getErrorCode(), + ResponseCode.resourceNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + DataCacheHandler.getConfigSettings() + .put((String) actorMessage.getContext().get(JsonKey.FIELD), setting.getValue()); + } + Response response = new Response(); + response.put(JsonKey.RESPONSE, setting); + sender().tell(response, self()); + } + + private void getAllSystemSettings() { + ProjectLogger.log("SystemSettingsActor: getAllSystemSettings called", LoggerEnum.DEBUG.name()); + Map systemSettings = DataCacheHandler.getConfigSettings(); + Response response = new Response(); + List allSystemSettings = null; + if (MapUtils.isNotEmpty(systemSettings)) { + allSystemSettings = new ArrayList<>(); + for (Map.Entry setting : systemSettings.entrySet()) { + allSystemSettings.add( + new SystemSetting( + (String) setting.getKey(), (String) setting.getKey(), (String) setting.getValue())); + } + } else { + allSystemSettings = systemSettingDaoImpl.readAll(); + } + response.put(JsonKey.RESPONSE, allSystemSettings); + sender().tell(response, self()); + } + + private void setSystemSetting(Request actorMessage) { + ProjectLogger.log("SystemSettingsActor: setSystemSetting called", LoggerEnum.DEBUG.name()); + + Map request = actorMessage.getRequest(); + String id = (String) request.get(JsonKey.ID); + String field = (String) request.get(JsonKey.FIELD); + if (JsonKey.PHONE_UNIQUE.equalsIgnoreCase(field) + || JsonKey.EMAIL_UNIQUE.equalsIgnoreCase(field) + || JsonKey.PHONE_UNIQUE.equalsIgnoreCase(id) + || JsonKey.EMAIL_UNIQUE.equalsIgnoreCase(id)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorUpdateSettingNotAllowed, + MessageFormat.format(ResponseCode.errorUpdateSettingNotAllowed.getErrorMessage(), field)); + } + ObjectMapper mapper = new ObjectMapper(); + SystemSetting systemSetting = mapper.convertValue(request, SystemSetting.class); + Response response = systemSettingDaoImpl.write(systemSetting); + sender().tell(response, self()); + } +} diff --git a/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/dao/SystemSettingDao.java b/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/dao/SystemSettingDao.java new file mode 100644 index 0000000000..f31fd3aaeb --- /dev/null +++ b/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/dao/SystemSettingDao.java @@ -0,0 +1,38 @@ +package org.sunbird.systemsettings.dao; + +import java.util.List; +import org.sunbird.common.models.response.Response; +import org.sunbird.models.systemsetting.SystemSetting; + +public interface SystemSettingDao { + /** + * Update system setting. + * + * @param systemSetting Setting information + * @return Response containing setting identifier. + */ + Response write(SystemSetting systemSetting); + + /** + * Read system setting for given identifier. + * + * @param id System setting identifier + * @return System setting information + */ + SystemSetting readById(String id); + + /** + * Read system setting for given field name. + * + * @param field System setting field name + * @return System setting information + */ + SystemSetting readByField(String field); + + /** + * Read all system settings. + * + * @return Response containing list of system settings. + */ + List readAll(); +} diff --git a/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/dao/impl/SystemSettingDaoImpl.java b/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/dao/impl/SystemSettingDaoImpl.java new file mode 100644 index 0000000000..fa87444de4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/systemsettings/src/main/java/org/sunbird/systemsettings/dao/impl/SystemSettingDaoImpl.java @@ -0,0 +1,87 @@ +package org.sunbird.systemsettings.dao.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections4.CollectionUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.models.systemsetting.SystemSetting; +import org.sunbird.systemsettings.dao.SystemSettingDao; + +public class SystemSettingDaoImpl implements SystemSettingDao { + private CassandraOperation cassandraOperation; + private static final String KEYSPACE_NAME = JsonKey.SUNBIRD; + private static final String TABLE_NAME = JsonKey.SYSTEM_SETTINGS_DB; + + public SystemSettingDaoImpl(CassandraOperation cassandraOperation) { + this.cassandraOperation = cassandraOperation; + } + + @Override + public Response write(SystemSetting systemSetting) { + ObjectMapper mapper = new ObjectMapper(); + Map map = mapper.convertValue(systemSetting, Map.class); + Response response = cassandraOperation.upsertRecord(KEYSPACE_NAME, TABLE_NAME, map); + response.put(JsonKey.ID, map.get(JsonKey.ID)); + return response; + } + + @Override + public SystemSetting readById(String id) { + Response response = cassandraOperation.getRecordById(KEYSPACE_NAME, TABLE_NAME, id); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(list)) { + return null; + } + return getSystemSetting(list); + } + + @Override + public SystemSetting readByField(String field) { + Response response = + cassandraOperation.getRecordsByIndexedProperty( + KEYSPACE_NAME, TABLE_NAME, JsonKey.FIELD, field); + List> list = (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(list)) { + return null; + } + return getSystemSetting(list); + } + + public List readAll() { + Response response = cassandraOperation.getAllRecords(KEYSPACE_NAME, TABLE_NAME); + List> list = (List>) response.get(JsonKey.RESPONSE); + List systemSettings = new ArrayList<>(); + ObjectMapper mapper = new ObjectMapper(); + list.forEach( + map -> { + SystemSetting systemSetting = mapper.convertValue(map, SystemSetting.class); + systemSettings.add(systemSetting); + }); + return systemSettings; + } + + private SystemSetting getSystemSetting(List> list) { + try { + ObjectMapper mapper = new ObjectMapper(); + String jsonString = mapper.writeValueAsString((list.get(0))); + return mapper.readValue(jsonString, SystemSetting.class); + } catch (IOException e) { + ProjectLogger.log( + "SystemSetting:getSystemSetting: Exception occurred with error messgae = " + + e.getMessage(), + LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException( + ResponseCode.SERVER_ERROR, ResponseCode.SERVER_ERROR.getErrorMessage()); + } + return null; + } +} diff --git a/actors/sunbird-lms-mw/actors/systemsettings/src/test/java/org/sunbird/systemsettings/actors/SystemSettingsActorTest.java b/actors/sunbird-lms-mw/actors/systemsettings/src/test/java/org/sunbird/systemsettings/actors/SystemSettingsActorTest.java new file mode 100644 index 0000000000..7077e0cfb3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/systemsettings/src/test/java/org/sunbird/systemsettings/actors/SystemSettingsActorTest.java @@ -0,0 +1,168 @@ +package org.sunbird.systemsettings.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import scala.concurrent.duration.FiniteDuration; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ElasticSearchRestHighImpl.class, + CassandraOperationImpl.class, + ServiceFactory.class, + EsClientFactory.class +}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class SystemSettingsActorTest { + private static final FiniteDuration ACTOR_MAX_WAIT_DURATION = duration("10 second"); + private ActorSystem system; + private Props props; + private TestKit probe; + private ActorRef subject; + private Request actorMessage; + private CassandraOperation cassandraOperation; + private static String ROOT_ORG_ID = "defaultRootOrgId"; + private static String FIELD = "someField"; + private static String VALUE = "someValue"; + private ElasticSearchRestHighImpl esUtil; + private static final String KEYSPACE_NAME = JsonKey.SUNBIRD; + private static final String TABLE_NAME = JsonKey.SYSTEM_SETTINGS_DB; + + @Before + public void setUp() { + system = ActorSystem.create("system"); + probe = new TestKit(system); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = PowerMockito.mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + props = Props.create(SystemSettingsActor.class); + subject = system.actorOf(props); + actorMessage = new Request(); + PowerMockito.mockStatic(EsClientFactory.class); + esUtil = PowerMockito.mock(ElasticSearchRestHighImpl.class); + Response resp = new Response(); + List> list = new ArrayList<>(); + list.add(getOrgData()); + resp.put(JsonKey.RESPONSE, list); + when(cassandraOperation.getRecordsByIndexedProperty( + KEYSPACE_NAME, TABLE_NAME, JsonKey.FIELD, ROOT_ORG_ID)) + .thenReturn(resp); + when(cassandraOperation.getRecordsByIndexedProperty( + KEYSPACE_NAME, TABLE_NAME, JsonKey.FIELD, KEYSPACE_NAME)) + .thenReturn(new Response()); + } + + private Map getOrgData() { + Map orgData = new HashMap(); + orgData.put(JsonKey.FIELD, ROOT_ORG_ID); + orgData.put(JsonKey.ID, ROOT_ORG_ID); + orgData.put(JsonKey.VALUE, VALUE); + return orgData; + } + + @Test + public void testSetSystemSettingSuccess() { + when(cassandraOperation.upsertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(new Response()); + actorMessage.setOperation(ActorOperations.SET_SYSTEM_SETTING.getValue()); + actorMessage.getRequest().putAll(getSystemSettingMap()); + subject.tell(actorMessage, probe.getRef()); + Response response = probe.expectMsgAnyClassOf(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testGetSystemSettingSuccess() { + actorMessage.setOperation(ActorOperations.GET_SYSTEM_SETTING.getValue()); + actorMessage.setContext(getOrgData()); + subject.tell(actorMessage, probe.getRef()); + Response response = probe.expectMsgAnyClassOf(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testGetSystemSettingFailure() { + // when(cassandraOperation.getRecordsByIndexedProperty(Mockito.anyString(), + // Mockito.anyString(), Mockito.anyString(), Mockito.any())).thenReturn(new Response()); + Map orgData = new HashMap(); + orgData.put(JsonKey.FIELD, KEYSPACE_NAME); + actorMessage.setOperation(ActorOperations.GET_SYSTEM_SETTING.getValue()); + actorMessage.setContext(orgData); + subject.tell(actorMessage, probe.getRef()); + ProjectCommonException exception = + probe.expectMsgAnyClassOf(ACTOR_MAX_WAIT_DURATION, ProjectCommonException.class); + Assert.assertTrue( + null != exception + && exception.getResponseCode() == ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + + @Test + public void testGetAllSystemSettingsSuccess() { + when(cassandraOperation.getAllRecords(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getSystemSettingResponse()); + actorMessage.setOperation(ActorOperations.GET_ALL_SYSTEM_SETTINGS.getValue()); + subject.tell(actorMessage, probe.getRef()); + Response response = probe.expectMsgAnyClassOf(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testGetAllSystemSettingsSuccessWithEmptyResponse() { + when(cassandraOperation.getAllRecords(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getSystemSettingEmptyResponse()); + actorMessage.setOperation(ActorOperations.GET_ALL_SYSTEM_SETTINGS.getValue()); + subject.tell(actorMessage, probe.getRef()); + Response response = probe.expectMsgAnyClassOf(ACTOR_MAX_WAIT_DURATION, Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + private Map getSystemSettingMap() { + Map orgData = new HashMap(); + orgData.put(JsonKey.ID, ROOT_ORG_ID); + orgData.put(JsonKey.FIELD, FIELD); + orgData.put(JsonKey.VALUE, VALUE); + return orgData; + } + + private Response getSystemSettingResponse() { + Response response = new Response(); + List> list = new ArrayList<>(); + list.add(getSystemSettingMap()); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private Response getSystemSettingEmptyResponse() { + Response response = new Response(); + response.put( + JsonKey.RESPONSE, + new ArrayList>(Arrays.asList(new HashMap()))); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/systemsettings/src/test/java/org/sunbird/systemsettings/dao/impl/SystemSettingDaoImplTest.java b/actors/sunbird-lms-mw/actors/systemsettings/src/test/java/org/sunbird/systemsettings/dao/impl/SystemSettingDaoImplTest.java new file mode 100644 index 0000000000..407e8ef3a2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/systemsettings/src/test/java/org/sunbird/systemsettings/dao/impl/SystemSettingDaoImplTest.java @@ -0,0 +1,100 @@ +package org.sunbird.systemsettings.dao.impl; + +import java.util.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.models.systemsetting.SystemSetting; +import org.sunbird.systemsettings.dao.SystemSettingDao; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({CassandraOperationImpl.class}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +public class SystemSettingDaoImplTest { + private CassandraOperation cassandraOperation; + private SystemSettingDao systemSettingDaoImpl; + private static String ROOT_ORG_ID = "defaultRootOrgId"; + private static String FIELD = "someField"; + private static String VALUE = "someValue"; + + @Before + public void setUp() { + cassandraOperation = PowerMockito.mock(CassandraOperationImpl.class); + systemSettingDaoImpl = new SystemSettingDaoImpl(cassandraOperation); + } + + @Test + public void testSetSystemSettingSuccess() { + PowerMockito.when( + cassandraOperation.upsertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(new Response()); + boolean thrown = false; + try { + SystemSetting systemSetting = new SystemSetting(ROOT_ORG_ID, FIELD, VALUE); + Response upsertResp = systemSettingDaoImpl.write(systemSetting); + Assert.assertNotEquals(null, upsertResp); + } catch (Exception e) { + thrown = true; + } + Assert.assertEquals(false, thrown); + } + + @Test + public void testReadSystemSettingSuccess() { + PowerMockito.when( + cassandraOperation.getRecordsByIndexedProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any())) + .thenReturn(getSystemSettingSuccessResponse(false)); + SystemSetting systemSetting = systemSettingDaoImpl.readByField(ROOT_ORG_ID); + Assert.assertTrue(null != systemSetting); + } + + @Test + public void testReadSystemSettingEmpty() { + PowerMockito.when( + cassandraOperation.getRecordsByIndexedProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any())) + .thenReturn(getSystemSettingSuccessResponse(true)); + SystemSetting systemSetting = systemSettingDaoImpl.readByField(FIELD); + Assert.assertTrue(null == systemSetting); + } + + @Test + public void testReadAllSystemSettingsSuccess() { + PowerMockito.when(cassandraOperation.getAllRecords(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getSystemSettingSuccessResponse(false)); + List result = systemSettingDaoImpl.readAll(); + Assert.assertTrue(null != result); + } + + @Test + public void testReadAllSystemSettingsEmpty() { + PowerMockito.when(cassandraOperation.getAllRecords(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getSystemSettingSuccessResponse(true)); + List result = systemSettingDaoImpl.readAll(); + Assert.assertTrue(null != result); + } + + private Response getSystemSettingSuccessResponse(boolean isEmpty) { + Response response = new Response(); + if (!isEmpty) + response.put( + JsonKey.RESPONSE, + new ArrayList>(Arrays.asList(new HashMap()))); + else { + response.put(JsonKey.RESPONSE, new ArrayList>()); + } + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/pom.xml b/actors/sunbird-lms-mw/actors/user/pom.xml new file mode 100644 index 0000000000..3f76be1906 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + org.sunbird + mw-actors + 1.0-SNAPSHOT + ../pom.xml + + user + Users + + UTF-8 + + + + org.sunbird + actor-common + 1.0-SNAPSHOT + + + com.typesafe.akka + akka-testkit_2.11 + ${learner.akka.version} + test + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + org/sunbird/models/**/* + org/sunbird/user/util/KafkaConfigConstants.class + org/sunbird/user/util/UserActorOperations.class + org/sunbird/user/util/UserConstants.class + org/sunbird/content/store/util/ContentStoreUtil.class + + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + **/*Spec.java + **/*Test.java + + + + + + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/content/store/util/ContentStoreUtil.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/content/store/util/ContentStoreUtil.java new file mode 100644 index 0000000000..cf4b28fe40 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/content/store/util/ContentStoreUtil.java @@ -0,0 +1,60 @@ +package org.sunbird.content.store.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import org.apache.http.HttpHeaders; +import org.sunbird.common.models.util.HttpUtil; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; + +public class ContentStoreUtil { + + private static Map getHeaders() { + Map headers = new HashMap<>(); + headers.put( + HttpHeaders.AUTHORIZATION, + JsonKey.BEARER + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_AUTHORIZATION)); + return headers; + } + + public static Map readFramework(String frameworkId) { + ProjectLogger.log( + "ContentStoreUtil:readFramework: frameworkId = " + frameworkId, LoggerEnum.INFO.name()); + return handleReadRequest(frameworkId, JsonKey.SUNBIRD_FRAMEWORK_READ_API); + } + + @SuppressWarnings("unchecked") + private static Map handleReadRequest(String id, String urlPath) { + Map headers = getHeaders(); + ObjectMapper mapper = new ObjectMapper(); + Map resultMap = new HashMap<>(); + + ProjectLogger.log("ContentStoreUtil:handleReadRequest: id = " + id, LoggerEnum.INFO.name()); + + try { + String requestUrl = + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_API_BASE_URL) + + ProjectUtil.getConfigValue(urlPath) + + "/" + + id; + String response = HttpUtil.sendGetRequest(requestUrl, headers); + + resultMap = mapper.readValue(response, Map.class); + if (!((String) resultMap.get(JsonKey.RESPONSE_CODE)).equalsIgnoreCase(JsonKey.OK)) { + ProjectLogger.log( + "ContentStoreUtil:handleReadRequest: Response code is not ok.", + LoggerEnum.ERROR.name()); + return null; + } + } catch (Exception e) { + ProjectLogger.log( + "ContentStoreUtil:handleReadRequest: Exception occurred with error message = " + + e.getMessage(), + e); + } + return resultMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/certificate/Certificate.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/certificate/Certificate.java new file mode 100644 index 0000000000..c264d5dc1c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/certificate/Certificate.java @@ -0,0 +1,112 @@ +package org.sunbird.models.certificate; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Certificate implements Serializable { + + private String id; + private String accessCode; + private Timestamp createdAt; + private Timestamp updatedAt; + private String userId; + private Map store; + private String otherLink; + private String oldId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAccessCode() { + return accessCode; + } + + public void setAccessCode(String accessCode) { + this.accessCode = accessCode; + } + + public Timestamp getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Timestamp createdAt) { + this.createdAt = createdAt; + } + + public Timestamp getUpTimesatmdAt() { + return updatedAt; + } + + public void setUpTimesatmdAt(Timestamp upTimesatmdAt) { + this.updatedAt = upTimesatmdAt; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + @JsonProperty("store") + public Map getStoreMap() { + return store; + } + + @JsonProperty("store") + public void setStore(Map store) { + this.store = store; + } + + public String getOtherLink() { + return otherLink; + } + + public void setOtherLink(String otherLink) { + this.otherLink = otherLink; + } + + @Override + public String toString() { + return "Certificate{" + + "id='" + + id + + '\'' + + ", accessCode='" + + accessCode + + '\'' + + ", createdAt=" + + createdAt + + ", updatedAt=" + + updatedAt + + ", userId='" + + userId + + '\'' + + ", store=" + + store + + ", otherLink='" + + otherLink + + '\'' + + '}'; + } + + public String getOldId() { + return oldId; + } + + public void setOldId(String oldId) { + this.oldId = oldId; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/organisation/Organisation.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/organisation/Organisation.java new file mode 100644 index 0000000000..c310b3f48d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/organisation/Organisation.java @@ -0,0 +1,347 @@ +package org.sunbird.models.organisation; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.List; + +/** + * @desc POJO class for Organisation + * @author Amit Kumar + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) +public class Organisation implements Serializable { + + private static final long serialVersionUID = 3617862727235741692L; + private String id; + private String addressId; + private String approvedBy; + private String approvedDate; + private String channel; + private String communityId; + private String contactDetail; + private String createdBy; + private String createdDate; + private Timestamp dateTime; + private String description; + private String email; + private String externalId; + private String hashTagId; + private String homeUrl; + private String imgUrl; + private Boolean isApproved; + private Boolean isDefault; + private Boolean isRootOrg; + private String locationId; + private Integer noOfMembers; + private String orgCode; + private String orgName; + private String orgType; + private String orgTypeId; + private String parentOrgId; + private String preferredLanguage; + private String provider; + private String rootOrgId; + private String slug; + private Integer status; + private String theme; + private String thumbnail; + private String updatedBy; + private String updatedDate; + private List locationIds; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAddressId() { + return addressId; + } + + public void setAddressId(String addressId) { + this.addressId = addressId; + } + + public String getApprovedBy() { + return approvedBy; + } + + public void setApprovedBy(String approvedBy) { + this.approvedBy = approvedBy; + } + + public String getApprovedDate() { + return approvedDate; + } + + public void setApprovedDate(String approvedDate) { + this.approvedDate = approvedDate; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getCommunityId() { + return communityId; + } + + public void setCommunityId(String communityId) { + this.communityId = communityId; + } + + public String getContactDetail() { + return contactDetail; + } + + public void setContactDetail(String contactDetail) { + this.contactDetail = contactDetail; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public String getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(String createdDate) { + this.createdDate = createdDate; + } + + public Timestamp getDateTime() { + return dateTime; + } + + public void setDateTime(Timestamp dateTime) { + this.dateTime = dateTime; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getHashTagId() { + return hashTagId; + } + + public void setHashTagId(String hashTagId) { + this.hashTagId = hashTagId; + } + + public String getHomeUrl() { + return homeUrl; + } + + public void setHomeUrl(String homeUrl) { + this.homeUrl = homeUrl; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getLocationId() { + return locationId; + } + + public void setLocationId(String locationId) { + this.locationId = locationId; + } + + public Integer getNoOfMembers() { + return noOfMembers; + } + + public void setNoOfMembers(Integer noOfMembers) { + this.noOfMembers = noOfMembers; + } + + public String getOrgCode() { + return orgCode; + } + + public void setOrgCode(String orgCode) { + this.orgCode = orgCode; + } + + public String getOrgName() { + return orgName; + } + + public void setOrgName(String orgName) { + this.orgName = orgName; + } + + public String getOrgType() { + return orgType; + } + + public void setOrgType(String orgType) { + this.orgType = orgType; + } + + public String getOrgTypeId() { + return orgTypeId; + } + + public void setOrgTypeId(String orgTypeId) { + this.orgTypeId = orgTypeId; + } + + public String getParentOrgId() { + return parentOrgId; + } + + public void setParentOrgId(String parentOrgId) { + this.parentOrgId = parentOrgId; + } + + public String getPreferredLanguage() { + return preferredLanguage; + } + + public void setPreferredLanguage(String preferredLanguage) { + this.preferredLanguage = preferredLanguage; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getRootOrgId() { + return rootOrgId; + } + + public void setRootOrgId(String rootOrgId) { + this.rootOrgId = rootOrgId; + } + + public String getSlug() { + return slug; + } + + public void setSlug(String slug) { + this.slug = slug; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getTheme() { + return theme; + } + + public void setTheme(String theme) { + this.theme = theme; + } + + public String getThumbnail() { + return thumbnail; + } + + public void setThumbnail(String thumbnail) { + this.thumbnail = thumbnail; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(String updatedDate) { + this.updatedDate = updatedDate; + } + + public List getLocationIds() { + return locationIds; + } + + public void setLocationIds(List locationIds) { + this.locationIds = locationIds; + } + + @JsonProperty(value = "isApproved") + public Boolean isApproved() { + return isApproved; + } + + public void setApproved(Boolean isApproved) { + this.isApproved = isApproved; + } + + @JsonProperty(value = "isDefault") + public Boolean isDefault() { + return isDefault; + } + + public void setDefault(Boolean isDefault) { + this.isDefault = isDefault; + } + + @JsonProperty(value = "isRootOrg") + public Boolean isRootOrg() { + return isRootOrg; + } + + public void setRootOrg(Boolean isRootOrg) { + this.isRootOrg = isRootOrg; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/user/org/UserOrg.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/user/org/UserOrg.java new file mode 100644 index 0000000000..15ce2b788b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/models/user/org/UserOrg.java @@ -0,0 +1,174 @@ +package org.sunbird.models.user.org; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserOrg implements Serializable { + private static final long serialVersionUID = 1L; + + private String id; + private String addedBy; + private String addedByName; + private String approvalDate; + private String approvedBy; + private String hashTagId; + private boolean isApproved; + private boolean isDeleted; + private boolean isRejected; + private String organisationId; + private String orgJoinDate; + private String orgLeftDate; + private String position; + private List roles; + private String updatedBy; + private String updatedDate; + private String userId; + + public static long getSerialVersionUID() { + return serialVersionUID; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAddedBy() { + return addedBy; + } + + public void setAddedBy(String addedBy) { + this.addedBy = addedBy; + } + + public String getAddedByName() { + return addedByName; + } + + public void setAddedByName(String addedByName) { + this.addedByName = addedByName; + } + + public String getApprovalDate() { + return approvalDate; + } + + public void setApprovalDate(String approvalDate) { + this.approvalDate = approvalDate; + } + + public String getApprovedBy() { + return approvedBy; + } + + public void setApprovedBy(String approvedBy) { + this.approvedBy = approvedBy; + } + + public String getHashTagId() { + return hashTagId; + } + + public void setHashTagId(String hashTagId) { + this.hashTagId = hashTagId; + } + + @JsonProperty(value = "isApproved") + public boolean isApproved() { + return isApproved; + } + + public void setApproved(boolean isApproved) { + this.isApproved = isApproved; + } + + @JsonProperty(value = "isDeleted") + public boolean isDeleted() { + return isDeleted; + } + + public void setDeleted(boolean isDeleted) { + this.isDeleted = isDeleted; + } + + @JsonProperty(value = "isRejected") + public boolean isRejected() { + return isRejected; + } + + public void setRejected(boolean isRejected) { + this.isRejected = isRejected; + } + + public String getOrganisationId() { + return organisationId; + } + + public void setOrganisationId(String organisationId) { + this.organisationId = organisationId; + } + + public String getOrgJoinDate() { + return orgJoinDate; + } + + public void setOrgJoinDate(String orgJoinDate) { + this.orgJoinDate = orgJoinDate; + } + + public String getOrgLeftDate() { + return orgLeftDate; + } + + public void setOrgLeftDate(String orgLeftDate) { + this.orgLeftDate = orgLeftDate; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(String updatedDate) { + this.updatedDate = updatedDate; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/AddressManagementActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/AddressManagementActor.java new file mode 100644 index 0000000000..b410d27a94 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/AddressManagementActor.java @@ -0,0 +1,162 @@ +package org.sunbird.user.actors; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.user.dao.AddressDao; +import org.sunbird.user.dao.impl.AddressDaoImpl; + +@ActorConfig( + tasks = {"insertUserAddress", "updateUserAddress"}, + asyncTasks = {"insertUserAddress", "updateUserAddress"} +) +public class AddressManagementActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + switch (operation) { + case "insertUserAddress": + insertAddress(request); + break; + + case "updateUserAddress": + updateAddress(request); + break; + + default: + onReceiveUnsupportedOperation("AddressManagementActor"); + } + } + + @SuppressWarnings("unchecked") + private void insertAddress(Request request) { + Map requestMap = request.getRequest(); + List> addressList = + (List>) requestMap.get(JsonKey.ADDRESS); + Response response = new Response(); + List errMsgs = new ArrayList<>(); + List> responseAddressList = new ArrayList<>(); + EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null); + try { + String encUserId = encryptionService.encryptData((String) requestMap.get(JsonKey.ID)); + String encCreatedById = + encryptionService.encryptData((String) requestMap.get(JsonKey.CREATED_BY)); + for (int i = 0; i < addressList.size(); i++) { + try { + Map address = addressList.get(i); + responseAddressList.add(createAddress(encUserId, encCreatedById, address)); + } catch (ProjectCommonException e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log( + "AddressManagementActor:insertAddress: Exception occurred with error message = " + + e.getMessage(), + e); + } catch (Exception e) { + errMsgs.add("Error occurred while inserting address details."); + ProjectLogger.log( + "AddressManagementActor:insertAddress: Generic exception occurred with error message = " + + e.getMessage(), + e); + } + } + } catch (Exception e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log(e.getMessage(), e); + } + response.put(JsonKey.ADDRESS, responseAddressList); + response.put(JsonKey.KEY, JsonKey.ADDRESS); + if (CollectionUtils.isNotEmpty(errMsgs)) { + response.put(JsonKey.ERROR_MSG, errMsgs); + } else { + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + } + sender().tell(response, self()); + } + + @SuppressWarnings("unchecked") + private void updateAddress(Request request) { + Map requestMap = request.getRequest(); + List> addressList = + (List>) requestMap.get(JsonKey.ADDRESS); + Response response = new Response(); + List errMsgs = new ArrayList<>(); + List> responseAddressList = new ArrayList<>(); + EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null); + try { + String encUserId = encryptionService.encryptData((String) requestMap.get(JsonKey.ID)); + String encCreatedById = + encryptionService.encryptData((String) requestMap.get(JsonKey.CREATED_BY)); + AddressDao addressDao = AddressDaoImpl.getInstance(); + for (int i = 0; i < addressList.size(); i++) { + try { + Map address = addressList.get(i); + if (BooleanUtils.isTrue((boolean) address.get(JsonKey.IS_DELETED)) + && !StringUtils.isBlank((String) address.get(JsonKey.ID))) { + addressDao.deleteAddress((String) address.get(JsonKey.ID)); + continue; + } + if (!address.containsKey(JsonKey.ID)) { + responseAddressList.add(createAddress(encUserId, encCreatedById, address)); + } else { + address.put(JsonKey.UPDATED_BY, encCreatedById); + address.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + address.remove(JsonKey.USER_ID); + addressDao.updateAddress(address); + responseAddressList.add(address); + } + } catch (ProjectCommonException e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log( + "AddressManagementActor:updateAddress: Exception occurred with error message = " + + e.getMessage(), + e); + } catch (Exception e) { + errMsgs.add("Error occurred while updating address details."); + ProjectLogger.log( + "AddressManagementActor:updateAddress: Generic exception occurred with error message = " + + e.getMessage(), + e); + } + } + } catch (Exception e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log(e.getMessage(), e); + } + response.put(JsonKey.ADDRESS, responseAddressList); + if (CollectionUtils.isNotEmpty(errMsgs)) { + response.put(JsonKey.KEY, JsonKey.ADDRESS); + response.put(JsonKey.ERROR_MSG, errMsgs); + } else { + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + } + sender().tell(response, self()); + } + + private Map createAddress( + String encUserId, String encCreatedById, Map address) { + AddressDao addressDao = AddressDaoImpl.getInstance(); + address.put(JsonKey.CREATED_BY, encCreatedById); + address.put(JsonKey.USER_ID, encUserId); + address.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(1)); + address.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + addressDao.createAddress(address); + return address; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/BackgroundUserDataEncryptionActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/BackgroundUserDataEncryptionActor.java new file mode 100644 index 0000000000..bc7c9c4550 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/BackgroundUserDataEncryptionActor.java @@ -0,0 +1,221 @@ +package org.sunbird.user.actors; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.user.service.UserEncryptionService; +import org.sunbird.user.service.impl.UserEncryptionServiceImpl; + +/** Background encrytion and decryption of user sensitive data. */ +@ActorConfig( + tasks = {}, + asyncTasks = {"backgroundEncryption", "backgroundDecryption"} +) +public class BackgroundUserDataEncryptionActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + switch (operation) { + case "backgroundEncryption": + backgroundEncrypt(request); + break; + case "backgroundDecryption": + backgroundDecrypt(request); + break; + default: + onReceiveUnsupportedOperation("BackgroundUserDataEncryptionActor"); + break; + } + } + + private void backgroundEncrypt(Request request) { + List> userDetails = getUserDetails(request); + encryptData(userDetails); + } + + private void backgroundDecrypt(Request request) { + List> userDetails = getUserDetails(request); + decryptData(userDetails); + } + + private void encryptData(List> userDetails) { + List userIdsListToSync = new ArrayList<>(); + if (CollectionUtils.isEmpty(userDetails)) { + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:encryptData: Empty user details.", LoggerEnum.INFO); + return; + } + UserEncryptionService userEncryptionService = UserEncryptionServiceImpl.getInstance(); + for (Map userMap : userDetails) { + List fieldsToEncrypt = userEncryptionService.getDecryptedFields(userMap); + if (CollectionUtils.isNotEmpty(fieldsToEncrypt)) { + encryptUserDataAndUpdateDB(userMap, fieldsToEncrypt); + userIdsListToSync.add((String) userMap.get(JsonKey.ID)); + } else { + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:encryptData: Cannot encrypt data for userId = " + + (String) userMap.get(JsonKey.ID), + LoggerEnum.INFO); + } + } + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:encryptData: Total number of user details to encrypt = " + + userIdsListToSync.size(), + LoggerEnum.INFO); + if (CollectionUtils.isNotEmpty(userIdsListToSync)) { + syncToES(userIdsListToSync); + } + } + + private void decryptData(List> userDetails) { + List userIdsListToSync = new ArrayList<>(); + if (CollectionUtils.isEmpty(userDetails)) { + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:decryptData: Empty user details.", LoggerEnum.INFO); + return; + } + UserEncryptionService userEncryptionService = UserEncryptionServiceImpl.getInstance(); + for (Map userMap : userDetails) { + List fieldsToDecrypt = userEncryptionService.getEncryptedFields(userMap); + if (CollectionUtils.isNotEmpty(fieldsToDecrypt)) { + decryptUserDataAndUpdateDB(userMap, fieldsToDecrypt); + userIdsListToSync.add((String) userMap.get(JsonKey.ID)); + } else { + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:decryptData: Cannot decrypt data for userId = " + + (String) userMap.get(JsonKey.ID), + LoggerEnum.INFO); + } + } + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:decryptData: Total number of user details to decrypt = " + + userIdsListToSync.size(), + LoggerEnum.INFO); + if (CollectionUtils.isNotEmpty(userIdsListToSync)) { + syncToES(userIdsListToSync); + } + } + + @SuppressWarnings("unchecked") + private List> getUserDetails(Request request) { + List userIds = (List) request.getRequest().get(JsonKey.USER_IDs); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Response response = + cassandraOperation.getRecordsByIdsWithSpecifiedColumns( + JsonKey.SUNBIRD, JsonKey.USER, null, userIds); + List> userList = (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(userList)) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidUserId); + } + return userList; + } + + private void encryptUserDataAndUpdateDB( + Map userMap, List fieldsToEncrypt) { + try { + UserUtility.encryptSpecificUserData(userMap, fieldsToEncrypt); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + cassandraOperation.updateRecord(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userMap); + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:encryptUserDataAndUpdateDB: Updating user data for userId = " + + ((String) userMap.get(JsonKey.ID)) + + " is completed", + LoggerEnum.INFO); + + List> addressList = getAddressList((String) userMap.get(JsonKey.ID)); + if (CollectionUtils.isNotEmpty(addressList)) { + UserUtility.encryptUserAddressData(addressList); + updateAddressList(addressList); + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:encryptUserDataAndUpdateDB: Updating user address data for userId = " + + ((String) userMap.get(JsonKey.ID)) + + " is completed", + LoggerEnum.INFO); + } + } catch (Exception e) { + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:encryptUserDataAndUpdateDB: Exception occurred with error message = " + + e.getMessage(), + e); + } + } + + private void decryptUserDataAndUpdateDB( + Map userMap, List fieldsToDecrypt) { + try { + UserUtility.decryptSpecificUserData(userMap, fieldsToDecrypt); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + cassandraOperation.updateRecord(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userMap); + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:decryptUserDataAndUpdateDB: Updating user data for userId = " + + ((String) userMap.get(JsonKey.ID)) + + " is completed", + LoggerEnum.INFO); + + List> addressList = getAddressList((String) userMap.get(JsonKey.ID)); + if (CollectionUtils.isNotEmpty(addressList)) { + UserUtility.decryptUserAddressData(addressList); + updateAddressList(addressList); + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:decryptUserDataAndUpdateDB: Updating user address data for userId = " + + ((String) userMap.get(JsonKey.ID)) + + " is completed", + LoggerEnum.INFO); + } + } catch (Exception e) { + ProjectLogger.log( + "BackgroundUserDataEncryptionActor:decryptUserDataAndUpdateDB: Exception occurred with error message = " + + e.getMessage(), + e); + } + } + + @SuppressWarnings("unchecked") + private List> getAddressList(String userId) { + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Util.DbInfo addrDbInfo = Util.dbInfoMap.get(JsonKey.ADDRESS_DB); + Response response = + cassandraOperation.getRecordsByProperty( + addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), JsonKey.USER_ID, userId); + return (List>) response.get(JsonKey.RESPONSE); + } + + private void updateAddressList(List> addressList) { + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Util.DbInfo addrDbInfo = Util.dbInfoMap.get(JsonKey.ADDRESS_DB); + for (Map address : addressList) { + cassandraOperation.updateRecord(addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), address); + } + } + + private void syncToES(List userIds) { + + Request backgroundSyncRequest = new Request(); + backgroundSyncRequest.setOperation(ActorOperations.BACKGROUND_SYNC.getValue()); + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.OBJECT_TYPE, JsonKey.USER); + requestMap.put(JsonKey.OBJECT_IDS, userIds); + backgroundSyncRequest.getRequest().put(JsonKey.DATA, requestMap); + + tellToAnother(backgroundSyncRequest); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/CertificateActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/CertificateActor.java new file mode 100644 index 0000000000..c60062ed32 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/CertificateActor.java @@ -0,0 +1,530 @@ +package org.sunbird.user.actors; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.sql.Timestamp; +import java.text.MessageFormat; +import java.util.*; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.HttpUtilResponse; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.models.certificate.Certificate; +import org.sunbird.models.user.User; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; + +/** This class helps in interacting with adding and validating the user-certificate details */ +@ActorConfig( + tasks = {"validateCertificate", "addCertificate", "getSignUrl", "mergeUserCertificate"}, + asyncTasks = {} +) +public class CertificateActor extends UserBaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private Util.DbInfo certDbInfo = Util.dbInfoMap.get(JsonKey.USER_CERT); + private Util.DbInfo userDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + private UserService userService = UserServiceImpl.getInstance(); + private DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + ""); + private DataMaskingService maskingService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getMaskingServiceInstance(""); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + if (request.getOperation().equals(ActorOperations.VALIDATE_CERTIFICATE.getValue())) { + getCertificate(request); + } else if (request + .getOperation() + .equalsIgnoreCase(ActorOperations.ADD_CERTIFICATE.getValue())) { + addCertificate(request); + } else if (request.getOperation().equalsIgnoreCase(ActorOperations.GET_SIGN_URL.getValue())) { + getSignUrl(request); + } else if (ActorOperations.MERGE_USER_CERTIFICATE.getValue().equals(request.getOperation())) { + mergeUserCertificate(request); + } else { + unSupportedMessage(); + } + } + + /** + * This method merges the certificates from custodian-user to non-custodian-user + * + * @param certRequest + */ + private void mergeUserCertificate(Request certRequest) { + Response userResult = new Response(); + Map request = certRequest.getRequest(); + String mergeeId = (String) request.get(JsonKey.FROM_ACCOUNT_ID); + String mergerId = (String) request.get(JsonKey.TO_ACCOUNT_ID); + Response response = + cassandraOperation.getRecordsByProperty( + certDbInfo.getKeySpace(), certDbInfo.getTableName(), JsonKey.USER_ID, mergeeId); + Map record = response.getResult(); + if (null != record && null != record.get(JsonKey.RESPONSE)) { + List responseList = (List) record.get(JsonKey.RESPONSE); + if (!responseList.isEmpty()) { + responseList.forEach( + responseMap -> { + Map responseDetails = (Map) responseMap; + responseDetails.put(JsonKey.USER_ID, mergerId); + }); + cassandraOperation.batchUpdateById( + certDbInfo.getKeySpace(), certDbInfo.getTableName(), responseList); + ProjectLogger.log( + "CertificateActor:getCertificate: cert details merged to user id : " + mergerId, + LoggerEnum.INFO.name()); + } else { + ProjectLogger.log( + "CertificateActor:getCertificate: cert details unavailable for user id : " + mergeeId, + LoggerEnum.INFO.name()); + } + userResult.setResponseCode(ResponseCode.success); + sender().tell(userResult, self()); + sendMergeNotification(mergeeId, mergerId); + triggerMergeCertTelemetry(request, certRequest.getContext()); + } + } + + private void sendMergeNotification(String mergeeId, String mergerId) { + ProjectLogger.log( + "CertificateActor:sendMergeNotification start sending merge notification to user " + + mergeeId + + " -" + + mergerId, + LoggerEnum.INFO.name()); + List ids = new ArrayList(); + ids.add(mergeeId); + ids.add(mergerId); + List attributeList = new ArrayList<>(); + attributeList.add(JsonKey.EMAIL); + attributeList.add(JsonKey.PHONE); + attributeList.add(JsonKey.PREV_USED_EMAIL); + attributeList.add(JsonKey.PREV_USED_PHONE); + attributeList.add(JsonKey.FIRST_NAME); + attributeList.add(JsonKey.ID); + List> userList = getUserByIdentifiers(ids, attributeList); + HashMap mergeeUserMap = new HashMap<>(); + HashMap mergerUserMap = new HashMap<>(); + if (userList != null && userList.size() == 2) { + mergeeUserMap = getMergeeUserDetails(userList, mergeeId); + mergerUserMap = getMergerUserDetails(userList, mergerId); + } + if (MapUtils.isNotEmpty(mergeeUserMap)) { + mergeeUserMap = createUserData(mergeeUserMap, false); + } else { + ProjectLogger.log( + "CertificateActor:sendMergeNotification mergee user account not found , so email or sms can't be sent " + + mergeeId, + LoggerEnum.INFO.name()); + return; + } + if (MapUtils.isNotEmpty(mergerUserMap)) { + mergerUserMap = createUserData(mergerUserMap, true); + } else { + ProjectLogger.log( + "CertificateActor:sendMergeNotification merger user account not found , so email or sms can't be sent " + + mergeeId, + LoggerEnum.INFO.name()); + return; + } + + Request emailReq = createNotificationData(mergeeUserMap, mergerUserMap); + tellToAnother(emailReq); + } + + private HashMap getMergeeUserDetails( + List> userList, String mergeeId) { + return getUserDetails(userList, mergeeId); + } + + private HashMap getMergerUserDetails( + List> userList, String mergerId) { + return getUserDetails(userList, mergerId); + } + + private HashMap getUserDetails( + List> userList, String userId) { + HashMap usermap = userList.get(0); + if (userId.equalsIgnoreCase((String) usermap.get(JsonKey.ID))) { + return usermap; + } else { + return userList.get(1); + } + } + + private HashMap createUserData( + HashMap userMap, boolean isMergerAccount) { + String MASK_IDENTIFIER = "maskIdentifier"; + if (isMergerAccount) { + if (StringUtils.isNotBlank((String) userMap.get(JsonKey.EMAIL))) { + String deceryptedEmail = decryptionService.decryptData((String) userMap.get(JsonKey.EMAIL)); + String maskEmail = maskingService.maskEmail(deceryptedEmail); + userMap.put(JsonKey.EMAIL, deceryptedEmail); + userMap.put(MASK_IDENTIFIER, maskEmail); + } else { + String deceryptedPhone = decryptionService.decryptData((String) userMap.get(JsonKey.PHONE)); + String maskPhone = maskingService.maskPhone(deceryptedPhone); + userMap.put(JsonKey.PHONE, deceryptedPhone); + userMap.put(MASK_IDENTIFIER, maskPhone); + } + } else { + if (StringUtils.isNotBlank((String) userMap.get(JsonKey.PREV_USED_EMAIL))) { + String deceryptedEmail = + decryptionService.decryptData((String) userMap.get(JsonKey.PREV_USED_EMAIL)); + String maskEmail = maskingService.maskEmail(deceryptedEmail); + userMap.put(JsonKey.PREV_USED_EMAIL, deceryptedEmail); + userMap.put(MASK_IDENTIFIER, maskEmail); + } else { + String deceryptedPhone = + decryptionService.decryptData((String) userMap.get(JsonKey.PREV_USED_PHONE)); + String maskPhone = maskingService.maskPhone(deceryptedPhone); + userMap.put(JsonKey.PREV_USED_PHONE, deceryptedPhone); + userMap.put(MASK_IDENTIFIER, maskPhone); + } + } + return userMap; + } + + private Request createNotificationData( + HashMap mergeeUserData, HashMap mergerUserData) { + Request request = new Request(); + Map requestMap = new HashMap<>(); + List identifiers = new ArrayList<>(); + requestMap.put(JsonKey.NAME, mergerUserData.get(JsonKey.FIRST_NAME)); + requestMap.put(JsonKey.FIRST_NAME, mergerUserData.get(JsonKey.FIRST_NAME)); + if (StringUtils.isNotBlank((String) mergerUserData.get(JsonKey.EMAIL))) { + identifiers.add((String) mergerUserData.get(JsonKey.EMAIL)); + requestMap.put(JsonKey.RECIPIENT_EMAILS, identifiers); + } else { + identifiers.add((String) mergerUserData.get(JsonKey.PHONE)); + requestMap.put(JsonKey.RECIPIENT_PHONES, identifiers); + requestMap.put(JsonKey.MODE, "sms"); + } + requestMap.put(JsonKey.EMAIL_TEMPLATE_TYPE, "accountMerge"); + String MASK_IDENTIFIER = "maskIdentifier"; + String body = + MessageFormat.format( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_ACCOUNT_MERGE_BODY), + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_INSTALLATION), + mergerUserData.get(MASK_IDENTIFIER), + mergeeUserData.get(MASK_IDENTIFIER)); + requestMap.put(JsonKey.BODY, body); + requestMap.put(JsonKey.SUBJECT, ProjectUtil.getConfigValue("sunbird_account_merge_subject")); + request.getRequest().put(JsonKey.EMAIL_REQUEST, requestMap); + request.setOperation(BackgroundOperations.emailService.name()); + return request; + } + + private List> getUserByIdentifiers( + List identifiers, List attributes) { + Response response = + cassandraOperation.getRecordsByIdsWithSpecifiedColumns( + userDbInfo.getKeySpace(), userDbInfo.getTableName(), attributes, identifiers); + Map record = response.getResult(); + if (record != null && record.get(JsonKey.RESPONSE) != null) { + List responseList = (List) record.get(JsonKey.RESPONSE); + ProjectLogger.log( + "CertificateActor:getUserByIdentifier user found with id:" + identifiers, + LoggerEnum.INFO.name()); + return responseList; + } + ProjectLogger.log( + "CertificateActor:getUserByIdentifier user not found with id:" + identifiers, + LoggerEnum.INFO.name()); + return null; + } + + /** + * This method validates the access-code of the certificate and retrieve certificate details. + * + * @param userRequest + */ + private void getCertificate(Request userRequest) throws IOException { + Map request = userRequest.getRequest(); + String certificatedId = (String) request.get(JsonKey.CERT_ID); + String accessCode = (String) request.get(JsonKey.ACCESS_CODE); + Map responseDetails = getCertificateDetails(certificatedId); + if (responseDetails.get(JsonKey.ACCESS_CODE.toLowerCase()).equals(accessCode)) { + Map userResponse = new HashMap(); + Response userResult = new Response(); + Map recordStore = (Map) responseDetails.get(JsonKey.STORE); + String jsonData = (String) recordStore.get(JsonKey.JSON_DATA); + ObjectMapper objectMapper = new ObjectMapper(); + userResponse.put(JsonKey.JSON, objectMapper.readValue(jsonData, Map.class)); + userResponse.put(JsonKey.PDF, recordStore.get(JsonKey.PDF_URL)); + userResponse.put(JsonKey.COURSE_ID, recordStore.get(JsonKey.COURSE_ID)); + userResponse.put(JsonKey.BATCH_ID, recordStore.get(JsonKey.BATCH_ID)); + ProjectLogger.log( + "CertificateActor:getCertificate: userMap got with certificateId " + .concat(certificatedId + "") + + " and response got " + + userResponse, + LoggerEnum.INFO.name()); + userResult.put(JsonKey.RESPONSE, userResponse); + sender().tell(userResult, self()); + } else { + ProjectLogger.log( + "CertificateActor:getCertificate: access code is incorrect : " + accessCode, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameter.getErrorMessage(), JsonKey.ACCESS_CODE), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private Map getCertificateDetails(String certificatedId) { + Map responseDetails = null; + Response response = + cassandraOperation.getRecordById( + certDbInfo.getKeySpace(), certDbInfo.getTableName(), certificatedId); + Map record = response.getResult(); + if (null != record && null != record.get(JsonKey.RESPONSE)) { + List responseList = (List) record.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(responseList)) { + responseDetails = (Map) responseList.get(0); + if (responseDetails.get(JsonKey.IS_DELETED) != null + && (boolean) responseDetails.get(JsonKey.IS_DELETED)) { + ProjectLogger.log( + "CertificateActor:getCertificate: certificate is deleted : ", + LoggerEnum.ERROR.name()); + ProjectCommonException.throwClientErrorException( + ResponseCode.errorUnavailableCertificate, null); + } + } else { + ProjectLogger.log( + "CertificateActor:getCertificate: cert id is incorrect : " + certificatedId, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameter.getErrorMessage(), JsonKey.CERT_ID), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + return responseDetails; + } + + private void addCertificate(Request request) throws JsonProcessingException { + Response response = null; + Map storeMap = new HashMap<>(); + Map telemetryMap = new HashMap(); + Map certAddReqMap = request.getRequest(); + String userId = (String) certAddReqMap.get(JsonKey.USER_ID); + String oldCertId = (String) certAddReqMap.get(JsonKey.OLD_ID); + User user = userService.getUserById(userId); + assureUniqueCertId((String) certAddReqMap.get(JsonKey.ID)); + populateStoreData(storeMap, certAddReqMap); + certAddReqMap.put(JsonKey.STORE, storeMap); + certAddReqMap = getRequiredRequest(certAddReqMap); + certAddReqMap.put(JsonKey.CREATED_AT, getTimeStamp()); + if (StringUtils.isNotBlank(oldCertId)) { + getCertificateDetails(oldCertId); + HashMap certUpdatedMap = new HashMap<>(certAddReqMap); + response = reIssueCert(certAddReqMap, certUpdatedMap); + telemetryMap.put(JsonKey.OLD_ID, oldCertId); + } else { + certAddReqMap.put(JsonKey.IS_DELETED, false); + response = + cassandraOperation.insertRecord( + certDbInfo.getKeySpace(), certDbInfo.getTableName(), certAddReqMap); + } + + ProjectLogger.log( + "CertificateActor:addCertificate:successfully added certificate in records with userId" + + certAddReqMap.get(JsonKey.USER_ID) + + " and certId:" + + certAddReqMap.get(JsonKey.CERT_ID), + LoggerEnum.INFO.name()); + sender().tell(response, self()); + telemetryMap.put(JsonKey.USER_ID, userId); + telemetryMap.put(JsonKey.CERT_ID, certAddReqMap.get(JsonKey.ID)); + telemetryMap.put(JsonKey.ROOT_ORG_ID, user.getRootOrgId()); + triggerAddCertTelemetry(telemetryMap, request.getContext()); + } + + private Response reIssueCert( + Map certAddReqMap, Map certUpdateReqMap) { + Map cassandraInput = new HashMap<>(); + cassandraInput.put(JsonKey.INSERT, certAddReqMap); + certAddReqMap.put(JsonKey.IS_DELETED, false); + certUpdateReqMap.put(JsonKey.ID, certAddReqMap.get(JsonKey.OLD_ID)); + certUpdateReqMap.remove(JsonKey.OLD_ID); + certUpdateReqMap.put(JsonKey.IS_DELETED, true); + cassandraInput.put(JsonKey.UPDATE, certUpdateReqMap); + return cassandraOperation.performBatchAction( + certDbInfo.getKeySpace(), certDbInfo.getTableName(), cassandraInput); + } + + private void populateStoreData( + Map storeMap, Map certAddRequestMap) + throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + storeMap.put(JsonKey.PDF_URL, (String) certAddRequestMap.get(JsonKey.PDF_URL)); + storeMap.put( + JsonKey.JSON_DATA, + objectMapper.writeValueAsString(certAddRequestMap.get(JsonKey.JSON_DATA))); + String batchId = (String) certAddRequestMap.get(JsonKey.BATCH_ID); + String courseId = (String) certAddRequestMap.get(JsonKey.COURSE_ID); + storeMap.put(JsonKey.BATCH_ID, StringUtils.isNotBlank(batchId) ? batchId : StringUtils.EMPTY); + storeMap.put(JsonKey.COURSE_ID, StringUtils.isNotBlank(batchId) ? courseId : StringUtils.EMPTY); + ProjectLogger.log( + "CertificateActor:populateStoreMapWithUrlAndIds: store map after populated: " + storeMap, + LoggerEnum.INFO.name()); + } + + private Map getRequiredRequest(Map certAddReqMap) { + ObjectMapper objectMapper = new ObjectMapper(); + Certificate certificate = objectMapper.convertValue(certAddReqMap, Certificate.class); + return objectMapper.convertValue(certificate, Map.class); + } + + private Timestamp getTimeStamp() { + return new Timestamp(Calendar.getInstance().getTime().getTime()); + } + + public void getSignUrl(Request request) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + HashMap certReqMap = new HashMap<>(); + certReqMap.put(JsonKey.REQUEST, request.getRequest()); + String requestBody = objectMapper.writeValueAsString(certReqMap); + String completeUrl = + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_CERT_SERVICE_BASE_URL) + + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_CERT_DOWNLOAD_URI); + ProjectLogger.log( + "CertificateActor:getSignUrl complete url found: " + completeUrl, LoggerEnum.INFO.name()); + + Map headerMap = new HashMap<>(); + headerMap.put("Content-Type", "application/json"); + HttpUtilResponse httpResponse = HttpUtil.doPostRequest(completeUrl, requestBody, headerMap); + if (httpResponse != null && httpResponse.getStatusCode() == 200) { + HashMap val = + (HashMap) objectMapper.readValue(httpResponse.getBody(), Map.class); + HashMap resultMap = (HashMap) val.get(JsonKey.RESULT); + Response response = new Response(); + response.put(JsonKey.SIGNED_URL, resultMap.get(JsonKey.SIGNED_URL)); + sender().tell(response, self()); + } else { + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameter.getErrorMessage(), JsonKey.PDF_URL), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + } catch (Exception e) { + ProjectLogger.log( + "CertificateActor:getSignUrl exception occurred :" + e, LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.SERVER_ERROR.getErrorCode(), + ResponseCode.SERVER_ERROR.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + private void assureUniqueCertId(String certificatedId) { + if (isIdentityPresent(certificatedId)) { + ProjectLogger.log( + "CertificateActor:addCertificate:provided certificateId exists in record " + .concat(certificatedId), + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.invalidParameter.getErrorCode(), + ResponseMessage.Message.DATA_ALREADY_EXIST, + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + ProjectLogger.log( + "CertificateActor:addCertificate:successfully certId not found in records creating new record", + LoggerEnum.INFO.name()); + } + + private boolean isIdentityPresent(String certificateId) { + Response response = + cassandraOperation.getRecordById( + certDbInfo.getKeySpace(), certDbInfo.getTableName(), certificateId); + Map record = response.getResult(); + if (null != record && null != record.get(JsonKey.RESPONSE)) { + List responseList = (List) record.get(JsonKey.RESPONSE); + if (!responseList.isEmpty()) { + return true; + } + } + return false; + } + + private void triggerMergeCertTelemetry(Map telemetryMap, Map context) { + ProjectLogger.log( + "UserMergeActor:triggerMergeCertTelemetry: generating telemetry event for merge certificate"); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + Map rollUp = new HashMap<>(); + rollUp.put("l1", (String) telemetryMap.get(JsonKey.ROOT_ORG_ID)); + context.put(JsonKey.ROLLUP, rollUp); + targetObject = + TelemetryUtil.generateTargetObject( + (String) telemetryMap.get(JsonKey.FROM_ACCOUNT_ID), + TelemetryEnvKey.USER, + JsonKey.MERGE_CERT, + null); + TelemetryUtil.generateCorrelatedObject( + (String) telemetryMap.get(JsonKey.FROM_ACCOUNT_ID), + JsonKey.FROM_ACCOUNT_ID, + null, + correlatedObject); + TelemetryUtil.generateCorrelatedObject( + (String) telemetryMap.get(JsonKey.TO_ACCOUNT_ID), + JsonKey.TO_ACCOUNT_ID, + null, + correlatedObject); + telemetryMap.remove(JsonKey.ID); + telemetryMap.remove(JsonKey.USER_ID); + telemetryMap.remove(JsonKey.ROOT_ORG_ID); + TelemetryUtil.telemetryProcessingCall(telemetryMap, targetObject, correlatedObject, context); + } + + private void triggerAddCertTelemetry(Map telemetryMap, Map context) { + ProjectLogger.log( + "UserMergeActor:triggerAddCertTelemetry: generating telemetry event for add certificate"); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + Map rollUp = new HashMap<>(); + rollUp.put("l1", (String) telemetryMap.get(JsonKey.ROOT_ORG_ID)); + context.put(JsonKey.ROLLUP, rollUp); + if (null != telemetryMap.get(JsonKey.OLD_ID)) { + TelemetryUtil.generateCorrelatedObject( + (String) telemetryMap.get(JsonKey.OLD_ID), + JsonKey.OLD_CERTIFICATE, + null, + correlatedObject); + } + targetObject = + TelemetryUtil.generateTargetObject( + (String) telemetryMap.get(JsonKey.CERT_ID), JsonKey.CERTIFICATE, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject( + (String) telemetryMap.get(JsonKey.USER_ID), JsonKey.USER, null, correlatedObject); + TelemetryUtil.generateCorrelatedObject( + (String) telemetryMap.get(JsonKey.CERT_ID), JsonKey.CERTIFICATE, null, correlatedObject); + telemetryMap.remove(JsonKey.ROOT_ORG_ID); + TelemetryUtil.telemetryProcessingCall(telemetryMap, targetObject, correlatedObject, context); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/EducationManagementActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/EducationManagementActor.java new file mode 100644 index 0000000000..8e004d835d --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/EducationManagementActor.java @@ -0,0 +1,283 @@ +package org.sunbird.user.actors; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.user.dao.AddressDao; +import org.sunbird.user.dao.EducationDao; +import org.sunbird.user.dao.impl.AddressDaoImpl; +import org.sunbird.user.dao.impl.EducationDaoImpl; + +@ActorConfig( + tasks = {"insertUserEducation", "updateUserEducation"}, + asyncTasks = {"insertUserEducation", "updateUserEducation"} +) +public class EducationManagementActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + switch (operation) { + case "insertUserEducation": + insertEducation(request); + break; + + case "updateUserEducation": + updateEducation(request); + break; + + default: + onReceiveUnsupportedOperation("EducationManagementActor"); + } + } + + @SuppressWarnings("unchecked") + private void insertEducation(Request request) { + Map requestMap = request.getRequest(); + List> reqList = + (List>) requestMap.get(JsonKey.EDUCATION); + Response response = new Response(); + List errMsgs = new ArrayList<>(); + List> responseEducationList = new ArrayList<>(); + try { + for (int i = 0; i < reqList.size(); i++) { + try { + Map educationDetailsMap = reqList.get(i); + String createdBy = (String) requestMap.get(JsonKey.ID); + Response addrResponse = null; + educationDetailsMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(i)); + if (educationDetailsMap.containsKey(JsonKey.ADDRESS)) { + addrResponse = upsertEducationAddressDetails(educationDetailsMap, createdBy); + } + responseEducationList.add( + insertEducationDetails(requestMap, educationDetailsMap, addrResponse, createdBy)); + } catch (ProjectCommonException e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log( + "EducationManagementActor:insertEducation: Exception occurred with error message = " + + e.getMessage(), + e); + } catch (Exception e) { + errMsgs.add("Error occurred while inserting education details."); + ProjectLogger.log( + "EducationManagementActor:insertEducation: Generic exception occurred with error message = " + + e.getMessage(), + e); + } + } + } catch (Exception e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log(e.getMessage(), e); + } + response.put(JsonKey.EDUCATION, responseEducationList); + response.put(JsonKey.KEY, JsonKey.EDUCATION); + if (CollectionUtils.isNotEmpty(errMsgs)) { + response.put(JsonKey.ERROR_MSG, errMsgs); + } else { + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + } + sender().tell(response, self()); + } + + @SuppressWarnings("unchecked") + private void updateEducation(Request request) { + Map requestMap = request.getRequest(); + List> reqList = + (List>) requestMap.get(JsonKey.EDUCATION); + Response response = new Response(); + List errMsgs = new ArrayList<>(); + List> responseEducationList = new ArrayList<>(); + try { + for (int i = 0; i < reqList.size(); i++) { + try { + Map educationDetailsMap = reqList.get(i); + String createdBy = (String) requestMap.get(JsonKey.ID); + Response addrResponse = null; + if (BooleanUtils.isTrue((boolean) educationDetailsMap.get(JsonKey.IS_DELETED)) + && !StringUtils.isBlank((String) educationDetailsMap.get(JsonKey.ID))) { + deleteEducationDetails(educationDetailsMap); + continue; + } + if (educationDetailsMap.containsKey(JsonKey.ADDRESS)) { + addrResponse = upsertEducationAddressDetails(educationDetailsMap, createdBy); + } + if (StringUtils.isBlank((String) educationDetailsMap.get(JsonKey.ID))) { + educationDetailsMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(i)); + responseEducationList.add( + insertEducationDetails(requestMap, educationDetailsMap, addrResponse, createdBy)); + } else { + responseEducationList.add( + updateEducationDetails(educationDetailsMap, addrResponse, createdBy)); + } + } catch (ProjectCommonException e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log( + "EducationManagementActor:updateEducation: Exception occurred with error message = " + + e.getMessage(), + e); + } catch (Exception e) { + errMsgs.add("Error occurred while updating education details."); + ProjectLogger.log( + "EducationManagementActor:updateEducation: Generic exception occurred with error message = " + + e.getMessage(), + e); + } + } + } catch (Exception e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log(e.getMessage(), e); + } + response.put(JsonKey.EDUCATION, responseEducationList); + if (CollectionUtils.isNotEmpty(errMsgs)) { + response.put(JsonKey.KEY, JsonKey.EDUCATION); + response.put(JsonKey.ERROR_MSG, errMsgs); + } else { + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + } + sender().tell(response, self()); + } + + private Map updateEducationDetails( + Map educationDetailsMap, Response addrResponse, String createdBy) { + if (null != addrResponse + && ((String) addrResponse.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + educationDetailsMap.put(JsonKey.ADDRESS_ID, addrResponse.get(JsonKey.ADDRESS_ID)); + educationDetailsMap.remove(JsonKey.ADDRESS); + } + validateYearOfPassingAndPercentageDetails(educationDetailsMap); + educationDetailsMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + educationDetailsMap.put(JsonKey.UPDATED_BY, createdBy); + educationDetailsMap.remove(JsonKey.USER_ID); + getEducationDao().upsertEducation(educationDetailsMap); + educationDetailsMap.put(JsonKey.ADDRESS, addrResponse.get(JsonKey.ADDRESS)); + return educationDetailsMap; + } + + @SuppressWarnings("unchecked") + private void deleteEducationDetails(Map educationDetailsMap) { + String addrsId = null; + if (educationDetailsMap.containsKey(JsonKey.ADDRESS) + && null != educationDetailsMap.get(JsonKey.ADDRESS)) { + addrsId = + (String) ((Map) educationDetailsMap.get(JsonKey.ADDRESS)).get(JsonKey.ID); + } else { + addrsId = getAddressId((String) educationDetailsMap.get(JsonKey.ID)); + } + if (null != addrsId) { + // delete eductaion address + getAddressDao().deleteAddress(addrsId); + } + getEducationDao().deleteEducation((String) educationDetailsMap.get(JsonKey.ID)); + } + + @SuppressWarnings("unchecked") + private String getAddressId(String id) { + String addressId = null; + // eduDbInfo + try { + Response res = getEducationDao().getPropertiesValueById(JsonKey.ADDRESS_ID, id); + if (!((List>) res.get(JsonKey.RESPONSE)).isEmpty()) { + addressId = + (String) + (((List>) res.get(JsonKey.RESPONSE)).get(0)) + .get(JsonKey.ADDRESS_ID); + } + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + return addressId; + } + + private Map insertEducationDetails( + Map requestMap, + Map educationDetailsMap, + Response addrResponse, + String createdBy) { + + if (null != addrResponse + && ((String) addrResponse.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + educationDetailsMap.put(JsonKey.ADDRESS_ID, addrResponse.get(JsonKey.ADDRESS_ID)); + educationDetailsMap.remove(JsonKey.ADDRESS); + } + validateYearOfPassingAndPercentageDetails(educationDetailsMap); + educationDetailsMap.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + educationDetailsMap.put(JsonKey.CREATED_BY, createdBy); + educationDetailsMap.put(JsonKey.USER_ID, requestMap.get(JsonKey.ID)); + getEducationDao().createEducation(educationDetailsMap); + if (null != addrResponse) { + educationDetailsMap.put(JsonKey.ADDRESS, addrResponse.get(JsonKey.ADDRESS)); + } + return educationDetailsMap; + } + + private void validateYearOfPassingAndPercentageDetails(Map educationDetailsMap) { + try { + if (null != educationDetailsMap.get(JsonKey.YEAR_OF_PASSING)) { + educationDetailsMap.put( + JsonKey.YEAR_OF_PASSING, + ((BigInteger) educationDetailsMap.get(JsonKey.YEAR_OF_PASSING)).intValue()); + } else { + educationDetailsMap.put(JsonKey.YEAR_OF_PASSING, 0); + } + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + educationDetailsMap.put(JsonKey.YEAR_OF_PASSING, 0); + } + try { + if (null != educationDetailsMap.get(JsonKey.PERCENTAGE)) { + educationDetailsMap.put( + JsonKey.PERCENTAGE, + Double.parseDouble(String.valueOf(educationDetailsMap.get(JsonKey.PERCENTAGE)))); + } else { + educationDetailsMap.put(JsonKey.PERCENTAGE, Double.parseDouble(String.valueOf("0"))); + } + } catch (Exception ex) { + educationDetailsMap.put(JsonKey.PERCENTAGE, Double.parseDouble(String.valueOf("0"))); + ProjectLogger.log(ex.getMessage(), ex); + } + } + + @SuppressWarnings("unchecked") + private Response upsertEducationAddressDetails( + Map educationDetailsMap, String createdBy) { + Response addrResponse = null; + Map address = (Map) educationDetailsMap.get(JsonKey.ADDRESS); + address.remove(JsonKey.IS_DELETED); + String addrId = null; + if (!address.containsKey(JsonKey.ID)) { + addrId = ProjectUtil.getUniqueIdFromTimestamp(3); + address.put(JsonKey.ID, addrId); + address.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + address.put(JsonKey.CREATED_BY, createdBy); + } else { + addrId = (String) address.get(JsonKey.ID); + address.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + address.put(JsonKey.UPDATED_BY, createdBy); + address.remove(JsonKey.USER_ID); + } + addrResponse = getAddressDao().upsertAddress(address); + addrResponse.put(JsonKey.ADDRESS_ID, addrId); + addrResponse.put(JsonKey.ADDRESS, address); + return addrResponse; + } + + private EducationDao getEducationDao() { + return EducationDaoImpl.getInstance(); + } + + private AddressDao getAddressDao() { + return AddressDaoImpl.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/IdentifierFreeUpActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/IdentifierFreeUpActor.java new file mode 100644 index 0000000000..a5e092f6ea --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/IdentifierFreeUpActor.java @@ -0,0 +1,158 @@ +package org.sunbird.user.actors; + +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.UserFlagEnum; +import org.sunbird.learner.util.Util; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {"freeUpUserIdentity"}, + asyncTasks = {} +) + +/** + * this Actor class is being used to free Up used User Identifier for now it only free Up user + * Email, Phone. + */ +public class IdentifierFreeUpActor extends BaseActor { + + @Override + public void onReceive(Request request) { + String id = (String) request.get(JsonKey.ID); + List identifiers = (List) request.get(JsonKey.IDENTIFIER); + freeUpUserIdentifier(id, identifiers); + } + + private Map getUserById(String id) { + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Response response = + getCassandraOperation() + .getRecordById(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), id); + List> responseList = (List) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isEmpty(responseList)) { + ProjectLogger.log( + String.format( + "%s:%s:User not found with provided Id:%s", + this.getClass().getSimpleName(), "getById", id), + LoggerEnum.ERROR.name()); + ProjectCommonException.throwClientErrorException(ResponseCode.invalidUserId); + } + return responseList.get(0); + } + + private Response processUserAttribute(Map userDbMap, List identifiers) { + + if (identifiers.contains(JsonKey.EMAIL)) { + nullifyEmail(userDbMap); + ProjectLogger.log( + String.format( + "%s:%s:Nullified Email. WITH ID %s", + this.getClass().getSimpleName(), "freeUpUserIdentifier", userDbMap.get(JsonKey.ID)), + LoggerEnum.INFO.name()); + } + if (identifiers.contains(JsonKey.PHONE)) { + nullifyPhone(userDbMap); + ProjectLogger.log( + String.format( + "%s:%s:Nullified Phone. WITH ID %s", + this.getClass().getSimpleName(), "freeUpUserIdentifier", userDbMap.get(JsonKey.ID)), + LoggerEnum.INFO.name()); + } + return updateUser(userDbMap); + } + + private void nullifyEmail(Map userDbMap) { + if (isNullifyOperationValid((String) userDbMap.get(JsonKey.EMAIL))) { + userDbMap.replace(JsonKey.PREV_USED_EMAIL, userDbMap.get(JsonKey.EMAIL)); + userDbMap.replace(JsonKey.EMAIL, null); + userDbMap.replace(JsonKey.MASKED_EMAIL, null); + userDbMap.replace(JsonKey.EMAIL_VERIFIED, false); + userDbMap.put( + JsonKey.FLAGS_VALUE, calculateFlagvalue(UserFlagEnum.EMAIL_VERIFIED, userDbMap)); + } + } + + private void nullifyPhone(Map userDbMap) { + if (isNullifyOperationValid((String) userDbMap.get(JsonKey.PHONE))) { + userDbMap.replace(JsonKey.PREV_USED_PHONE, userDbMap.get(JsonKey.PHONE)); + userDbMap.replace(JsonKey.PHONE, null); + userDbMap.replace(JsonKey.MASKED_PHONE, null); + userDbMap.replace(JsonKey.PHONE_VERIFIED, false); + userDbMap.replace(JsonKey.COUNTRY_CODE, null); + userDbMap.put( + JsonKey.FLAGS_VALUE, calculateFlagvalue(UserFlagEnum.PHONE_VERIFIED, userDbMap)); + } + } + + private int calculateFlagvalue(UserFlagEnum identifier, Map userDbMap) { + int flagsValue = 0; + if (userDbMap.get(JsonKey.FLAGS_VALUE) != null + && (int) userDbMap.get(JsonKey.FLAGS_VALUE) > 0) { + flagsValue = (int) userDbMap.get(JsonKey.FLAGS_VALUE); + flagsValue = flagsValue - identifier.getUserFlagValue(); + } + return flagsValue; + } + + private Response updateUser(Map userDbMap) { + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + return getCassandraOperation() + .updateRecord(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userDbMap); + } + + private void freeUpUserIdentifier(String id, List identifiers) { + Map userDbMap = getUserById(id); + Response response = processUserAttribute(userDbMap, identifiers); + boolean esResponse = saveUserDetailsToEs(userDbMap); + ProjectLogger.log( + "IdentifierFreeUpActor:freeUpUserIdentifier response got from ES for identifier freeup api :" + + esResponse, + LoggerEnum.INFO.name()); + sender().tell(response, self()); + ProjectLogger.log( + String.format( + "%s:%s:USER MAP SUCCESSFULLY UPDATED IN CASSANDRA. WITH ID %s", + this.getClass().getSimpleName(), "freeUpUserIdentifier", userDbMap.get(JsonKey.ID)), + LoggerEnum.INFO.name()); + } + + private boolean saveUserDetailsToEs(Map userDbMap) { + Future future = + getEsUtil() + .update( + ProjectUtil.EsType.user.getTypeName(), + (String) userDbMap.get(JsonKey.ID), + userDbMap); + return (boolean) ElasticSearchHelper.getResponseFromFuture(future); + } + + private boolean isNullifyOperationValid(String identifier) { + return StringUtils.isNotBlank(identifier); + } + + private CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } + + private ElasticSearchService getEsUtil() { + return EsClientFactory.getInstance(JsonKey.REST); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/JobProfileManagementActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/JobProfileManagementActor.java new file mode 100644 index 0000000000..c7fc4b3ec5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/JobProfileManagementActor.java @@ -0,0 +1,250 @@ +package org.sunbird.user.actors; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.user.dao.AddressDao; +import org.sunbird.user.dao.JobProfileDao; +import org.sunbird.user.dao.impl.AddressDaoImpl; +import org.sunbird.user.dao.impl.JobProfileDaoImpl; + +@ActorConfig( + tasks = {"insertUserJobProfile", "updateUserJobProfile"}, + asyncTasks = {"insertUserJobProfile", "updateUserJobProfile"} +) +public class JobProfileManagementActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + switch (operation) { + case "insertUserJobProfile": + insertJobProfile(request); + break; + + case "updateUserJobProfile": + updateJobProfile(request); + break; + + default: + onReceiveUnsupportedOperation("JobProfileManagementActor"); + } + } + + @SuppressWarnings("unchecked") + private void insertJobProfile(Request request) { + Map requestMap = request.getRequest(); + List> reqList = + (List>) requestMap.get(JsonKey.JOB_PROFILE); + Response response = new Response(); + List errMsgs = new ArrayList<>(); + List> responseJobProfileList = new ArrayList<>(); + try { + for (int i = 0; i < reqList.size(); i++) { + try { + Map jobProfileMap = reqList.get(i); + String createdBy = (String) requestMap.get(JsonKey.CREATED_BY); + Response addrResponse = null; + jobProfileMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(i)); + if (jobProfileMap.containsKey(JsonKey.ADDRESS)) { + addrResponse = upsertJobProfileAddressDetails(jobProfileMap, createdBy); + } + responseJobProfileList.add( + insertJobProfileDetails(requestMap, jobProfileMap, addrResponse, createdBy)); + } catch (ProjectCommonException e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log( + "JobProfileManagementActor:insertJobProfile: Exception occurred with error message = " + + e.getMessage(), + e); + } catch (Exception e) { + errMsgs.add("Error occurred while inserting job profile details."); + ProjectLogger.log( + "JobProfileManagementActor:insertJobProfile: Generic exception occurred with error message = " + + e.getMessage(), + e); + } + } + } catch (Exception e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log(e.getMessage(), e); + } + response.put(JsonKey.JOB_PROFILE, responseJobProfileList); + response.put(JsonKey.KEY, JsonKey.JOB_PROFILE); + if (CollectionUtils.isNotEmpty(errMsgs)) { + response.put(JsonKey.ERROR_MSG, errMsgs); + } else { + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + } + sender().tell(response, self()); + } + + @SuppressWarnings("unchecked") + private void updateJobProfile(Request request) { + Map requestMap = request.getRequest(); + List> reqList = + (List>) requestMap.get(JsonKey.JOB_PROFILE); + Response response = new Response(); + List errMsgs = new ArrayList<>(); + List> responseJobProfileList = new ArrayList<>(); + try { + for (int i = 0; i < reqList.size(); i++) { + try { + Map jobProfileMap = reqList.get(i); + String createdBy = (String) requestMap.get(JsonKey.CREATED_BY); + Response addrResponse = null; + if (BooleanUtils.isTrue((boolean) jobProfileMap.get(JsonKey.IS_DELETED)) + && !StringUtils.isBlank((String) jobProfileMap.get(JsonKey.ID))) { + deleteJobProfileDetails(jobProfileMap); + continue; + } + if (jobProfileMap.containsKey(JsonKey.ADDRESS)) { + addrResponse = upsertJobProfileAddressDetails(jobProfileMap, createdBy); + } + if (StringUtils.isBlank((String) jobProfileMap.get(JsonKey.ID))) { + jobProfileMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(i)); + responseJobProfileList.add( + insertJobProfileDetails(requestMap, jobProfileMap, addrResponse, createdBy)); + } else { + responseJobProfileList.add( + updateJobProfileDetails(jobProfileMap, addrResponse, createdBy)); + } + } catch (ProjectCommonException e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log( + "JobProfileManagementActor:updateJobProfile: Exception occurred with error message = " + + e.getMessage(), + e); + } catch (Exception e) { + errMsgs.add("Error occurred while updating job profile details."); + ProjectLogger.log( + "JobProfileManagementActor:updateJobProfile: Generic exception occurred with error message = " + + e.getMessage(), + e); + } + } + } catch (Exception e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log(e.getMessage(), e); + } + response.put(JsonKey.JOB_PROFILE, responseJobProfileList); + if (CollectionUtils.isNotEmpty(errMsgs)) { + response.put(JsonKey.KEY, JsonKey.JOB_PROFILE); + response.put(JsonKey.ERROR_MSG, errMsgs); + } else { + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + } + sender().tell(response, self()); + } + + private Map updateJobProfileDetails( + Map jobProfileMap, Response addrResponse, String createdBy) { + if (null != addrResponse + && ((String) addrResponse.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + jobProfileMap.put(JsonKey.ADDRESS_ID, addrResponse.get(JsonKey.ADDRESS_ID)); + jobProfileMap.remove(JsonKey.ADDRESS); + } + jobProfileMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + jobProfileMap.put(JsonKey.UPDATED_BY, createdBy); + jobProfileMap.remove(JsonKey.USER_ID); + getJobProfileDao().upsertJobProfile(jobProfileMap); + if (null != addrResponse) { + jobProfileMap.put(JsonKey.ADDRESS, addrResponse.get(JsonKey.ADDRESS)); + } + return jobProfileMap; + } + + @SuppressWarnings("unchecked") + private void deleteJobProfileDetails(Map requestMap) { + String addrsId = null; + if (requestMap.containsKey(JsonKey.ADDRESS) && null != requestMap.get(JsonKey.ADDRESS)) { + addrsId = (String) ((Map) requestMap.get(JsonKey.ADDRESS)).get(JsonKey.ID); + } else { + addrsId = getAddressId((String) requestMap.get(JsonKey.ID)); + } + if (null != addrsId) { + getAddressDao().deleteAddress(addrsId); + } + getJobProfileDao().deleteJobProfile((String) requestMap.get(JsonKey.ID)); + } + + @SuppressWarnings("unchecked") + private String getAddressId(String id) { + String addressId = null; + try { + Response res = getJobProfileDao().getPropertiesValueById(JsonKey.ADDRESS_ID, id); + if (!((List>) res.get(JsonKey.RESPONSE)).isEmpty()) { + addressId = + (String) + (((List>) res.get(JsonKey.RESPONSE)).get(0)) + .get(JsonKey.ADDRESS_ID); + } + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + return addressId; + } + + private Map insertJobProfileDetails( + Map requestMap, + Map jobProfileMap, + Response addrResponse, + String createdBy) { + if (null != addrResponse + && ((String) addrResponse.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + jobProfileMap.put(JsonKey.ADDRESS_ID, addrResponse.get(JsonKey.ADDRESS_ID)); + jobProfileMap.remove(JsonKey.ADDRESS); + } + jobProfileMap.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + jobProfileMap.put(JsonKey.CREATED_BY, createdBy); + jobProfileMap.put(JsonKey.USER_ID, requestMap.get(JsonKey.ID)); + getJobProfileDao().createJobProfile(jobProfileMap); + if (null != addrResponse) { + jobProfileMap.put(JsonKey.ADDRESS, addrResponse.get(JsonKey.ADDRESS)); + } + return jobProfileMap; + } + + @SuppressWarnings("unchecked") + private Response upsertJobProfileAddressDetails( + Map jobProfileDetailsMap, String createdBy) { + Response addrResponse = null; + String addrId = null; + Map address = (Map) jobProfileDetailsMap.get(JsonKey.ADDRESS); + address.remove(JsonKey.IS_DELETED); + if (!address.containsKey(JsonKey.ID)) { + addrId = ProjectUtil.getUniqueIdFromTimestamp(2); + address.put(JsonKey.ID, addrId); + address.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + address.put(JsonKey.CREATED_BY, createdBy); + } else { + addrId = (String) address.get(JsonKey.ID); + address.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + address.put(JsonKey.UPDATED_BY, createdBy); + address.remove(JsonKey.USER_ID); + } + addrResponse = getAddressDao().upsertAddress(address); + addrResponse.put(JsonKey.ADDRESS_ID, addrId); + addrResponse.put(JsonKey.ADDRESS, address); + return addrResponse; + } + + private JobProfileDao getJobProfileDao() { + return JobProfileDaoImpl.getInstance(); + } + + private AddressDao getAddressDao() { + return AddressDaoImpl.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/ResetPasswordActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/ResetPasswordActor.java new file mode 100644 index 0000000000..0400baed24 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/ResetPasswordActor.java @@ -0,0 +1,104 @@ +package org.sunbird.user.actors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.user.dao.UserDao; +import org.sunbird.user.dao.impl.UserDaoImpl; + +/** This actor process the request for reset password. */ +@ActorConfig( + tasks = {"resetPassword"}, + asyncTasks = {} +) +public class ResetPasswordActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String userId = (String) request.get(JsonKey.USER_ID); + String type = (String) request.get(JsonKey.TYPE); + resetPassword(userId, type); + generateTelemetry(request); + } + + private void resetPassword(String userId, String type) { + ProjectLogger.log("ResetPasswordActor:resetPassword: method called.", LoggerEnum.INFO.name()); + User user = getUserDao().getUserById(userId); + ObjectMapper mapper = new ObjectMapper(); + if (null != user) { + user = removeUnUsedIdentity(user, type); + Map userMap = mapper.convertValue(user, Map.class); + UserUtility.decryptUserData(userMap); + userMap.put(JsonKey.USERNAME, userMap.get(JsonKey.USERNAME)); + userMap.put(JsonKey.REDIRECT_URI, Util.getSunbirdLoginUrl()); + String url = Util.getUserRequiredActionLink(userMap, false); + userMap.put(JsonKey.SET_PASSWORD_LINK, url); + if ((String) userMap.get(JsonKey.SET_PASSWORD_LINK) != null) { + ProjectLogger.log( + "ResetPasswordActor:resetPassword: link generated for reset password.", + LoggerEnum.INFO.name()); + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + response.put(JsonKey.LINK, (String) userMap.get(JsonKey.SET_PASSWORD_LINK)); + sender().tell(response, self()); + } else { + ProjectLogger.log( + "ResetPasswordActor:resetPassword: not able to generate reset password link.", + LoggerEnum.INFO.name()); + ProjectCommonException.throwServerErrorException(ResponseCode.internalError); + } + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.userNotFound); + } + } + + private void generateTelemetry(Request request) { + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + targetObject = + TelemetryUtil.generateTargetObject( + (String) request.get(JsonKey.USER_ID), TelemetryEnvKey.USER, JsonKey.UPDATE, null); + TelemetryUtil.generateCorrelatedObject( + (String) request.get(JsonKey.USER_ID), TelemetryEnvKey.USER, null, correlatedObject); + TelemetryUtil.telemetryProcessingCall( + request.getRequest(), targetObject, correlatedObject, request.getContext()); + } + + private User removeUnUsedIdentity(User user, String type) { + if (!(JsonKey.EMAIL.equalsIgnoreCase(type))) { + user.setEmail(null); + user.setMaskedEmail(null); + } + if (!(JsonKey.PHONE.equalsIgnoreCase(type))) { + user.setPhone(null); + user.setMaskedPhone(null); + } + if (JsonKey.PREV_USED_PHONE.equalsIgnoreCase(type)) { + user.setPhone(user.getPrevUsedPhone()); + } + if (JsonKey.PREV_USED_EMAIL.equalsIgnoreCase(type)) { + user.setEmail(user.getPrevUsedEmail()); + } + return user; + } + + private UserDao getUserDao() { + return UserDaoImpl.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/TenantMigrationActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/TenantMigrationActor.java new file mode 100644 index 0000000000..5c03791244 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/TenantMigrationActor.java @@ -0,0 +1,674 @@ +package org.sunbird.user.actors; + +import akka.actor.ActorRef; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.sql.Timestamp; +import java.text.MessageFormat; +import java.util.*; +import java.util.stream.IntStream; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.background.BackgroundOperations; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.bean.ClaimStatus; +import org.sunbird.bean.ShadowUser; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.feed.IFeedService; +import org.sunbird.feed.impl.FeedFactory; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.organisation.external.identity.service.OrgExternalService; +import org.sunbird.learner.util.UserFlagEnum; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.user.service.impl.UserServiceImpl; +import org.sunbird.user.util.MigrationUtils; +import org.sunbird.user.util.UserActorOperations; +import org.sunbird.user.util.UserUtil; +import scala.concurrent.Future; + +/** + * This class contains method and business logic to migrate user from custodian org to some other + * root org. + * + * @author Amit Kumar + */ +@ActorConfig( + tasks = {"userTenantMigrate", "migrateUser"}, + asyncTasks = {} +) +public class TenantMigrationActor extends BaseActor { + + private Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + private Util.DbInfo usrOrgDbInfo = Util.dbInfoMap.get(JsonKey.USER_ORG_DB); + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + private ActorRef systemSettingActorRef = null; + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + private static final String ACCOUNT_MERGE_EMAIL_TEMPLATE = "accountMerge"; + private static final String MASK_IDENTIFIER = "maskIdentifier"; + private static final int MAX_MIGRATION_ATTEMPT = 2; + public static final int USER_EXTERNAL_ID_MISMATCH = -1; + private IFeedService feedService = FeedFactory.getInstance(); + private DecryptionService decryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + ""); + private DataMaskingService maskingService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getMaskingServiceInstance(""); + + @Override + public void onReceive(Request request) throws Throwable { + ProjectLogger.log("TenantMigrationActor:onReceive called.", LoggerEnum.INFO.name()); + Util.initializeContext(request, StringUtils.capitalize(JsonKey.CONSUMER)); + String operation = request.getOperation(); + if (systemSettingActorRef == null) { + systemSettingActorRef = getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()); + } + switch (operation) { + case "userTenantMigrate": + migrateUser(request, true); + break; + case "migrateUser": + processShadowUserMigrate(request); + break; + default: + onReceiveUnsupportedOperation("TenantMigrationActor"); + } + } + + @SuppressWarnings("unchecked") + private void migrateUser(Request request, boolean notify) { + ProjectLogger.log("TenantMigrationActor:migrateUser called.", LoggerEnum.INFO.name()); + Map reqMap = new HashMap<>(request.getRequest()); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + Map userDetails = + UserServiceImpl.getInstance() + .esGetPublicUserProfileById((String) request.getRequest().get(JsonKey.USER_ID)); + validateUserCustodianOrgId((String) userDetails.get(JsonKey.ROOT_ORG_ID)); + validateChannelAndGetRootOrgId(request); + Map rollup = new HashMap<>(); + rollup.put("l1", (String) request.getRequest().get(JsonKey.ROOT_ORG_ID)); + request.getContext().put(JsonKey.ROLLUP, rollup); + String orgId = validateOrgExternalIdOrOrgIdAndGetOrgId(request.getRequest()); + request.getRequest().put(JsonKey.ORG_ID, orgId); + int userFlagValue = UserFlagEnum.STATE_VALIDATED.getUserFlagValue(); + if (userDetails.containsKey(JsonKey.FLAGS_VALUE)) { + userFlagValue += Integer.parseInt(String.valueOf(userDetails.get(JsonKey.FLAGS_VALUE))); + } + request.getRequest().put(JsonKey.FLAGS_VALUE, userFlagValue); + Map userUpdateRequest = createUserUpdateRequest(request); + // Update user channel and rootOrgId + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + Response response = + cassandraOperation.updateRecord( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userUpdateRequest); + if (null == response + || null == (String) response.get(JsonKey.RESPONSE) + || (null != (String) response.get(JsonKey.RESPONSE) + && !((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS))) { + // throw exception for migration failed + ProjectCommonException.throwServerErrorException(ResponseCode.errorUserMigrationFailed); + } + if (null != userUpdateRequest.get(JsonKey.IS_DELETED) + && (Boolean) userUpdateRequest.get(JsonKey.IS_DELETED)) { + deactivateUserFromKC((String) userUpdateRequest.get(JsonKey.ID)); + } + ProjectLogger.log( + "TenantMigrationActor:migrateUser user record got updated.", LoggerEnum.INFO.name()); + // Update user org details + Response userOrgResponse = + updateUserOrg(request, (List>) userDetails.get(JsonKey.ORGANISATIONS)); + // Update user externalIds + Response userExternalIdsResponse = updateUserExternalIds(request); + // Collect all the error message + List> userOrgErrMsgList = new ArrayList<>(); + if (MapUtils.isNotEmpty(userOrgResponse.getResult()) + && CollectionUtils.isNotEmpty( + (List>) userOrgResponse.getResult().get(JsonKey.ERRORS))) { + userOrgErrMsgList = + (List>) userOrgResponse.getResult().get(JsonKey.ERRORS); + } + List> userExtIdErrMsgList = new ArrayList<>(); + if (MapUtils.isNotEmpty(userExternalIdsResponse.getResult()) + && CollectionUtils.isNotEmpty( + (List>) userExternalIdsResponse.getResult().get(JsonKey.ERRORS))) { + userExtIdErrMsgList = + (List>) userExternalIdsResponse.getResult().get(JsonKey.ERRORS); + } + userOrgErrMsgList.addAll(userExtIdErrMsgList); + response.getResult().put(JsonKey.ERRORS, userOrgErrMsgList); + // send the response + sender().tell(response, self()); + // save user data to ES + saveUserDetailsToEs((String) request.getRequest().get(JsonKey.USER_ID)); + if (notify) { + notify(userDetails); + } + targetObject = + TelemetryUtil.generateTargetObject( + (String) reqMap.get(JsonKey.USER_ID), TelemetryEnvKey.USER, "migrate", null); + TelemetryUtil.telemetryProcessingCall( + reqMap, targetObject, correlatedObject, request.getContext()); + } + + private void notify(Map userDetail) { + ProjectLogger.log( + "notify starts sending migrate notification to user " + userDetail.get(JsonKey.USER_ID)); + Map userData = createUserData(userDetail); + Request notificationRequest = createNotificationData(userData); + tellToAnother(notificationRequest); + } + + private void deactivateUserFromKC(String userId) { + try { + Map userDbMap = new HashMap<>(); + userDbMap.put(JsonKey.USER_ID, userId); + String status = getSSOManager().deactivateUser(userDbMap); + ProjectLogger.log( + "TenantMigrationActor:deactivateUserFromKC:user status in deactivating Keycloak" + status, + LoggerEnum.INFO.name()); + } catch (Exception e) { + ProjectLogger.log( + "TenantMigrationActor:deactivateUserFromKC:Error occurred while deactivating user from Keycloak" + + e, + LoggerEnum.ERROR.name()); + } + } + + private Request createNotificationData(Map userData) { + Request request = new Request(); + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.NAME, userData.get(JsonKey.FIRST_NAME)); + requestMap.put(JsonKey.FIRST_NAME, userData.get(JsonKey.FIRST_NAME)); + if (StringUtils.isNotBlank((String) userData.get(JsonKey.EMAIL))) { + requestMap.put(JsonKey.RECIPIENT_EMAILS, Arrays.asList(userData.get(JsonKey.EMAIL))); + } else { + requestMap.put(JsonKey.RECIPIENT_PHONES, Arrays.asList(userData.get(JsonKey.PHONE))); + requestMap.put(JsonKey.MODE, JsonKey.SMS); + } + requestMap.put(JsonKey.EMAIL_TEMPLATE_TYPE, ACCOUNT_MERGE_EMAIL_TEMPLATE); + String body = + MessageFormat.format( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_MIGRATE_USER_BODY), + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_INSTALLATION), + userData.get(MASK_IDENTIFIER)); + requestMap.put(JsonKey.BODY, body); + requestMap.put( + JsonKey.SUBJECT, ProjectUtil.getConfigValue(JsonKey.SUNBIRD_ACCOUNT_MERGE_SUBJECT)); + request.getRequest().put(JsonKey.EMAIL_REQUEST, requestMap); + request.setOperation(BackgroundOperations.emailService.name()); + return request; + } + + private Map createUserData(Map userData) { + if (StringUtils.isNotBlank((String) userData.get(JsonKey.EMAIL))) { + userData.put( + JsonKey.EMAIL, decryptionService.decryptData((String) userData.get(JsonKey.EMAIL))); + userData.put(MASK_IDENTIFIER, maskingService.maskEmail((String) userData.get(JsonKey.EMAIL))); + } else { + userData.put( + JsonKey.PHONE, decryptionService.decryptData((String) userData.get(JsonKey.PHONE))); + userData.put(MASK_IDENTIFIER, maskingService.maskPhone((String) userData.get(JsonKey.PHONE))); + } + return userData; + } + + private String validateOrgExternalIdOrOrgIdAndGetOrgId(Map migrateReq) { + ProjectLogger.log( + "TenantMigrationActor:validateOrgExternalIdOrOrgIdAndGetOrgId called.", + LoggerEnum.INFO.name()); + String orgId = ""; + if (StringUtils.isNotBlank((String) migrateReq.get(JsonKey.ORG_ID)) + || StringUtils.isNotBlank((String) migrateReq.get(JsonKey.ORG_EXTERNAL_ID))) { + if (StringUtils.isNotBlank((String) migrateReq.get(JsonKey.ORG_ID))) { + orgId = (String) migrateReq.get(JsonKey.ORG_ID); + Future> resultF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), orgId); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + if (MapUtils.isEmpty(result)) { + ProjectLogger.log( + "TenantMigrationActor:validateOrgExternalIdOrOrgIdAndGetOrgId called. OrgId is Invalid", + LoggerEnum.INFO.name()); + ProjectCommonException.throwClientErrorException(ResponseCode.invalidOrgId); + } else { + String reqOrgRootOrgId = (String) result.get(JsonKey.ROOT_ORG_ID); + if (StringUtils.isNotBlank(reqOrgRootOrgId) + && !reqOrgRootOrgId.equalsIgnoreCase((String) migrateReq.get(JsonKey.ROOT_ORG_ID))) { + ProjectCommonException.throwClientErrorException( + ResponseCode.parameterMismatch, + MessageFormat.format( + ResponseCode.parameterMismatch.getErrorMessage(), + StringFormatter.joinByComma(JsonKey.CHANNEL, JsonKey.ORG_ID))); + } + } + } else if (StringUtils.isNotBlank((String) migrateReq.get(JsonKey.ORG_EXTERNAL_ID))) { + OrgExternalService orgExternalService = new OrgExternalService(); + orgId = + orgExternalService.getOrgIdFromOrgExternalIdAndProvider( + (String) migrateReq.get(JsonKey.ORG_EXTERNAL_ID), + (String) migrateReq.get(JsonKey.CHANNEL)); + if (StringUtils.isBlank(orgId)) { + ProjectLogger.log( + "TenantMigrationActor:validateOrgExternalIdOrOrgIdAndGetOrgId called. OrgExternalId is Invalid", + LoggerEnum.INFO.name()); + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + (String) migrateReq.get(JsonKey.ORG_EXTERNAL_ID), + JsonKey.ORG_EXTERNAL_ID)); + } + } + } + return orgId; + } + + private void validateUserCustodianOrgId(String rootOrgId) { + String custodianOrgId = UserServiceImpl.getInstance().getCustodianOrgId(systemSettingActorRef); + if (!rootOrgId.equalsIgnoreCase(custodianOrgId)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.parameterMismatch, + MessageFormat.format( + ResponseCode.parameterMismatch.getErrorMessage(), + "user rootOrgId and custodianOrgId")); + } + } + + private void saveUserDetailsToEs(String userId) { + Request userRequest = new Request(); + userRequest.setOperation(ActorOperations.UPDATE_USER_INFO_ELASTIC.getValue()); + userRequest.getRequest().put(JsonKey.ID, userId); + ProjectLogger.log( + "TenantMigrationActor:saveUserDetailsToEs: Trigger sync of user details to ES", + LoggerEnum.INFO.name()); + tellToAnother(userRequest); + } + + private Response updateUserExternalIds(Request request) { + ProjectLogger.log("TenantMigrationActor:updateUserExternalIds called.", LoggerEnum.INFO.name()); + Response response = new Response(); + Map userExtIdsReq = new HashMap<>(); + userExtIdsReq.put(JsonKey.ID, request.getRequest().get(JsonKey.USER_ID)); + userExtIdsReq.put(JsonKey.USER_ID, request.getRequest().get(JsonKey.USER_ID)); + userExtIdsReq.put(JsonKey.EXTERNAL_IDS, request.getRequest().get(JsonKey.EXTERNAL_IDS)); + try { + ObjectMapper mapper = new ObjectMapper(); + User user = mapper.convertValue(userExtIdsReq, User.class); + UserUtil.validateExternalIds(user, JsonKey.CREATE); + userExtIdsReq.put(JsonKey.EXTERNAL_IDS, user.getExternalIds()); + Request userequest = new Request(); + userequest.setOperation(UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS.getValue()); + userExtIdsReq.put(JsonKey.OPERATION_TYPE, JsonKey.CREATE); + userequest.getRequest().putAll(userExtIdsReq); + response = + (Response) + interServiceCommunication.getResponse( + getActorRef(UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS.getValue()), + userequest); + ProjectLogger.log( + "TenantMigrationActor:updateUserExternalIds user externalIds got updated.", + LoggerEnum.INFO.name()); + } catch (Exception ex) { + ProjectLogger.log( + "TenantMigrationActor:updateUserExternalIds:Exception occurred while updating user externalIds.", + ex); + List> errMsgList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ERROR_MSG, ex.getMessage()); + errMsgList.add(map); + response.getResult().put(JsonKey.ERRORS, errMsgList); + } + return response; + } + + private Response updateUserOrg(Request request, List> userOrgList) { + ProjectLogger.log("TenantMigrationActor:updateUserOrg called.", LoggerEnum.INFO.name()); + Response response = new Response(); + deleteOldUserOrgMapping(userOrgList); + Map userDetails = request.getRequest(); + // add mapping root org + createUserOrgRequestAndUpdate( + (String) userDetails.get(JsonKey.USER_ID), (String) userDetails.get(JsonKey.ROOT_ORG_ID)); + String orgId = (String) userDetails.get(JsonKey.ORG_ID); + if (StringUtils.isNotBlank(orgId) + && !((String) userDetails.get(JsonKey.ROOT_ORG_ID)).equalsIgnoreCase(orgId)) { + try { + createUserOrgRequestAndUpdate((String) userDetails.get(JsonKey.USER_ID), orgId); + ProjectLogger.log( + "TenantMigrationActor:updateUserOrg user org data got updated.", + LoggerEnum.INFO.name()); + } catch (Exception ex) { + ProjectLogger.log( + "TenantMigrationActor:updateUserOrg:Exception occurred while updating user Org.", ex); + List> errMsgList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ERROR_MSG, ex.getMessage()); + errMsgList.add(map); + response.getResult().put(JsonKey.ERRORS, errMsgList); + } + } + return response; + } + + private void createUserOrgRequestAndUpdate(String userId, String orgId) { + Map userOrgRequest = new HashMap<>(); + userOrgRequest.put(JsonKey.ID, userId); + String hashTagId = Util.getHashTagIdFromOrgId(orgId); + userOrgRequest.put(JsonKey.HASHTAGID, hashTagId); + userOrgRequest.put(JsonKey.ORGANISATION_ID, orgId); + List roles = new ArrayList<>(); + roles.add(ProjectUtil.UserRole.PUBLIC.getValue()); + userOrgRequest.put(JsonKey.ROLES, roles); + Util.registerUserToOrg(userOrgRequest); + } + + private void deleteOldUserOrgMapping(List> userOrgList) { + ProjectLogger.log( + "TenantMigrationActor:deleteOldUserOrgMapping: delete old user org association started.", + LoggerEnum.INFO.name()); + CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + for (Map userOrg : userOrgList) { + cassandraOperation.deleteRecord( + usrOrgDbInfo.getKeySpace(), + usrOrgDbInfo.getTableName(), + (String) userOrg.get(JsonKey.ID)); + } + } + + private void validateChannelAndGetRootOrgId(Request request) { + String rootOrgId = ""; + String channel = (String) request.getRequest().get(JsonKey.CHANNEL); + if (StringUtils.isNotBlank(channel)) { + rootOrgId = UserServiceImpl.getInstance().getRootOrgIdFromChannel(channel); + request.getRequest().put(JsonKey.ROOT_ORG_ID, rootOrgId); + } + } + + private Map createUserUpdateRequest(Request request) { + Map userRequest = new HashMap<>(); + userRequest.put(JsonKey.ID, request.getRequest().get(JsonKey.USER_ID)); + userRequest.put(JsonKey.CHANNEL, request.getRequest().get(JsonKey.CHANNEL)); + userRequest.put(JsonKey.ROOT_ORG_ID, request.getRequest().get(JsonKey.ROOT_ORG_ID)); + userRequest.put(JsonKey.FLAGS_VALUE, request.getRequest().get(JsonKey.FLAGS_VALUE)); + userRequest.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + userRequest.put(JsonKey.USER_TYPE, JsonKey.TEACHER); + if (request.getRequest().containsKey(JsonKey.STATUS)) { + userRequest.put(JsonKey.STATUS, request.getRequest().get(JsonKey.STATUS)); + userRequest.put( + JsonKey.IS_DELETED, + (int) request.getRequest().get(JsonKey.STATUS) == ProjectUtil.Status.ACTIVE.getValue() + ? false + : true); + } + return userRequest; + } + + /** + * this method will be used when user reject the migration + * + * @param userId + */ + private boolean rejectMigration(String userId) { + ProjectLogger.log( + "TenantMigrationActor:rejectMigration: started rejecting Migration with userId:" + userId, + LoggerEnum.INFO.name()); + List shadowUserList = MigrationUtils.getEligibleUsersById(userId); + if (shadowUserList.isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidUserId); + } + shadowUserList.forEach( + shadowUser -> { + MigrationUtils.markUserAsRejected(shadowUser); + }); + return true; + } + + private void processShadowUserMigrate(Request request) throws Exception { + ProjectLogger.log( + "TenantMigrationActor:processShadowUserMigrate called.", LoggerEnum.INFO.name()); + String userId = (String) request.getRequest().get(JsonKey.USER_ID); + String extUserId = (String) request.getRequest().get(JsonKey.USER_EXT_ID); + String channel = (String) request.getRequest().get(JsonKey.CHANNEL); + String action = (String) request.getRequest().get(JsonKey.ACTION); + String feedId = + (String) request.getRequest().get(JsonKey.FEED_ID); // will be used with user_feed table + Response response = new Response(); + response.put(JsonKey.SUCCESS, true); + response.put(JsonKey.USER_ID, userId); + if (StringUtils.equalsIgnoreCase(action, JsonKey.REJECT)) { + rejectMigration(userId); + deleteUserFeed(feedId); + } else if (StringUtils.equalsIgnoreCase(action, JsonKey.ACCEPT)) { + ProjectLogger.log( + "TenantMigrationActor: processShadowUserMigrate: shadow-user accepted and the extUserId : " + + extUserId, + LoggerEnum.INFO.name()); + List shadowUserList = getShadowUsers(channel, userId); + checkUserId(shadowUserList); + int index = getIndexOfShadowUser(shadowUserList, extUserId); + if (!isIndexValid(index)) { + ProjectLogger.log( + "TenantMigrationActor: processShadowUserMigrate: user entered invalid externalId ", + LoggerEnum.INFO.name()); + if (getRemainingAttempt(shadowUserList) <= 0) { + deleteUserFeed(feedId); + } + response = modifyAttemptCount(response, shadowUserList, extUserId); + } else { + ProjectLogger.log( + "TenantMigrationActor: processShadowUserMigrate: user entered valid externalId ", + LoggerEnum.INFO.name()); + selfMigrate(request, userId, extUserId, shadowUserList.get(index)); + increaseAttemptCount(shadowUserList.get(index), false); + shadowUserList.remove(index); + rejectRemainingUser(shadowUserList); + } + } else { + unSupportedMessage(); + } + sender().tell(response, self()); + } + + private int getRemainingAttempt(List shadowUserList) { + return MAX_MIGRATION_ATTEMPT - shadowUserList.get(0).getAttemptedCount() - 1; + } + + private Response modifyAttemptCount( + Response response, List shadowUserList, String extUserId) { + int remainingAttempt = getRemainingAttempt(shadowUserList); + if (remainingAttempt <= 0) { + increaseBulkAttemptCount(shadowUserList, true); + ProjectCommonException.throwClientErrorException(ResponseCode.userMigrationFiled); + } + response = prepareFailureResponse(extUserId, remainingAttempt); + increaseBulkAttemptCount(shadowUserList, false); + return response; + } + + /** + * this method will throw exception if no record found with provided userId and channel. + * + * @param shadowUserList + */ + private void checkUserId(List shadowUserList) { + if (CollectionUtils.isEmpty(shadowUserList)) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidUserId); + } + } + + private boolean isIndexValid(int index) { + return (index != USER_EXTERNAL_ID_MISMATCH); + } + + /** + * this method will reject the remaining user found with the same channel in shadow_user table + * + * @param shadowUserList + */ + private void rejectRemainingUser(List shadowUserList) { + shadowUserList + .stream() + .forEach( + shadowUser -> { + MigrationUtils.markUserAsRejected(shadowUser); + }); + } + /** + * this method will return the index from the shadowUserList whose user ext id is matching with + * provided one + * + * @param shadowUserList + * @param extUserId + * @return + */ + private int getIndexOfShadowUser(List shadowUserList, String extUserId) { + int index = + IntStream.range(0, shadowUserList.size()) + .filter(i -> Objects.nonNull(shadowUserList.get(i))) + .filter( + i -> StringUtils.equalsIgnoreCase(extUserId, shadowUserList.get(i).getUserExtId())) + .findFirst() + .orElse(USER_EXTERNAL_ID_MISMATCH); + return index; + } + + /** + * this method will return the shadow user based on channel and userId + * + * @param channel + * @param userId + * @return + */ + private List getShadowUsers(String channel, String userId) { + Map propsMap = new HashMap<>(); + propsMap.put(JsonKey.CHANNEL, channel); + List shadowUserList = MigrationUtils.getEligibleUsersById(userId, propsMap); + return shadowUserList; + } + + /** + * this method will migrate the user from custodian channel to non-custodian channel. + * + * @param request + * @param userId + * @param extUserId + * @param shadowUser + */ + private void selfMigrate( + Request request, String userId, String extUserId, ShadowUser shadowUser) { + String feedId = (String) request.getRequest().get(JsonKey.FEED_ID); + request.setRequest(prepareMigrationRequest(shadowUser, userId, extUserId)); + ProjectLogger.log( + "TenantMigrationActor:selfMigrate:request prepared for user migration:" + + request.getRequest(), + LoggerEnum.INFO.name()); + migrateUser(request, false); + Map propertiesMap = new HashMap<>(); + propertiesMap.put(JsonKey.CLAIM_STATUS, ClaimStatus.CLAIMED.getValue()); + propertiesMap.put(JsonKey.UPDATED_ON, new Timestamp(System.currentTimeMillis())); + propertiesMap.put(JsonKey.CLAIMED_ON, new Timestamp(System.currentTimeMillis())); + propertiesMap.put(JsonKey.USER_ID, userId); + MigrationUtils.updateRecord(propertiesMap, shadowUser.getChannel(), shadowUser.getUserExtId()); + deleteUserFeed(feedId); + } + + private void deleteUserFeed(String feedId) { + if (StringUtils.isNotBlank(feedId)) { + ProjectLogger.log( + "TenantMigrationActor:deleteUserFeed method called for feedId : " + feedId, + LoggerEnum.INFO.name()); + feedService.delete(feedId); + } + } + + /** + * this method will prepare the failure response will return the remainingCount if provided user + * ext id in incorrect + * + * @param extUserId + * @param remainingAttempt + * @return + */ + private Response prepareFailureResponse(String extUserId, int remainingAttempt) { + Response response = new Response(); + response.setResponseCode(ResponseCode.invalidUserExternalId); + response.put(JsonKey.ERROR, true); + response.put(JsonKey.MAX_ATTEMPT, MAX_MIGRATION_ATTEMPT); + response.put(JsonKey.REMAINING_ATTEMPT, remainingAttempt); + response.put( + JsonKey.MESSAGE, + MessageFormat.format(ResponseCode.invalidUserExternalId.getErrorMessage(), extUserId)); + return response; + } + + /** + * this method will prepare the migration request. + * + * @param shadowUser + * @param userId + * @param extUserId + */ + private static Map prepareMigrationRequest( + ShadowUser shadowUser, String userId, String extUserId) { + Map reqMap = new WeakHashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + reqMap.put(JsonKey.CHANNEL, shadowUser.getChannel()); + reqMap.put(JsonKey.ORG_EXTERNAL_ID, shadowUser.getOrgExtId()); + reqMap.put(JsonKey.STATUS, shadowUser.getUserStatus()); + List> extUserIds = new ArrayList<>(); + Map externalIdMap = new WeakHashMap<>(); + externalIdMap.put(JsonKey.ID, extUserId); + externalIdMap.put(JsonKey.ID_TYPE, shadowUser.getChannel()); + externalIdMap.put(JsonKey.PROVIDER, shadowUser.getChannel()); + extUserIds.add(externalIdMap); + reqMap.put(JsonKey.EXTERNAL_IDS, extUserIds); + return reqMap; + } + + private void increaseAttemptCount(ShadowUser shadowUser, boolean isFailed) { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.ATTEMPTED_COUNT, shadowUser.getAttemptedCount() + 1); + propertiesMap.put(JsonKey.UPDATED_ON, new Timestamp(System.currentTimeMillis())); + if (isFailed) { + propertiesMap.put(JsonKey.CLAIM_STATUS, ClaimStatus.FAILED.getValue()); + } + MigrationUtils.updateRecord(propertiesMap, shadowUser.getChannel(), shadowUser.getUserExtId()); + } + + /** + * this method will increase the attemptCount of the remaining user found with same channel + * + * @param shadowUserList + * @param isFailed + */ + private void increaseBulkAttemptCount(List shadowUserList, boolean isFailed) { + shadowUserList + .stream() + .forEach( + shadowUser -> { + increaseAttemptCount(shadowUser, isFailed); + }); + } + + private SSOManager getSSOManager() { + return SSOServiceFactory.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserBackgroundJobActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserBackgroundJobActor.java new file mode 100644 index 0000000000..a2c06c41bf --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserBackgroundJobActor.java @@ -0,0 +1,143 @@ +package org.sunbird.user.actors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.models.user.User; +import org.sunbird.user.util.UserUtil; +import scala.concurrent.Future; + +@ActorConfig( + tasks = { + "upsertUserDetailsToES", + "upsertUserAddressToES", + "upsertUserEducationToES", + "upsertUserJobProfileToES", + "upsertUserOrgDetailsToES" + }, + asyncTasks = { + "upsertUserDetailsToES", + "upsertUserAddressToES", + "upsertUserEducationToES", + "upsertUserJobProfileToES", + "upsertUserOrgDetailsToES" + } +) +public class UserBackgroundJobActor extends BaseActor { + + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + + @Override + public void onReceive(Request request) throws Throwable { + Map userDetails = request.getRequest(); + String operation = request.getOperation(); + switch (operation) { + case "upsertUserDetailsToES": + saveUserDataToES(userDetails); + break; + case "upsertUserAddressToES": + saveUserAddressToES(userDetails); + break; + case "upsertUserEducationToES": + saveUserEducationToES(userDetails); + break; + case "upsertUserJobProfileToES": + saveUserJobProfileToES(userDetails); + break; + case "upsertUserOrgDetailsToES": + saveUserOrgDetailsToES(userDetails); + break; + default: + onReceiveUnsupportedOperation("UserBackgroundJobActor"); + break; + } + } + + private void saveUserOrgDetailsToES(Map userDetails) { + Map userOrgMap = new HashMap<>(); + userOrgMap.put(JsonKey.ID, userDetails.get(JsonKey.ID)); + userOrgMap.put( + JsonKey.ORGANISATIONS, + UserUtil.getActiveUserOrgDetails((String) userDetails.get(JsonKey.ID))); + ProjectLogger.log("Updating saveUserOrgDetailsToES"); + upsertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) userDetails.get(JsonKey.ID), + userOrgMap); + } + + private void saveUserJobProfileToES(Map userDetails) { + ProjectLogger.log("Updating saveUserJobProfileToES"); + Map jobProfileMap = new HashMap<>(); + jobProfileMap.put(JsonKey.ID, userDetails.get(JsonKey.ID)); + jobProfileMap.put(JsonKey.JOB_PROFILE, userDetails.get(JsonKey.JOB_PROFILE)); + upsertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) userDetails.get(JsonKey.ID), + jobProfileMap); + } + + private void saveUserEducationToES(Map userDetails) { + ProjectLogger.log("Updating saveUserEducationToES"); + Map educationMap = new HashMap<>(); + educationMap.put(JsonKey.ID, userDetails.get(JsonKey.ID)); + educationMap.put(JsonKey.EDUCATION, userDetails.get(JsonKey.EDUCATION)); + upsertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) userDetails.get(JsonKey.ID), + educationMap); + } + + private void saveUserAddressToES(Map userDetails) { + ProjectLogger.log("Updating saveUserAddressToES"); + Map addressMap = new HashMap<>(); + addressMap.put(JsonKey.ID, userDetails.get(JsonKey.ID)); + addressMap.put(JsonKey.ADDRESS, userDetails.get(JsonKey.ADDRESS)); + upsertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) userDetails.get(JsonKey.ID), + addressMap); + } + + private void saveUserDataToES(Map userDetails) { + ProjectLogger.log("Updating saveUserDataToES"); + userDetails.remove(JsonKey.PASSWORD); + ObjectMapper mapper = new ObjectMapper(); + User user = mapper.convertValue(userDetails, User.class); + userDetails = mapper.convertValue(user, Map.class); + upsertDataToElastic( + ProjectUtil.EsIndex.sunbird.getIndexName(), + ProjectUtil.EsType.user.getTypeName(), + (String) userDetails.get(JsonKey.ID), + userDetails); + } + + private void upsertDataToElastic( + String indexName, String typeName, String id, Map userDetails) { + + Future bool = esUtil.upsert(typeName, id, userDetails); + + ProjectLogger.log( + "Getting ES save response for type , identifier==" + + typeName + + " " + + id + + " " + + ElasticSearchHelper.getResponseFromFuture(bool), + LoggerEnum.INFO.name()); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserBaseActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserBaseActor.java new file mode 100644 index 0000000000..25e74a8088 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserBaseActor.java @@ -0,0 +1,54 @@ +package org.sunbird.user.actors; + +import akka.actor.ActorRef; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.telemetry.util.TelemetryUtil; + +public abstract class UserBaseActor extends BaseActor { + + private ActorRef systemSettingActorRef; + + protected void generateTelemetryEvent( + Map requestMap, + String userId, + String objectType, + Map context) { + List> correlatedObject = new ArrayList<>(); + Map targetObject = + TelemetryUtil.generateTargetObject(userId, JsonKey.USER, JsonKey.UPDATE, null); + Map telemetryAction = new HashMap<>(); + + switch (objectType) { + case "userLevel": + telemetryAction.put("AssignRole", "role assigned at user level"); + break; + case "blockUser": + telemetryAction.put("BlockUser", "user blocked"); + break; + case "unblockUser": + telemetryAction.put("UnblockUser", "user unblocked"); + break; + case "profileVisibility": + telemetryAction.put("ProfileVisibility", "profile visibility setting changed"); + break; + default: + // Do Nothing + } + + TelemetryUtil.telemetryProcessingCall(telemetryAction, targetObject, correlatedObject, context); + } + + protected ActorRef getSystemSettingActorRef() { + if (systemSettingActorRef == null) { + systemSettingActorRef = getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()); + } + + return systemSettingActorRef; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserDataEncryptionActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserDataEncryptionActor.java new file mode 100644 index 0000000000..6c25ac939e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserDataEncryptionActor.java @@ -0,0 +1,83 @@ +package org.sunbird.user.actors; + +import java.util.ArrayList; +import java.util.List; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; + +@ActorConfig( + tasks = {"encryptUserData", "decryptUserData"}, + asyncTasks = {} +) +public class UserDataEncryptionActor extends BaseActor { + + @Override + public void onReceive(Request actorMessage) throws Throwable { + String operation = actorMessage.getOperation(); + switch (operation) { + case "encryptUserData": + encryptUserData(actorMessage); + break; + case "decryptUserData": + decryptUserData(actorMessage); + break; + default: + onReceiveUnsupportedOperation(actorMessage.getOperation()); + break; + } + } + + private void decryptUserData(Request actorMessage) { + triggerBackgroundOperation(actorMessage, ActorOperations.BACKGROUND_DECRYPTION.getValue()); + } + + private void encryptUserData(Request actorMessage) { + triggerBackgroundOperation(actorMessage, ActorOperations.BACKGROUND_ENCRYPTION.getValue()); + } + + @SuppressWarnings("unchecked") + private void triggerBackgroundOperation(Request actorMessage, String backgroundOperation) { + Response resp = new Response(); + resp.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(resp, self()); + + List userIds = (List) actorMessage.getRequest().get(JsonKey.USER_IDs); + int size = userIds.size(); + int startIndex = 0; + while (startIndex < size) { + Request backgroundRequest = new Request(); + backgroundRequest.setOperation(backgroundOperation); + int lastIndex = lastIndexOfUserIdsBatch(size, startIndex); + List userIdsList = getUserIdsForEncryption(userIds, startIndex, lastIndex); + backgroundRequest.getRequest().put(JsonKey.USER_IDs, userIdsList); + startIndex = lastIndex + 1; + tellToAnother(backgroundRequest); + } + } + + private int lastIndexOfUserIdsBatch(int size, int startIndex) { + int maximumSizeAllowed = + Integer.parseInt( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_USER_MAX_ENCRYPTION_LIMIT).trim()); + int maximumIndex = startIndex + maximumSizeAllowed - 1; + if (maximumIndex < size) { + return maximumIndex; + } else { + return size - 1; + } + } + + private List getUserIdsForEncryption( + List userIds, int startIndex, int lastIndex) { + List userIdsList = new ArrayList<>(); + for (int index = startIndex; index <= lastIndex; index++) { + userIdsList.add(userIds.get(index)); + } + return userIdsList; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserExternalIdManagementActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserExternalIdManagementActor.java new file mode 100644 index 0000000000..616108beda --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserExternalIdManagementActor.java @@ -0,0 +1,216 @@ +package org.sunbird.user.actors; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.user.util.UserActorOperations; + +@ActorConfig( + tasks = {"upsertUserExternalIdentityDetails"}, + asyncTasks = {"upsertUserExternalIdentityDetails"} +) +public class UserExternalIdManagementActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + if (UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS + .getValue() + .equalsIgnoreCase(request.getOperation())) { + upsertUserExternalIdentityDetails(request); + } else { + onReceiveUnsupportedOperation("UserExternalIdManagementActor"); + } + } + + @SuppressWarnings("unchecked") + private void upsertUserExternalIdentityDetails(Request request) { + Map requestMap = request.getRequest(); + String operationtype = (String) requestMap.get(JsonKey.OPERATION_TYPE); + requestMap.remove(JsonKey.OPERATION_TYPE); + List> externalIds = + (List>) requestMap.get(JsonKey.EXTERNAL_IDS); + List> responseExternalIdList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(externalIds)) { + Response response = new Response(); + List errMsgs = new ArrayList<>(); + for (Map extIdsMap : externalIds) { + try { + if (JsonKey.CREATE.equalsIgnoreCase(operationtype)) { + if (StringUtils.isBlank(extIdsMap.get(JsonKey.OPERATION)) + || JsonKey.ADD.equalsIgnoreCase(extIdsMap.get(JsonKey.OPERATION))) { + responseExternalIdList.add( + upsertUserExternalIdentityData(extIdsMap, requestMap, JsonKey.CREATE)); + } + } else { + updateUserExtId(requestMap, responseExternalIdList); + } + } catch (Exception e) { + errMsgs.add(e.getMessage()); + ProjectLogger.log( + "UserExternalIdManagementActor:upsertUserExternalIdentityDetails: Exception occurred with error message = " + + e.getMessage(), + e); + } + response.put(JsonKey.EXTERNAL_IDS, responseExternalIdList); + response.put(JsonKey.KEY, JsonKey.EXTERNAL_IDS); + if (CollectionUtils.isNotEmpty(errMsgs)) { + response.put(JsonKey.ERROR_MSG, errMsgs); + } else { + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + } + sender().tell(response, self()); + } + } + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + } + + public void updateUserExtId( + Map requestMap, List> responseExternalIdList) { + List> dbResExternalIds = getUserExternalIds(requestMap); + List> externalIds = + (List>) requestMap.get(JsonKey.EXTERNAL_IDS); + if (CollectionUtils.isNotEmpty(externalIds)) { + // will not allow user to update idType value, if user will try to update idType will + // ignore + // user will have only one entry for a idType for given provider so get extId based on idType + // List of idType values for a user will distinct and unique + for (Map extIdMap : externalIds) { + Optional> extMap = checkExternalID(dbResExternalIds, extIdMap); + Map map = extMap.orElse(null); + // Allowed operation type for externalIds ("add", "remove", "edit") + if (JsonKey.ADD.equalsIgnoreCase(extIdMap.get(JsonKey.OPERATION)) + || StringUtils.isBlank(extIdMap.get(JsonKey.OPERATION))) { + if (MapUtils.isEmpty(map)) { + responseExternalIdList.add( + upsertUserExternalIdentityData(extIdMap, requestMap, JsonKey.CREATE)); + } else { + // if external Id with same provider and idType exist then delete first then update + // to update user externalId first we need to delete the record as externalId is the + // part of composite key + deleteUserExternalId(map); + responseExternalIdList.add( + upsertUserExternalIdentityData(extIdMap, requestMap, JsonKey.UPDATE)); + } + } else { + // operation is either edit or remove + if (MapUtils.isNotEmpty(map)) { + if (JsonKey.REMOVE.equalsIgnoreCase(extIdMap.get(JsonKey.OPERATION))) { + if (StringUtils.isNotBlank(map.get(JsonKey.ID_TYPE)) + && StringUtils.isNotBlank((String) requestMap.get(JsonKey.USER_ID)) + && StringUtils.isNotBlank(map.get(JsonKey.PROVIDER))) { + deleteUserExternalId(map); + } + } else if (JsonKey.EDIT.equalsIgnoreCase(extIdMap.get(JsonKey.OPERATION))) { + // to update user externalId first we need to delete the record as externalId is the + // part of composite key + deleteUserExternalId(map); + responseExternalIdList.add( + upsertUserExternalIdentityData(extIdMap, requestMap, JsonKey.UPDATE)); + } + } else { + throwExternalIDNotFoundException( + extIdMap.get(JsonKey.ID), + extIdMap.get(JsonKey.ID_TYPE), + extIdMap.get(JsonKey.PROVIDER)); + } + } + } + } + } + + private Optional> checkExternalID( + List> dbResExternalIds, Map extIdMap) { + Optional> extMap = + dbResExternalIds + .stream() + .filter( + s -> { + if (((s.get(JsonKey.ID_TYPE)).equalsIgnoreCase(extIdMap.get(JsonKey.ID_TYPE))) + && ((s.get(JsonKey.PROVIDER)) + .equalsIgnoreCase(extIdMap.get(JsonKey.PROVIDER)))) { + return true; + } else { + return false; + } + }) + .findFirst(); + return extMap; + } + + private List> getUserExternalIds(Map requestMap) { + List> dbResExternalIds = new ArrayList<>(); + Response response = + cassandraOperation.getRecordsByIndexedProperty( + JsonKey.SUNBIRD, + JsonKey.USR_EXT_IDNT_TABLE, + JsonKey.USER_ID, + requestMap.get(JsonKey.USER_ID)); + if (null != response && null != response.getResult()) { + dbResExternalIds = (List>) response.getResult().get(JsonKey.RESPONSE); + } + return dbResExternalIds; + } + + private void deleteUserExternalId(Map map) { + map.remove(JsonKey.LAST_UPDATED_BY); + map.remove(JsonKey.CREATED_BY); + map.remove(JsonKey.LAST_UPDATED_ON); + map.remove(JsonKey.CREATED_ON); + map.remove(JsonKey.EXTERNAL_ID); + map.remove(JsonKey.ORIGINAL_EXTERNAL_ID); + map.remove(JsonKey.ORIGINAL_ID_TYPE); + map.remove(JsonKey.ORIGINAL_PROVIDER); + cassandraOperation.deleteRecord(JsonKey.SUNBIRD, JsonKey.USR_EXT_IDNT_TABLE, map); + } + + private void throwExternalIDNotFoundException(String externalId, String idType, String provider) { + throw new ProjectCommonException( + ResponseCode.externalIdNotFound.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.externalIdNotFound.getErrorMessage(), externalId, idType, provider), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + private Map upsertUserExternalIdentityData( + Map extIdsMap, Map requestMap, String operation) { + Map map = new HashMap<>(); + map.put(JsonKey.EXTERNAL_ID, extIdsMap.get(JsonKey.ID)); + map.put(JsonKey.ORIGINAL_EXTERNAL_ID, extIdsMap.get(JsonKey.ORIGINAL_EXTERNAL_ID)); + map.put(JsonKey.PROVIDER, extIdsMap.get(JsonKey.PROVIDER)); + map.put(JsonKey.ORIGINAL_PROVIDER, extIdsMap.get(JsonKey.ORIGINAL_PROVIDER)); + map.put(JsonKey.ID_TYPE, extIdsMap.get(JsonKey.ID_TYPE)); + map.put(JsonKey.ORIGINAL_ID_TYPE, extIdsMap.get(JsonKey.ORIGINAL_ID_TYPE)); + map.put(JsonKey.USER_ID, requestMap.get(JsonKey.USER_ID)); + if (JsonKey.CREATE.equalsIgnoreCase(operation)) { + map.put(JsonKey.CREATED_BY, requestMap.get(JsonKey.CREATED_BY)); + map.put(JsonKey.CREATED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + } else { + map.put(JsonKey.LAST_UPDATED_BY, requestMap.get(JsonKey.UPDATED_BY)); + map.put(JsonKey.LAST_UPDATED_ON, new Timestamp(Calendar.getInstance().getTime().getTime())); + } + cassandraOperation.upsertRecord(JsonKey.SUNBIRD, JsonKey.USR_EXT_IDNT_TABLE, map); + return map; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserFeedActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserFeedActor.java new file mode 100644 index 0000000000..81be13bfa2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserFeedActor.java @@ -0,0 +1,56 @@ +package org.sunbird.user.actors; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.dto.SearchDTO; +import org.sunbird.feed.IFeedService; +import org.sunbird.feed.impl.FeedFactory; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; + +/** This class contains API related to user feed. */ +@ActorConfig( + tasks = {"getUserFeedById"}, + asyncTasks = {} +) +public class UserFeedActor extends BaseActor { + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + if (ActorOperations.GET_USER_FEED_BY_ID.getValue().equalsIgnoreCase(operation)) { + ProjectLogger.log( + "UserFeedActor:onReceive getUserFeed method called", LoggerEnum.INFO.name()); + String userId = (String) request.getRequest().get(JsonKey.USER_ID); + getUserFeed(userId); + } else { + onReceiveUnsupportedOperation("UserFeedActor"); + } + } + + private void getUserFeed(String userId) { + IFeedService feedService = FeedFactory.getInstance(); + Map filters = new HashMap<>(); + filters.put(JsonKey.USER_ID, userId); + SearchDTO search = new SearchDTO(); + search.getAdditionalProperties().put(JsonKey.FILTERS, filters); + Response userFeedResponse = feedService.search(search); + Map result = + (Map) userFeedResponse.getResult().get(JsonKey.RESPONSE); + result.put( + JsonKey.USER_FEED, + result.get(JsonKey.CONTENT) == null ? new ArrayList<>() : result.get(JsonKey.CONTENT)); + result.remove(JsonKey.COUNT); + result.remove(JsonKey.CONTENT); + sender().tell(userFeedResponse, self()); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserLoginActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserLoginActor.java new file mode 100644 index 0000000000..7ed108a877 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserLoginActor.java @@ -0,0 +1,49 @@ +package org.sunbird.user.actors; + +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.TelemetryEnvKey; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.Util; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; + +@ActorConfig( + tasks = {"userCurrentLogin"}, + asyncTasks = {} +) +public class UserLoginActor extends UserBaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + + if (operation.equalsIgnoreCase("userCurrentLogin")) { + updateUserLoginTime(request); + } else { + onReceiveUnsupportedOperation("UserLoginActor"); + } + } + + /** + * Updates user's current login time in Keycloak. + * + * @param actorMessage Request containing user ID. + */ + private void updateUserLoginTime(Request actorMessage) { + String userId = (String) actorMessage.getRequest().get(JsonKey.USER_ID); + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + if (Boolean.parseBoolean(PropertiesCache.getInstance().getProperty(JsonKey.IS_SSO_ENABLED))) { + SSOManager ssoManager = SSOServiceFactory.getInstance(); + boolean loginTimeResponse = ssoManager.addUserLoginTime(userId); + ProjectLogger.log( + "UserLoginActor:updateUserLoginTime: keycloak response = " + loginTimeResponse); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserManagementActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserManagementActor.java new file mode 100644 index 0000000000..84fad88eac --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserManagementActor.java @@ -0,0 +1,1278 @@ +package org.sunbird.user.actors; + +import akka.actor.ActorRef; +import akka.dispatch.Futures; +import akka.dispatch.Mapper; +import akka.pattern.Patterns; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.sql.Timestamp; +import java.text.MessageFormat; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpStatus; +import org.codehaus.jackson.annotate.JsonMethod; +import org.json.JSONArray; +import org.json.JSONObject; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.location.impl.LocationClientImpl; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.actorutil.org.impl.OrganisationClientImpl; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.actorutil.user.UserClient; +import org.sunbird.actorutil.user.impl.UserClientImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.BaseRequestValidator; +import org.sunbird.common.request.Request; +import org.sunbird.common.request.UserRequestValidator; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.common.util.Matcher; +import org.sunbird.content.store.util.ContentStoreUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.kafka.client.KafkaClient; +import org.sunbird.learner.actors.role.service.RoleService; +import org.sunbird.learner.organisation.external.identity.service.OrgExternalService; +import org.sunbird.learner.util.*; +import org.sunbird.models.organisation.Organisation; +import org.sunbird.models.user.User; +import org.sunbird.models.user.UserType; +import org.sunbird.models.user.org.UserOrg; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.user.dao.UserOrgDao; +import org.sunbird.user.dao.impl.UserOrgDaoImpl; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; +import org.sunbird.user.util.UserActorOperations; +import org.sunbird.user.util.UserUtil; +import scala.Tuple2; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {"createUser", "updateUser", "createUserV3", "createUserV4", "getManagedUsers"}, + asyncTasks = {} +) +public class UserManagementActor extends BaseActor { + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private UserRequestValidator userRequestValidator = new UserRequestValidator(); + private UserService userService = UserServiceImpl.getInstance(); + private SystemSettingClient systemSettingClient = SystemSettingClientImpl.getInstance(); + private OrganisationClient organisationClient = new OrganisationClientImpl(); + private OrgExternalService orgExternalService = new OrgExternalService(); + private Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + private Util.DbInfo userOrgDb = Util.dbInfoMap.get(JsonKey.USER_ORG_DB); + private ObjectMapper mapper = new ObjectMapper(); + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + private ActorRef systemSettingActorRef = null; + private static ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + private UserClient userClient = new UserClientImpl(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + cacheFrameworkFieldsConfig(); + if (systemSettingActorRef == null) { + systemSettingActorRef = getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()); + } + String operation = request.getOperation(); + switch (operation) { + case "createUser": // create User [v1,v2,v3] + createUser(request); + break; + case "updateUser": + updateUser(request); + break; + case "createUserV3": // signup [/v1/user/signup] + createUserV3(request); + break; + case "createUserV4": // managedUser creation + createUserV4(request); + break; + case "getManagedUsers": // managedUser search + getManagedUsers(request); + break; + default: + onReceiveUnsupportedOperation("UserManagementActor"); + } + } + /** + * This method will create user in user in cassandra and update to ES as well at same time. + * + * @param actorMessage + */ + private void createUserV3(Request actorMessage) { + ProjectLogger.log("UserManagementActor:createUserV3 method called.", LoggerEnum.INFO.name()); + createUserV3_V4(actorMessage, false); + } + /** + * This method will create managed user in user in cassandra and update to ES as well at same + * time. Email and phone is not provided, name and managedBy is mandatory. BMGS or Location is + * optional + * + * @param actorMessage + */ + private void createUserV4(Request actorMessage) { + ProjectLogger.log("UserManagementActor:createUserV4 method called.", LoggerEnum.INFO.name()); + createUserV3_V4(actorMessage, true); + } + + private void createUserV3_V4(Request actorMessage, boolean isV4) { + actorMessage.toLower(); + Map userMap = actorMessage.getRequest(); + String signupType = + (String) actorMessage.getContext().get(JsonKey.SIGNUP_TYPE) != null + ? (String) actorMessage.getContext().get(JsonKey.SIGNUP_TYPE) + : ""; + String source = + (String) actorMessage.getContext().get(JsonKey.REQUEST_SOURCE) != null + ? (String) actorMessage.getContext().get(JsonKey.REQUEST_SOURCE) + : ""; + + String managedBy = (String) userMap.get(JsonKey.MANAGED_BY); + String channel = DataCacheHandler.getConfigSettings().get(JsonKey.CUSTODIAN_ORG_CHANNEL); + String rootOrgId = DataCacheHandler.getConfigSettings().get(JsonKey.CUSTODIAN_ORG_ID); + userMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + userMap.put(JsonKey.CHANNEL, channel); + userMap.put(JsonKey.USER_TYPE, UserType.OTHER.getTypeName()); + + if (isV4) { + ProjectLogger.log( + "validateUserId :: requestedId: " + actorMessage.getContext().get(JsonKey.REQUESTED_BY), + LoggerEnum.INFO); + String userId = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY); + userMap.put(JsonKey.CREATED_BY, userId); + // If user account isManagedUser (managedBy passed in request) should be same as context + // user_id + userService.validateUserId(actorMessage, managedBy); + + // If managedUser limit is set, validate total number of managed users against it + UserUtil.validateManagedUserLimit(managedBy); + } + processUserRequestV3_V4(userMap, signupType, source, managedBy, actorMessage.getContext()); + } + + private void cacheFrameworkFieldsConfig() { + if (MapUtils.isEmpty(DataCacheHandler.getFrameworkFieldsConfig())) { + Map> frameworkFieldsConfig = + systemSettingClient.getSystemSettingByFieldAndKey( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + JsonKey.USER_PROFILE_CONFIG, + JsonKey.FRAMEWORK, + new TypeReference>>() {}); + DataCacheHandler.setFrameworkFieldsConfig(frameworkFieldsConfig); + } + } + + @SuppressWarnings("unchecked") + private void updateUser(Request actorMessage) { + Util.initializeContext(actorMessage, TelemetryEnvKey.USER); + actorMessage.toLower(); + Util.getUserProfileConfig(systemSettingActorRef); + String callerId = (String) actorMessage.getContext().get(JsonKey.CALLER_ID); + boolean isPrivate = false; + if (actorMessage.getContext().containsKey(JsonKey.PRIVATE)) { + isPrivate = (boolean) actorMessage.getContext().get(JsonKey.PRIVATE); + } + Map userMap = actorMessage.getRequest(); + userRequestValidator.validateUpdateUserRequest(actorMessage); + validateUserOrganisations(actorMessage, isPrivate); + Map userDbRecord = UserUtil.validateExternalIdsAndReturnActiveUser(userMap); + String managedById = (String) userDbRecord.get(JsonKey.MANAGED_BY); + if (!isPrivate) { + if (StringUtils.isNotBlank(callerId)) { + userService.validateUploader(actorMessage); + } else { + userService.validateUserId(actorMessage, managedById); + } + } + validateUserFrameworkData(userMap, userDbRecord); + // Check if the user is Custodian Org user + boolean isCustodianOrgUser = isCustodianOrgUser(userMap); + validateUserTypeForUpdate(userMap, isCustodianOrgUser); + User user = mapper.convertValue(userMap, User.class); + UserUtil.validateExternalIdsForUpdateUser(user, isCustodianOrgUser); + userMap.put(JsonKey.EXTERNAL_IDS, user.getExternalIds()); + UserUtil.validateUserPhoneEmailAndWebPages(user, JsonKey.UPDATE); + // not allowing user to update the status,provider,userName + removeFieldsFrmReq(userMap); + // if we are updating email then need to update isEmailVerified flag inside keycloak + UserUtil.checkEmailSameOrDiff(userMap, userDbRecord); + convertValidatedLocationCodesToIDs(userMap); + + userMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + if (StringUtils.isBlank(callerId)) { + userMap.put(JsonKey.UPDATED_BY, actorMessage.getContext().get(JsonKey.REQUESTED_BY)); + } + Map requestMap = UserUtil.encryptUserData(userMap); + validateRecoveryEmailPhone(userDbRecord, userMap); + UserUtil.addMaskEmailAndMaskPhone(requestMap); + removeUnwanted(requestMap); + if (requestMap.containsKey(JsonKey.TNC_ACCEPTED_ON)) { + requestMap.put( + JsonKey.TNC_ACCEPTED_ON, new Timestamp((Long) requestMap.get(JsonKey.TNC_ACCEPTED_ON))); + } + if (requestMap.containsKey(JsonKey.RECOVERY_EMAIL) + && StringUtils.isBlank((String) requestMap.get(JsonKey.RECOVERY_EMAIL))) { + requestMap.put(JsonKey.RECOVERY_EMAIL, null); + } + if (requestMap.containsKey(JsonKey.RECOVERY_PHONE) + && StringUtils.isBlank((String) requestMap.get(JsonKey.RECOVERY_PHONE))) { + requestMap.put(JsonKey.RECOVERY_PHONE, null); + } + + Map userBooleanMap = updatedUserFlagsMap(userMap, userDbRecord); + int userFlagValue = userFlagsToNum(userBooleanMap); + requestMap.put(JsonKey.FLAGS_VALUE, userFlagValue); + // As of now disallowing updating manageble user's phone/email, will le allowed in next release + boolean resetPasswordLink = false; + if (StringUtils.isNotEmpty(managedById) + && (StringUtils.isNotEmpty((String) requestMap.get(JsonKey.EMAIL))) + || (StringUtils.isNotEmpty((String) requestMap.get(JsonKey.PHONE)))) { + requestMap.put(JsonKey.MANAGED_BY, null); + resetPasswordLink = true; + } + Response response = + cassandraOperation.updateRecord( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), requestMap); + + if (StringUtils.isNotBlank(callerId)) { + userMap.put(JsonKey.ROOT_ORG_ID, actorMessage.getContext().get(JsonKey.ROOT_ORG_ID)); + } + Response resp = null; + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + if (isPrivate) { + updateUserOrganisations(actorMessage); + } + Map userRequest = new HashMap<>(userMap); + userRequest.put(JsonKey.OPERATION_TYPE, JsonKey.UPDATE); + resp = saveUserAttributes(userRequest); + } else { + ProjectLogger.log("UserManagementActor:updateUser: User update failure"); + } + response.put( + JsonKey.ERRORS, + ((Map) resp.getResult().get(JsonKey.RESPONSE)).get(JsonKey.ERRORS)); + sender().tell(response, self()); + // Managed-users should get ResetPassword Link + if (resetPasswordLink) { + sendResetPasswordLink(requestMap); + } + if (null != resp) { + Map completeUserDetails = new HashMap<>(userDbRecord); + completeUserDetails.putAll(requestMap); + saveUserDetailsToEs(completeUserDetails); + } + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + targetObject = + TelemetryUtil.generateTargetObject( + (String) userMap.get(JsonKey.USER_ID), TelemetryEnvKey.USER, JsonKey.UPDATE, null); + TelemetryUtil.telemetryProcessingCall( + userMap, targetObject, correlatedObject, actorMessage.getContext()); + } + + @SuppressWarnings("unchecked") + private void validateUserOrganisations(Request actorMessage, boolean isPrivate) { + if (isPrivate && null != actorMessage.getRequest().get(JsonKey.ORGANISATIONS)) { + List> userOrgList = + (List>) actorMessage.getRequest().get(JsonKey.ORGANISATIONS); + if (CollectionUtils.isNotEmpty(userOrgList)) { + List orgIdList = new ArrayList<>(); + userOrgList.forEach(org -> orgIdList.add((String) org.get(JsonKey.ORGANISATION_ID))); + List fields = new ArrayList<>(); + fields.add(JsonKey.HASHTAGID); + fields.add(JsonKey.ID); + List orgList = organisationClient.esSearchOrgByIds(orgIdList, fields); + Map orgMap = new HashMap<>(); + orgList.forEach(org -> orgMap.put(org.getId(), org)); + List missingOrgIds = new ArrayList<>(); + for (Map userOrg : userOrgList) { + String orgId = (String) userOrg.get(JsonKey.ORGANISATION_ID); + Organisation organisation = (Organisation) orgMap.get(orgId); + if (null == organisation) { + missingOrgIds.add(orgId); + } else { + userOrg.put(JsonKey.HASH_TAG_ID, organisation.getHashTagId()); + if (userOrg.get(JsonKey.ROLES) != null) { + List rolesList = (List) userOrg.get(JsonKey.ROLES); + RoleService.validateRoles(rolesList); + if (!rolesList.contains(ProjectUtil.UserRole.PUBLIC.getValue())) { + rolesList.add(ProjectUtil.UserRole.PUBLIC.getValue()); + } + } else { + userOrg.put(JsonKey.ROLES, Arrays.asList(ProjectUtil.UserRole.PUBLIC.getValue())); + } + } + } + if (!missingOrgIds.isEmpty()) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + JsonKey.ORGANISATION_ID, + missingOrgIds)); + } + } + } + } + + @SuppressWarnings("unchecked") + private void updateUserOrganisations(Request actorMessage) { + if (null != actorMessage.getRequest().get(JsonKey.ORGANISATIONS)) { + ProjectLogger.log("UserManagementActor: updateUserOrganisation called", LoggerEnum.INFO); + List> orgList = + (List>) actorMessage.getRequest().get(JsonKey.ORGANISATIONS); + String userId = (String) actorMessage.getRequest().get(JsonKey.USER_ID); + String rootOrgId = getUserRootOrgId(userId); + List> orgListDb = UserUtil.getAllUserOrgDetails(userId); + Map orgDbMap = new HashMap<>(); + if (CollectionUtils.isNotEmpty(orgListDb)) { + orgListDb.forEach(org -> orgDbMap.put((String) org.get(JsonKey.ORGANISATION_ID), org)); + } + if (!orgList.isEmpty()) { + for (Map org : orgList) { + createOrUpdateOrganisations(org, orgDbMap, actorMessage); + } + } + String requestedBy = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY); + removeOrganisations(orgDbMap, rootOrgId, requestedBy); + ProjectLogger.log( + "UserManagementActor:updateUserOrganisations : " + "updateUserOrganisation Completed", + LoggerEnum.INFO); + } + } + + private String getUserRootOrgId(String userId) { + User user = userService.getUserById(userId); + return user.getRootOrgId(); + } + + @SuppressWarnings("unchecked") + private void createOrUpdateOrganisations( + Map org, Map orgDbMap, Request actorMessage) { + UserOrgDao userOrgDao = UserOrgDaoImpl.getInstance(); + String userId = (String) actorMessage.getRequest().get(JsonKey.USER_ID); + if (MapUtils.isNotEmpty(org)) { + UserOrg userOrg = mapper.convertValue(org, UserOrg.class); + String orgId = (String) org.get(JsonKey.ORGANISATION_ID); + userOrg.setUserId(userId); + userOrg.setDeleted(false); + if (null != orgId && orgDbMap.containsKey(orgId)) { + userOrg.setUpdatedDate(ProjectUtil.getFormattedDate()); + userOrg.setUpdatedBy((String) (actorMessage.getContext().get(JsonKey.REQUESTED_BY))); + userOrg.setId((String) ((Map) orgDbMap.get(orgId)).get(JsonKey.ID)); + userOrgDao.updateUserOrg(userOrg); + orgDbMap.remove(orgId); + } else { + userOrg.setHashTagId((String) (org.get(JsonKey.HASH_TAG_ID))); + userOrg.setOrgJoinDate(ProjectUtil.getFormattedDate()); + userOrg.setAddedBy((String) actorMessage.getContext().get(JsonKey.REQUESTED_BY)); + userOrg.setId(ProjectUtil.getUniqueIdFromTimestamp(actorMessage.getEnv())); + userOrgDao.createUserOrg(userOrg); + } + } + } + + @SuppressWarnings("unchecked") + private void removeOrganisations( + Map orgDbMap, String rootOrgId, String requestedBy) { + Set ids = orgDbMap.keySet(); + UserOrgDao userOrgDao = UserOrgDaoImpl.getInstance(); + ids.remove(rootOrgId); + ObjectMapper mapper = new ObjectMapper(); + for (String id : ids) { + UserOrg userOrg = mapper.convertValue(orgDbMap.get(id), UserOrg.class); + userOrg.setDeleted(true); + userOrg.setId((String) ((Map) orgDbMap.get(id)).get(JsonKey.ID)); + userOrg.setUpdatedDate(ProjectUtil.getFormattedDate()); + userOrg.setUpdatedBy(requestedBy); + userOrg.setOrgLeftDate(ProjectUtil.getFormattedDate()); + userOrgDao.updateUserOrg(userOrg); + } + } + // Check if the user is Custodian Org user + private boolean isCustodianOrgUser(Map userMap) { + boolean isCustodianOrgUser = false; + String custodianRootOrgId = null; + User user = userService.getUserById((String) userMap.get(JsonKey.USER_ID)); + try { + custodianRootOrgId = getCustodianRootOrgId(); + } catch (Exception ex) { + ProjectLogger.log( + "UserManagementActor: isCustodianOrgUser :" + + " Exception Occured while fetching Custodian Org ", + LoggerEnum.INFO); + } + if (StringUtils.isNotBlank(custodianRootOrgId) + && user.getRootOrgId().equalsIgnoreCase(custodianRootOrgId)) { + isCustodianOrgUser = true; + } + return isCustodianOrgUser; + } + + private void validateUserTypeForUpdate(Map userMap, boolean isCustodianOrgUser) { + if (userMap.containsKey(JsonKey.USER_TYPE)) { + String userType = (String) userMap.get(JsonKey.USER_TYPE); + if (UserType.TEACHER.getTypeName().equalsIgnoreCase(userType) && isCustodianOrgUser) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorTeacherCannotBelongToCustodianOrg, + ResponseCode.errorTeacherCannotBelongToCustodianOrg.getErrorMessage()); + } else { + userMap.put(JsonKey.USER_TYPE, UserType.OTHER.getTypeName()); + } + } + } + + @SuppressWarnings("unchecked") + private void validateUserFrameworkData( + Map userRequestMap, Map userDbRecord) { + if (userRequestMap.containsKey(JsonKey.FRAMEWORK)) { + Map framework = (Map) userRequestMap.get(JsonKey.FRAMEWORK); + List frameworkIdList; + if (framework.get(JsonKey.ID) instanceof String) { + String frameworkIdString = (String) framework.remove(JsonKey.ID); + frameworkIdList = new ArrayList<>(); + frameworkIdList.add(frameworkIdString); + framework.put(JsonKey.ID, frameworkIdList); + } else { + frameworkIdList = (List) framework.get(JsonKey.ID); + } + userRequestMap.put(JsonKey.FRAMEWORK, framework); + List frameworkFields = + DataCacheHandler.getFrameworkFieldsConfig().get(JsonKey.FIELDS); + List frameworkMandatoryFields = + DataCacheHandler.getFrameworkFieldsConfig().get(JsonKey.MANDATORY_FIELDS); + userRequestValidator.validateMandatoryFrameworkFields( + userRequestMap, frameworkFields, frameworkMandatoryFields); + Map rootOrgMap = + Util.getOrgDetails((String) userDbRecord.get(JsonKey.ROOT_ORG_ID)); + String hashtagId = (String) rootOrgMap.get(JsonKey.HASHTAGID); + + verifyFrameworkId(hashtagId, frameworkIdList); + Map>> frameworkCachedValue = + getFrameworkDetails(frameworkIdList.get(0)); + ((Map) userRequestMap.get(JsonKey.FRAMEWORK)).remove(JsonKey.ID); + userRequestValidator.validateFrameworkCategoryValues(userRequestMap, frameworkCachedValue); + ((Map) userRequestMap.get(JsonKey.FRAMEWORK)) + .put(JsonKey.ID, frameworkIdList); + } + } + + private void removeFieldsFrmReq(Map userMap) { + userMap.remove(JsonKey.ENC_EMAIL); + userMap.remove(JsonKey.ENC_PHONE); + userMap.remove(JsonKey.STATUS); + userMap.remove(JsonKey.PROVIDER); + userMap.remove(JsonKey.USERNAME); + userMap.remove(JsonKey.ROOT_ORG_ID); + userMap.remove(JsonKey.LOGIN_ID); + userMap.remove(JsonKey.ROLES); + // channel update is not allowed + userMap.remove(JsonKey.CHANNEL); + } + + /** + * Method to create the new user , Username should be unique . + * + * @param actorMessage Request + */ + private void createUser(Request actorMessage) { + Util.initializeContext(actorMessage, TelemetryEnvKey.USER); + actorMessage.toLower(); + Map userMap = actorMessage.getRequest(); + String callerId = (String) actorMessage.getContext().get(JsonKey.CALLER_ID); + String version = (String) actorMessage.getContext().get(JsonKey.VERSION); + if (StringUtils.isNotBlank(version) + && (JsonKey.VERSION_2.equalsIgnoreCase(version) + || JsonKey.VERSION_3.equalsIgnoreCase(version))) { + userRequestValidator.validateCreateUserV2Request(actorMessage); + if (StringUtils.isNotBlank(callerId)) { + userMap.put(JsonKey.ROOT_ORG_ID, actorMessage.getContext().get(JsonKey.ROOT_ORG_ID)); + } + } else { + userRequestValidator.validateCreateUserV1Request(actorMessage); + } + validateChannelAndOrganisationId(userMap); + validatePrimaryAndRecoveryKeys(userMap); + + // remove these fields from req + userMap.remove(JsonKey.ENC_EMAIL); + userMap.remove(JsonKey.ENC_PHONE); + actorMessage.getRequest().putAll(userMap); + Util.getUserProfileConfig(systemSettingActorRef); + boolean isCustodianOrg = false; + if (StringUtils.isBlank(callerId)) { + userMap.put(JsonKey.CREATED_BY, actorMessage.getContext().get(JsonKey.REQUESTED_BY)); + try { + if (StringUtils.isBlank((String) userMap.get(JsonKey.CHANNEL)) + && StringUtils.isBlank((String) userMap.get(JsonKey.ROOT_ORG_ID))) { + String channel = userService.getCustodianChannel(userMap, systemSettingActorRef); + String rootOrgId = userService.getRootOrgIdFromChannel(channel); + userMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + userMap.put(JsonKey.CHANNEL, channel); + isCustodianOrg = true; + } + } catch (Exception ex) { + sender().tell(ex, self()); + return; + } + } + validateUserType(userMap, isCustodianOrg); + if (userMap.containsKey(JsonKey.ORG_EXTERNAL_ID)) { + String orgExternalId = (String) userMap.get(JsonKey.ORG_EXTERNAL_ID); + String channel = (String) userMap.get(JsonKey.CHANNEL); + String orgId = + orgExternalService.getOrgIdFromOrgExternalIdAndProvider(orgExternalId, channel); + if (StringUtils.isBlank(orgId)) { + ProjectLogger.log( + "UserManagementActor:createUser: No organisation with orgExternalId = " + + orgExternalId + + " and channel = " + + channel, + LoggerEnum.ERROR.name()); + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + orgExternalId, + JsonKey.ORG_EXTERNAL_ID)); + } + if (userMap.containsKey(JsonKey.ORGANISATION_ID) + && !orgId.equals(userMap.get(JsonKey.ORGANISATION_ID))) { + ProjectLogger.log( + "UserManagementActor:createUser Mismatch of organisation from orgExternalId=" + + orgExternalId + + " and channel=" + + channel + + " as organisationId=" + + orgId + + " and request organisationId=" + + userMap.get(JsonKey.ORGANISATION_ID), + LoggerEnum.ERROR.name()); + throwParameterMismatchException(JsonKey.ORG_EXTERNAL_ID, JsonKey.ORGANISATION_ID); + } + userMap.remove(JsonKey.ORG_EXTERNAL_ID); + userMap.put(JsonKey.ORGANISATION_ID, orgId); + } + processUserRequest(userMap, callerId, actorMessage.getContext()); + } + + private void validateUserType(Map userMap, boolean isCustodianOrg) { + String userType = (String) userMap.get(JsonKey.USER_TYPE); + if (StringUtils.isNotBlank(userType)) { + if (userType.equalsIgnoreCase(UserType.TEACHER.getTypeName()) && isCustodianOrg) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorTeacherCannotBelongToCustodianOrg, + ResponseCode.errorTeacherCannotBelongToCustodianOrg.getErrorMessage()); + } else if (UserType.TEACHER.getTypeName().equalsIgnoreCase(userType)) { + String custodianRootOrgId = null; + try { + custodianRootOrgId = getCustodianRootOrgId(); + } catch (Exception ex) { + ProjectLogger.log( + "UserManagementActor: validateUserType :" + + " Exception Occured while fetching Custodian Org ", + LoggerEnum.INFO); + } + if (StringUtils.isNotBlank(custodianRootOrgId) + && ((String) userMap.get(JsonKey.ROOT_ORG_ID)).equalsIgnoreCase(custodianRootOrgId)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorTeacherCannotBelongToCustodianOrg, + ResponseCode.errorTeacherCannotBelongToCustodianOrg.getErrorMessage()); + } + } + } else { + userMap.put(JsonKey.USER_TYPE, UserType.OTHER.getTypeName()); + } + } + + private void validateChannelAndOrganisationId(Map userMap) { + String organisationId = (String) userMap.get(JsonKey.ORGANISATION_ID); + String requestedChannel = (String) userMap.get(JsonKey.CHANNEL); + String subOrgRootOrgId = ""; + if (StringUtils.isNotBlank(organisationId)) { + Organisation organisation = organisationClient.esGetOrgById(organisationId); + if (null == organisation) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidOrgData); + } + if (organisation.isRootOrg()) { + subOrgRootOrgId = organisation.getId(); + if (StringUtils.isNotBlank(requestedChannel) + && !requestedChannel.equalsIgnoreCase(organisation.getChannel())) { + throwParameterMismatchException(JsonKey.CHANNEL, JsonKey.ORGANISATION_ID); + } + userMap.put(JsonKey.CHANNEL, organisation.getChannel()); + } else { + subOrgRootOrgId = organisation.getRootOrgId(); + Organisation subOrgRootOrg = organisationClient.esGetOrgById(subOrgRootOrgId); + if (null != subOrgRootOrg) { + if (StringUtils.isNotBlank(requestedChannel) + && !requestedChannel.equalsIgnoreCase(subOrgRootOrg.getChannel())) { + throwParameterMismatchException(JsonKey.CHANNEL, JsonKey.ORGANISATION_ID); + } + userMap.put(JsonKey.CHANNEL, subOrgRootOrg.getChannel()); + } + } + userMap.put(JsonKey.ROOT_ORG_ID, subOrgRootOrgId); + } + String rootOrgId = ""; + if (StringUtils.isNotBlank(requestedChannel)) { + rootOrgId = userService.getRootOrgIdFromChannel(requestedChannel); + if (StringUtils.isNotBlank(subOrgRootOrgId) && !rootOrgId.equalsIgnoreCase(subOrgRootOrgId)) { + throwParameterMismatchException(JsonKey.CHANNEL, JsonKey.ORGANISATION_ID); + } + userMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + } + } + + private void throwParameterMismatchException(String... param) { + ProjectCommonException.throwClientErrorException( + ResponseCode.parameterMismatch, + MessageFormat.format( + ResponseCode.parameterMismatch.getErrorMessage(), StringFormatter.joinByComma(param))); + } + + private void processUserRequestV3_V4( + Map userMap, + String signupType, + String source, + String managedBy, + Map context) { + UserUtil.setUserDefaultValueForV3(userMap); + UserUtil.toLower(userMap); + if (StringUtils.isEmpty(managedBy)) { + UserUtil.checkPhoneUniqueness((String) userMap.get(JsonKey.PHONE)); + UserUtil.checkEmailUniqueness((String) userMap.get(JsonKey.EMAIL)); + } else { + String channel = DataCacheHandler.getConfigSettings().get(JsonKey.CUSTODIAN_ORG_CHANNEL); + String rootOrgId = DataCacheHandler.getConfigSettings().get(JsonKey.CUSTODIAN_ORG_ID); + userMap.put(JsonKey.ROOT_ORG_ID, rootOrgId); + userMap.put(JsonKey.CHANNEL, channel); + Map managedByInfo = UserUtil.validateManagedByUser(managedBy); + convertValidatedLocationCodesToIDs(userMap); + validateUserFrameworkData(userMap, managedByInfo); + } + String userId = ProjectUtil.generateUniqueId(); + userMap.put(JsonKey.ID, userId); + userMap.put(JsonKey.USER_ID, userId); + try { + UserUtility.encryptUserData(userMap); + } catch (Exception ex) { + ex.printStackTrace(); + } + UserUtil.addMaskEmailAndMaskPhone(userMap); + userMap.put(JsonKey.IS_DELETED, false); + Map userFlagsMap = new HashMap<>(); + userFlagsMap.put(JsonKey.STATE_VALIDATED, false); + if (StringUtils.isEmpty(managedBy)) { + userFlagsMap.put( + JsonKey.EMAIL_VERIFIED, + (Boolean) + (userMap.get(JsonKey.EMAIL_VERIFIED) != null + ? userMap.get(JsonKey.EMAIL_VERIFIED) + : false)); + userFlagsMap.put( + JsonKey.PHONE_VERIFIED, + (Boolean) + (userMap.get(JsonKey.PHONE_VERIFIED) != null + ? userMap.get(JsonKey.PHONE_VERIFIED) + : false)); + } + int userFlagValue = userFlagsToNum(userFlagsMap); + userMap.put(JsonKey.FLAGS_VALUE, userFlagValue); + final String password = (String) userMap.get(JsonKey.PASSWORD); + userMap.remove(JsonKey.PASSWORD); + Response response = + cassandraOperation.insertRecord(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), userMap); + response.put(JsonKey.USER_ID, userMap.get(JsonKey.ID)); + Map esResponse = new HashMap<>(); + if (JsonKey.SUCCESS.equalsIgnoreCase((String) response.get(JsonKey.RESPONSE))) { + Map orgMap = saveUserOrgInfo(userMap); + esResponse = Util.getUserDetails(userMap, orgMap); + } else { + ProjectLogger.log("UserManagementActor:processUserRequest: User creation failure"); + } + if ("kafka".equalsIgnoreCase(ProjectUtil.getConfigValue("sunbird_user_create_sync_type"))) { + saveUserToKafka(esResponse); + sender().tell(response, self()); + } else { + Future kcFuture = + Futures.future( + new Callable() { + + @Override + public Boolean call() { + try { + Map updatePasswordMap = new HashMap(); + updatePasswordMap.put(JsonKey.ID, (String) userMap.get(JsonKey.ID)); + updatePasswordMap.put(JsonKey.PASSWORD, password); + ProjectLogger.log( + "Update password value passed " + + password + + " --" + + (String) userMap.get(JsonKey.ID), + LoggerEnum.INFO.name()); + return UserUtil.updatePassword(updatePasswordMap); + } catch (Exception e) { + ProjectLogger.log( + "Error occured during update pasword : " + e.getMessage(), + LoggerEnum.ERROR.name()); + return false; + } + } + }, + getContext().dispatcher()); + Future future = + saveUserToES(esResponse) + .zip(kcFuture) + .map( + new Mapper, Response>() { + + @Override + public Response apply(Tuple2 parameter) { + boolean updatePassResponse = parameter._2; + ProjectLogger.log( + "UserManagementActor:processUserRequest: Response from update password call " + + updatePassResponse, + LoggerEnum.INFO.name()); + if (!updatePassResponse) { + response.put( + JsonKey.ERROR_MSG, ResponseMessage.Message.ERROR_USER_UPDATE_PASSWORD); + } + return response; + } + }, + getContext().dispatcher()); + Patterns.pipe(future, getContext().dispatcher()).to(sender()); + } + + processTelemetry(userMap, signupType, source, userId, context); + } + + private void processTelemetry( + Map userMap, + String signupType, + String source, + String userId, + Map context) { + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + Map rollUp = new HashMap<>(); + rollUp.put("l1", (String) userMap.get(JsonKey.ROOT_ORG_ID)); + context.put(JsonKey.ROLLUP, rollUp); + targetObject = + TelemetryUtil.generateTargetObject( + (String) userMap.get(JsonKey.ID), TelemetryEnvKey.USER, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject(userId, TelemetryEnvKey.USER, null, correlatedObject); + if (StringUtils.isNotBlank(signupType)) { + TelemetryUtil.generateCorrelatedObject( + signupType, StringUtils.capitalize(JsonKey.SIGNUP_TYPE), null, correlatedObject); + } else { + ProjectLogger.log("UserManagementActor:processUserRequest: No signupType found"); + } + if (StringUtils.isNotBlank(source)) { + TelemetryUtil.generateCorrelatedObject( + source, StringUtils.capitalize(JsonKey.REQUEST_SOURCE), null, correlatedObject); + } else { + ProjectLogger.log("UserManagementActor:processUserRequest: No source found"); + } + + TelemetryUtil.telemetryProcessingCall(userMap, targetObject, correlatedObject, context); + } + + private Map saveUserOrgInfo(Map userMap) { + Map userOrgMap = createUserOrgRequestData(userMap); + cassandraOperation.insertRecord(userOrgDb.getKeySpace(), userOrgDb.getTableName(), userOrgMap); + + return userOrgMap; + } + + private Map createUserOrgRequestData(Map userMap) { + Map userOrgMap = new HashMap(); + userOrgMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(1)); + userOrgMap.put(JsonKey.HASHTAGID, userMap.get(JsonKey.ROOT_ORG_ID)); + userOrgMap.put(JsonKey.USER_ID, userMap.get(JsonKey.USER_ID)); + userOrgMap.put(JsonKey.ORGANISATION_ID, userMap.get(JsonKey.ROOT_ORG_ID)); + userOrgMap.put(JsonKey.ORG_JOIN_DATE, ProjectUtil.getFormattedDate()); + userOrgMap.put(JsonKey.IS_DELETED, false); + userOrgMap.put(JsonKey.ROLES, userMap.get(JsonKey.ROLES)); + return userOrgMap; + } + + @SuppressWarnings("unchecked") + private void processUserRequest( + Map userMap, String callerId, Map reqContext) { + Map requestMap = null; + UserUtil.setUserDefaultValue(userMap, callerId); + ObjectMapper mapper = new ObjectMapper(); + User user = mapper.convertValue(userMap, User.class); + UserUtil.validateExternalIds(user, JsonKey.CREATE); + userMap.put(JsonKey.EXTERNAL_IDS, user.getExternalIds()); + UserUtil.validateUserPhoneEmailAndWebPages(user, JsonKey.CREATE); + convertValidatedLocationCodesToIDs(userMap); + + UserUtil.toLower(userMap); + String userId = ProjectUtil.generateUniqueId(); + userMap.put(JsonKey.ID, userId); + userMap.put(JsonKey.USER_ID, userId); + requestMap = UserUtil.encryptUserData(userMap); + UserUtil.addMaskEmailAndMaskPhone(requestMap); + removeUnwanted(requestMap); + requestMap.put(JsonKey.IS_DELETED, false); + Map userFlagsMap = new HashMap<>(); + // checks if the user is belongs to state and sets a validation flag + setStateValidation(requestMap, userFlagsMap); + userFlagsMap.put(JsonKey.EMAIL_VERIFIED, (Boolean) userMap.get(JsonKey.EMAIL_VERIFIED)); + userFlagsMap.put(JsonKey.PHONE_VERIFIED, (Boolean) userMap.get(JsonKey.PHONE_VERIFIED)); + int userFlagValue = userFlagsToNum(userFlagsMap); + requestMap.put(JsonKey.FLAGS_VALUE, userFlagValue); + Response response = null; + boolean isPasswordUpdated = false; + try { + response = + cassandraOperation.insertRecord( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), requestMap); + isPasswordUpdated = UserUtil.updatePassword(userMap); + + } finally { + if (response == null) { + response = new Response(); + } + response.put(JsonKey.USER_ID, userMap.get(JsonKey.ID)); + if (!isPasswordUpdated) { + response.put(JsonKey.ERROR_MSG, ResponseMessage.Message.ERROR_USER_UPDATE_PASSWORD); + } + } + Response resp = null; + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + Map userRequest = new HashMap<>(); + userRequest.putAll(userMap); + userRequest.put(JsonKey.OPERATION_TYPE, JsonKey.CREATE); + userRequest.put(JsonKey.CALLER_ID, callerId); + resp = saveUserAttributes(userRequest); + } else { + ProjectLogger.log("UserManagementActor:processUserRequest: User creation failure"); + } + // Enable this when you want to send full response of user attributes + Map esResponse = new HashMap<>(); + esResponse.putAll((Map) resp.getResult().get(JsonKey.RESPONSE)); + esResponse.putAll(requestMap); + response.put( + JsonKey.ERRORS, + ((Map) resp.getResult().get(JsonKey.RESPONSE)).get(JsonKey.ERRORS)); + + Response syncResponse = new Response(); + syncResponse.putAll(response.getResult()); + + if (null != resp && userMap.containsKey("sync") && (boolean) userMap.get("sync")) { + Map userDetails = + Util.getUserDetails(userId, getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue())); + Future future = + saveUserToES(userDetails) + .map( + new Mapper() { + @Override + public Response apply(String parameter) { + return syncResponse; + } + }, + context().dispatcher()); + Patterns.pipe(future, getContext().dispatcher()).to(sender()); + } else { + sender().tell(response, self()); + if (null != resp) { + saveUserDetailsToEs(esResponse); + } + } + requestMap.put(JsonKey.PASSWORD, userMap.get(JsonKey.PASSWORD)); + if (StringUtils.isNotBlank(callerId)) { + sendEmailAndSms(requestMap); + } + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + Map rollUp = new HashMap<>(); + rollUp.put("l1", (String) userMap.get(JsonKey.ROOT_ORG_ID)); + reqContext.put(JsonKey.ROLLUP, rollUp); + targetObject = + TelemetryUtil.generateTargetObject( + (String) userMap.get(JsonKey.ID), TelemetryEnvKey.USER, JsonKey.CREATE, null); + TelemetryUtil.generateCorrelatedObject(userId, TelemetryEnvKey.USER, null, correlatedObject); + String signupType = + reqContext.get(JsonKey.SIGNUP_TYPE) != null + ? (String) reqContext.get(JsonKey.SIGNUP_TYPE) + : ""; + String source = + reqContext.get(JsonKey.REQUEST_SOURCE) != null + ? (String) reqContext.get(JsonKey.REQUEST_SOURCE) + : ""; + if (StringUtils.isNotBlank(signupType)) { + TelemetryUtil.generateCorrelatedObject( + signupType, StringUtils.capitalize(JsonKey.SIGNUP_TYPE), null, correlatedObject); + } + if (StringUtils.isNotBlank(source)) { + TelemetryUtil.generateCorrelatedObject( + source, StringUtils.capitalize(JsonKey.REQUEST_SOURCE), null, correlatedObject); + } + TelemetryUtil.telemetryProcessingCall(userMap, targetObject, correlatedObject, reqContext); + } + + private int userFlagsToNum(Map userBooleanMap) { + int userFlagValue = 0; + Set> mapEntry = userBooleanMap.entrySet(); + for (Map.Entry entry : mapEntry) { + if (StringUtils.isNotEmpty(entry.getKey())) { + userFlagValue += UserFlagUtil.getFlagValue(entry.getKey(), entry.getValue()); + } + } + return userFlagValue; + } + + private void setStateValidation( + Map requestMap, Map userBooleanMap) { + String rootOrgId = (String) requestMap.get(JsonKey.ROOT_ORG_ID); + String custodianRootOrgId = getCustodianRootOrgId(); + // if the user is creating for non-custodian(i.e state) the value is set as true else false + userBooleanMap.put(JsonKey.STATE_VALIDATED, !custodianRootOrgId.equals(rootOrgId)); + } + + private Map updatedUserFlagsMap( + Map userMap, Map userDbRecord) { + Map userBooleanMap = new HashMap<>(); + setUserFlagValue(userDbRecord, JsonKey.EMAIL, JsonKey.EMAIL_VERIFIED); + setUserFlagValue(userDbRecord, JsonKey.PHONE, JsonKey.PHONE_VERIFIED); + boolean emailVerified = + (boolean) + (userMap.containsKey(JsonKey.EMAIL_VERIFIED) + ? userMap.get(JsonKey.EMAIL_VERIFIED) + : userDbRecord.get(JsonKey.EMAIL_VERIFIED)); + boolean phoneVerified = + (boolean) + (userMap.containsKey(JsonKey.PHONE_VERIFIED) + ? userMap.get(JsonKey.PHONE_VERIFIED) + : userDbRecord.get(JsonKey.PHONE_VERIFIED)); + // for existing users, it won't contain state-validation + // adding in release-2.4.0 + // userDbRecord- record from es. + if (!userDbRecord.containsKey(JsonKey.STATE_VALIDATED)) { + setStateValidation(userDbRecord, userBooleanMap); + } else { + userBooleanMap.put( + JsonKey.STATE_VALIDATED, (boolean) userDbRecord.get(JsonKey.STATE_VALIDATED)); + } + userBooleanMap.put(JsonKey.EMAIL_VERIFIED, emailVerified); + userBooleanMap.put(JsonKey.PHONE_VERIFIED, phoneVerified); + return userBooleanMap; + } + + /** + * This method set the default value of the user-flag if it is not present in userDbRecord + * + * @param userDbRecord + * @param flagType + * @param verifiedFlagType + * @return + */ + public Map setUserFlagValue( + Map userDbRecord, String flagType, String verifiedFlagType) { + if (userDbRecord.get(flagType) != null + && (userDbRecord.get(verifiedFlagType) == null + || (boolean) userDbRecord.get(verifiedFlagType))) { + userDbRecord.put(verifiedFlagType, true); + } else { + userDbRecord.put(verifiedFlagType, false); + } + return userDbRecord; + } + + private String getCustodianRootOrgId() { + String custodianChannel = + userService.getCustodianChannel(new HashMap<>(), systemSettingActorRef); + return userService.getRootOrgIdFromChannel(custodianChannel); + } + + @SuppressWarnings("unchecked") + private void convertValidatedLocationCodesToIDs(Map userMap) { + if (userMap.containsKey(JsonKey.LOCATION_CODES) + && !CollectionUtils.isEmpty((List) userMap.get(JsonKey.LOCATION_CODES))) { + LocationClientImpl locationClient = new LocationClientImpl(); + List locationIdList = + locationClient.getRelatedLocationIds( + getActorRef(LocationActorOperation.GET_RELATED_LOCATION_IDS.getValue()), + (List) userMap.get(JsonKey.LOCATION_CODES)); + if (locationIdList != null && !locationIdList.isEmpty()) { + userMap.put(JsonKey.LOCATION_IDS, locationIdList); + userMap.remove(JsonKey.LOCATION_CODES); + } else { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + MessageFormat.format( + ResponseCode.invalidParameterValue.getErrorMessage(), + JsonKey.LOCATION_CODES, + userMap.get(JsonKey.LOCATION_CODES))); + } + } + } + + private void sendEmailAndSms(Map userMap) { + // sendEmailAndSms + Request EmailAndSmsRequest = new Request(); + EmailAndSmsRequest.getRequest().putAll(userMap); + EmailAndSmsRequest.setOperation(UserActorOperations.PROCESS_ONBOARDING_MAIL_AND_SMS.getValue()); + tellToAnother(EmailAndSmsRequest); + } + + private void sendResetPasswordLink(Map userMap) { + Request EmailAndSmsRequest = new Request(); + EmailAndSmsRequest.getRequest().putAll(userMap); + EmailAndSmsRequest.setOperation( + UserActorOperations.PROCESS_PASSWORD_RESET_MAIL_AND_SMS.getValue()); + tellToAnother(EmailAndSmsRequest); + } + + private Future saveUserToES(Map completeUserMap) { + + return esUtil.save( + ProjectUtil.EsType.user.getTypeName(), + (String) completeUserMap.get(JsonKey.USER_ID), + completeUserMap); + } + + private void saveUserToKafka(Map completeUserMap) { + ObjectMapper mapper = new ObjectMapper(); + try { + String event = mapper.writeValueAsString(completeUserMap); + // user_events + KafkaClient.send(event, ProjectUtil.getConfigValue("sunbird_user_create_sync_topic")); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + private void saveUserDetailsToEs(Map completeUserMap) { + Request userRequest = new Request(); + userRequest.setOperation(ActorOperations.UPDATE_USER_INFO_ELASTIC.getValue()); + userRequest.getRequest().put(JsonKey.ID, completeUserMap.get(JsonKey.ID)); + ProjectLogger.log( + "UserManagementActor:saveUserDetailsToEs: Trigger sync of user details to ES"); + tellToAnother(userRequest); + } + + private Response saveUserAttributes(Map userMap) { + Request request = new Request(); + request.setOperation(UserActorOperations.SAVE_USER_ATTRIBUTES.getValue()); + request.getRequest().putAll(userMap); + ProjectLogger.log("UserManagementActor:saveUserAttributes"); + try { + return (Response) + interServiceCommunication.getResponse( + getActorRef(UserActorOperations.SAVE_USER_ATTRIBUTES.getValue()), request); + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return null; + } + + private void removeUnwanted(Map reqMap) { + reqMap.remove(JsonKey.ADDRESS); + reqMap.remove(JsonKey.EDUCATION); + reqMap.remove(JsonKey.JOB_PROFILE); + reqMap.remove(JsonKey.ORGANISATION); + reqMap.remove(JsonKey.REGISTERED_ORG); + reqMap.remove(JsonKey.ROOT_ORG); + reqMap.remove(JsonKey.IDENTIFIER); + reqMap.remove(JsonKey.ORGANISATIONS); + reqMap.remove(JsonKey.IS_DELETED); + reqMap.remove(JsonKey.EXTERNAL_ID); + reqMap.remove(JsonKey.ID_TYPE); + reqMap.remove(JsonKey.EXTERNAL_ID_TYPE); + reqMap.remove(JsonKey.PROVIDER); + reqMap.remove(JsonKey.EXTERNAL_ID_PROVIDER); + reqMap.remove(JsonKey.EXTERNAL_IDS); + reqMap.remove(JsonKey.ORGANISATION_ID); + } + + public static void verifyFrameworkId(String hashtagId, List frameworkIdList) { + List frameworks = DataCacheHandler.getHashtagIdFrameworkIdMap().get(hashtagId); + String frameworkId = frameworkIdList.get(0); + if (frameworks != null && frameworks.contains(frameworkId)) { + return; + } else { + Map>> frameworkDetails = getFrameworkDetails(frameworkId); + if (frameworkDetails == null) + throw new ProjectCommonException( + ResponseCode.errorNoFrameworkFound.getErrorCode(), + ResponseCode.errorNoFrameworkFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + } + + public static Map>> getFrameworkDetails(String frameworkId) { + if (DataCacheHandler.getFrameworkCategoriesMap().get(frameworkId) == null) { + handleGetFrameworkDetails(frameworkId); + } + return DataCacheHandler.getFrameworkCategoriesMap().get(frameworkId); + } + + @SuppressWarnings("unchecked") + private static void handleGetFrameworkDetails(String frameworkId) { + Map response = ContentStoreUtil.readFramework(frameworkId); + Map>> frameworkCacheMap = new HashMap<>(); + List supportedfFields = DataCacheHandler.getFrameworkFieldsConfig().get(JsonKey.FIELDS); + Map result = (Map) response.get(JsonKey.RESULT); + if (MapUtils.isNotEmpty(result)) { + Map frameworkDetails = (Map) result.get(JsonKey.FRAMEWORK); + if (MapUtils.isNotEmpty(frameworkDetails)) { + List> frameworkCategories = + (List>) frameworkDetails.get(JsonKey.CATEGORIES); + if (CollectionUtils.isNotEmpty(frameworkCategories)) { + for (Map frameworkCategoriesValue : frameworkCategories) { + String frameworkField = (String) frameworkCategoriesValue.get(JsonKey.CODE); + if (supportedfFields.contains(frameworkField)) { + List> listOfFields = new ArrayList<>(); + List> frameworkTermList = + (List>) frameworkCategoriesValue.get(JsonKey.TERMS); + if (CollectionUtils.isNotEmpty(frameworkTermList)) { + for (Map frameworkTerm : frameworkTermList) { + String id = (String) frameworkTerm.get(JsonKey.IDENTIFIER); + String name = (String) frameworkTerm.get(JsonKey.NAME); + Map writtenValue = new HashMap<>(); + writtenValue.put(JsonKey.ID, id); + writtenValue.put(JsonKey.NAME, name); + listOfFields.add(writtenValue); + } + } + if (StringUtils.isNotBlank(frameworkField) + && CollectionUtils.isNotEmpty(listOfFields)) + frameworkCacheMap.put(frameworkField, listOfFields); + } + if (MapUtils.isNotEmpty(frameworkCacheMap)) + DataCacheHandler.updateFrameworkCategoriesMap(frameworkId, frameworkCacheMap); + } + } + } + } + } + + private void throwRecoveryParamsMatchException(String type, String recoveryType) { + ProjectLogger.log( + "UserManagementActor:throwParamMatchException:".concat(recoveryType + "") + + "should not same as primary ".concat(type + ""), + LoggerEnum.ERROR.name()); + ProjectCommonException.throwClientErrorException( + ResponseCode.recoveryParamsMatchException, + MessageFormat.format( + ResponseCode.recoveryParamsMatchException.getErrorMessage(), recoveryType, type)); + } + + private void validateRecoveryEmailPhone( + Map userDbRecord, Map userReqMap) { + String userPrimaryPhone = (String) userDbRecord.get(JsonKey.PHONE); + String userPrimaryEmail = (String) userDbRecord.get(JsonKey.EMAIL); + String recoveryEmail = (String) userReqMap.get(JsonKey.RECOVERY_EMAIL); + String recoveryPhone = (String) userReqMap.get(JsonKey.RECOVERY_PHONE); + if (StringUtils.isNotBlank(recoveryEmail) + && Matcher.matchIdentifiers(userPrimaryEmail, recoveryEmail)) { + throwRecoveryParamsMatchException(JsonKey.EMAIL, JsonKey.RECOVERY_EMAIL); + } + if (StringUtils.isNotBlank(recoveryPhone) + && Matcher.matchIdentifiers(userPrimaryPhone, recoveryPhone)) { + throwRecoveryParamsMatchException(JsonKey.PHONE, JsonKey.RECOVERY_PHONE); + } + validatePrimaryEmailOrPhone(userDbRecord, userReqMap); + validatePrimaryAndRecoveryKeys(userReqMap); + } + + private void validatePrimaryEmailOrPhone( + Map userDbRecord, Map userReqMap) { + String userPrimaryPhone = (String) userReqMap.get(JsonKey.PHONE); + String userPrimaryEmail = (String) userReqMap.get(JsonKey.EMAIL); + String recoveryEmail = (String) userDbRecord.get(JsonKey.RECOVERY_EMAIL); + String recoveryPhone = (String) userDbRecord.get(JsonKey.RECOVERY_PHONE); + if (StringUtils.isNotBlank(userPrimaryEmail) + && Matcher.matchIdentifiers(userPrimaryEmail, recoveryEmail)) { + throwRecoveryParamsMatchException(JsonKey.EMAIL, JsonKey.RECOVERY_EMAIL); + } + if (StringUtils.isNotBlank(userPrimaryPhone) + && Matcher.matchIdentifiers(userPrimaryPhone, recoveryPhone)) { + throwRecoveryParamsMatchException(JsonKey.PHONE, JsonKey.RECOVERY_PHONE); + } + } + + private void validatePrimaryAndRecoveryKeys(Map userReqMap) { + String userPhone = (String) userReqMap.get(JsonKey.PHONE); + String userEmail = (String) userReqMap.get(JsonKey.EMAIL); + String userRecoveryEmail = (String) userReqMap.get(JsonKey.RECOVERY_EMAIL); + String userRecoveryPhone = (String) userReqMap.get(JsonKey.RECOVERY_PHONE); + if (StringUtils.isNotBlank(userEmail) + && Matcher.matchIdentifiers(userEmail, userRecoveryEmail)) { + throwRecoveryParamsMatchException(JsonKey.EMAIL, JsonKey.RECOVERY_EMAIL); + } + if (StringUtils.isNotBlank(userPhone) + && Matcher.matchIdentifiers(userPhone, userRecoveryPhone)) { + throwRecoveryParamsMatchException(JsonKey.PHONE, JsonKey.RECOVERY_PHONE); + } + } + + /** + * Get managed user list for LUA uuid (JsonKey.ID) and fetch encrypted token for eac user + * from admin utils if the JsonKey.WITH_TOKENS value sent in query param is true + * + * @param request Request + */ + private void getManagedUsers(Request request) { + //LUA uuid/ManagedBy Id + String uuid = (String)request.get(JsonKey.ID); + + boolean withTokens = Boolean.valueOf((String)request.get(JsonKey.WITH_TOKENS)); + + Map searchResult = userClient.searchManagedUser(getActorRef(ActorOperations.COMPOSITE_SEARCH.getValue()), request); + List> userList = (List) searchResult.get(JsonKey.CONTENT); + + List> activeUserList = null; + if(CollectionUtils.isNotEmpty(userList)) { + activeUserList = userList.stream() + .filter(o -> !BooleanUtils.isTrue((Boolean) o.get(JsonKey.IS_DELETED))) + .collect(Collectors.toList()); + } + if(withTokens && CollectionUtils.isNotEmpty(activeUserList)) { + //Fetch encrypted token from admin utils + Map encryptedTokenList = userService.fetchEncryptedToken(uuid, activeUserList); + //encrypted token for each managedUser in respList + userService.appendEncryptedToken(encryptedTokenList, activeUserList); + } + Map responseMap = new HashMap<>(); + if(CollectionUtils.isNotEmpty(activeUserList)) { + responseMap.put(JsonKey.CONTENT, activeUserList); + responseMap.put(JsonKey.COUNT, activeUserList.size()); + }else{ + responseMap.put(JsonKey.CONTENT, new ArrayList>()); + responseMap.put(JsonKey.COUNT, 0); + } + Response response = new Response(); + response.put(JsonKey.RESPONSE, responseMap); + sender().tell(response, self()); + } + +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserMergeActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserMergeActor.java new file mode 100644 index 0000000000..22779c0d56 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserMergeActor.java @@ -0,0 +1,318 @@ +package org.sunbird.user.actors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.typesafe.config.Config; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.datasecurity.OneWayHashing; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.common.util.ConfigUtil; +import org.sunbird.kafka.client.KafkaClient; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.models.systemsetting.SystemSetting; +import org.sunbird.models.user.User; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.telemetry.dto.Actor; +import org.sunbird.telemetry.dto.Context; +import org.sunbird.telemetry.dto.Target; +import org.sunbird.telemetry.dto.Telemetry; +import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.user.dao.UserDao; +import org.sunbird.user.dao.impl.UserDaoImpl; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; +import org.sunbird.user.util.KafkaConfigConstants; + +@ActorConfig( + tasks = {"mergeUser"}, + asyncTasks = {} +) +public class UserMergeActor extends UserBaseActor { + String topic = null; + Producer producer = null; + private UserService userService = UserServiceImpl.getInstance(); + private SSOManager keyCloakService = SSOServiceFactory.getInstance(); + private SystemSettingClient systemSettingClient = SystemSettingClientImpl.getInstance(); + + @Override + public void onReceive(Request userRequest) throws Throwable { + Util.initializeContext(userRequest, TelemetryEnvKey.USER); + if (producer == null) { + initKafkaClient(); + } + updateUserMergeDetails(userRequest); + } + + /** + * Main method for calling user-course service, merge user details and then call user-cert service + * + * @param userRequest + * @throws IOException + */ + private void updateUserMergeDetails(Request userRequest) throws IOException { + ProjectLogger.log("UserMergeActor:updateUserMergeDetails: starts : ", LoggerEnum.DEBUG.name()); + Response response = new Response(); + Map mergeeDBMap = new HashMap(); + HashMap requestMap = (HashMap) userRequest.getRequest(); + Map userCertMap = (Map) requestMap.clone(); + Map headers = (Map) userRequest.getContext().get(JsonKey.HEADER); + String mergeeId = (String) requestMap.get(JsonKey.FROM_ACCOUNT_ID); + String mergerId = (String) requestMap.get(JsonKey.TO_ACCOUNT_ID); + // validating tokens + checkTokenDetails(headers, mergeeId, mergerId); + Map telemetryMap = (HashMap) requestMap.clone(); + User mergee = userService.getUserById(mergeeId); + User merger = userService.getUserById(mergerId); + String custodianId = getCustodianValue(); + if ((!custodianId.equals(mergee.getRootOrgId())) || custodianId.equals(merger.getRootOrgId())) { + ProjectLogger.log( + "UserMergeActor:updateUserMergeDetails: Either custodian id is not matching with mergeeid root-org" + + mergeeId + + "or matching with mergerid root-org" + + mergerId, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.accountNotFound.getErrorCode(), + ResponseCode.accountNotFound.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + if (!mergee.getIsDeleted()) { + prepareMergeeAccountData(mergee, mergeeDBMap); + userRequest.put(JsonKey.USER_MERGEE_ACCOUNT, mergeeDBMap); + UserDao userDao = UserDaoImpl.getInstance(); + Response mergeeResponse = userDao.updateUser(mergeeDBMap); + String mergeeResponseStr = (String) mergeeResponse.get(JsonKey.RESPONSE); + ProjectLogger.log( + "UserMergeActor: updateUserMergeDetails: mergeeResponseStr = " + mergeeResponseStr, + LoggerEnum.INFO.name()); + Map result = new HashMap(); + result.put(JsonKey.STATUS, JsonKey.SUCCESS); + response.put(JsonKey.RESULT, result); + sender().tell(response, self()); + + // update user-course-cert details + mergeCertCourseDetails(mergee, merger); + + // update mergee details in ES + mergeUserDetailsToEs(userRequest); + + // deleting User From KeyCloak + CompletableFuture.supplyAsync( + () -> { + return deactivateMergeeFromKC((String) mergeeDBMap.get(JsonKey.ID)); + }) + .thenApply( + status -> { + ProjectLogger.log( + "UserMergeActor: updateUserMergeDetails: user deleted from KeyCloak: " + status, + LoggerEnum.INFO.name()); + return null; + }); + + // create telemetry event for merge + triggerUserMergeTelemetry(telemetryMap, merger, userRequest.getContext()); + + } else { + ProjectLogger.log( + "UserMergeActor:updateUserMergeDetails: User mergee is not exist : " + mergeeId, + LoggerEnum.ERROR.name()); + throw new ProjectCommonException( + ResponseCode.invalidIdentifier.getErrorCode(), + ProjectUtil.formatMessage( + ResponseMessage.Message.INVALID_PARAMETER_VALUE, mergeeId, JsonKey.FROM_ACCOUNT_ID), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + /** + * This method returns system custodian value + * + * @return rootCustodianValue + */ + private String getCustodianValue() { + String custodianId = null; + try { + Map configSettingMap = DataCacheHandler.getConfigSettings(); + custodianId = configSettingMap.get(JsonKey.CUSTODIAN_ORG_ID); + if (custodianId == null || custodianId.isEmpty()) { + SystemSetting custodianIdSetting = + systemSettingClient.getSystemSettingByField( + getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()), + JsonKey.CUSTODIAN_ORG_ID); + if (custodianIdSetting != null) { + configSettingMap.put(custodianIdSetting.getId(), custodianIdSetting.getValue()); + custodianId = custodianIdSetting.getValue(); + } + } + } catch (Exception e) { + ProjectLogger.log( + "UserMergeActor:updateTncInfo: Exception occurred while getting system setting for" + + JsonKey.CUSTODIAN_ORG_ID + + e.getMessage(), + LoggerEnum.ERROR.name()); + } + return custodianId; + } + + /** + * This method creates Kafka topic for user-cert + * + * @param mergee + * @param merger + * @throws IOException + */ + private void mergeCertCourseDetails(User mergee, User merger) throws IOException { + String content = null; + Telemetry userCertMergeRequest = createAccountMergeTopicData(mergee, merger); + ObjectMapper objectMapper = new ObjectMapper(); + content = objectMapper.writeValueAsString(userCertMergeRequest); + ProjectLogger.log( + "UserMergeActor:mergeCertCourseDetails: Kafka producer topic::" + content, + LoggerEnum.INFO.name()); + ProducerRecord record = new ProducerRecord<>(topic, content); + if (producer != null) { + producer.send(record); + } else { + ProjectLogger.log( + "UserMergeActor:mergeCertCourseDetails: Kafka producer is not initialised.", + LoggerEnum.INFO.name()); + } + } + + private Telemetry createAccountMergeTopicData(User mergee, User merger) { + Map edata = new HashMap<>(); + Telemetry mergeUserEvent = new Telemetry(); + Actor actor = new Actor(); + actor.setId(JsonKey.TELEMETRY_ACTOR_USER_MERGE_ID); + actor.setType(JsonKey.SYSTEM); + mergeUserEvent.setActor(actor); + mergeUserEvent.setEid(JsonKey.BE_JOB_REQUEST); + edata.put(JsonKey.ACTION, JsonKey.TELEMETRY_EDATA_USER_MERGE_ACTION); + edata.put(JsonKey.FROM_ACCOUNT_ID, mergee.getId()); + edata.put(JsonKey.TO_ACCOUNT_ID, merger.getId()); + edata.put(JsonKey.ROOT_ORG_ID, merger.getRootOrgId()); + edata.put(JsonKey.ITERATION, 1); + mergeUserEvent.setEdata(edata); + Context context = new Context(); + org.sunbird.telemetry.dto.Producer dataProducer = new org.sunbird.telemetry.dto.Producer(); + dataProducer.setVer("1.0"); + dataProducer.setId(JsonKey.TELEMETRY_PRODUCER_USER_MERGE_ID); + context.setPdata(dataProducer); + mergeUserEvent.setContext(context); + Target target = new Target(); + target.setId(OneWayHashing.encryptVal(mergee.getId() + "_" + merger.getId())); + target.setType(JsonKey.TELEMETRY_TARGET_USER_MERGE_TYPE); + mergeUserEvent.setObject(target); + return mergeUserEvent; + } + + private void triggerUserMergeTelemetry( + Map telemetryMap, User merger, Map context) { + ProjectLogger.log( + "UserMergeActor:triggerUserMergeTelemetry: generating telemetry event for merge"); + Map targetObject = null; + List> correlatedObject = new ArrayList<>(); + Map rollUp = new HashMap<>(); + rollUp.put("l1", merger.getRootOrgId()); + context.put(JsonKey.ROLLUP, rollUp); + targetObject = + TelemetryUtil.generateTargetObject( + (String) telemetryMap.get(JsonKey.FROM_ACCOUNT_ID), + TelemetryEnvKey.USER, + JsonKey.MERGE_USER, + null); + TelemetryUtil.generateCorrelatedObject( + (String) telemetryMap.get(JsonKey.FROM_ACCOUNT_ID), + JsonKey.FROM_ACCOUNT_ID, + null, + correlatedObject); + TelemetryUtil.generateCorrelatedObject( + (String) telemetryMap.get(JsonKey.TO_ACCOUNT_ID), + JsonKey.TO_ACCOUNT_ID, + null, + correlatedObject); + telemetryMap.remove(JsonKey.ID); + telemetryMap.remove(JsonKey.USER_ID); + TelemetryUtil.telemetryProcessingCall(telemetryMap, targetObject, correlatedObject, context); + } + + private void mergeUserDetailsToEs(Request userRequest) { + userRequest.setOperation(ActorOperations.MERGE_USER_TO_ELASTIC.getValue()); + ProjectLogger.log( + "UserMergeActor: mergeUserDetailsToEs: Trigger sync of user details to ES for user id" + + userRequest.getRequest().get(JsonKey.FROM_ACCOUNT_ID), + LoggerEnum.INFO.name()); + tellToAnother(userRequest); + } + + private void prepareMergeeAccountData(User mergee, Map mergeeDBMap) { + mergeeDBMap.put(JsonKey.STATUS, 0); + mergeeDBMap.put(JsonKey.IS_DELETED, true); + mergeeDBMap.put(JsonKey.EMAIL, null); + mergeeDBMap.put(JsonKey.PHONE, null); + mergeeDBMap.put(JsonKey.USERNAME, null); + mergeeDBMap.put(JsonKey.PREV_USED_EMAIL, mergee.getEmail()); + mergeeDBMap.put(JsonKey.PREV_USED_PHONE, mergee.getPhone()); + mergeeDBMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + mergeeDBMap.put(JsonKey.ID, mergee.getId()); + } + + private void checkTokenDetails(Map headers, String mergeeId, String mergerId) { + String userAuthToken = (String) headers.get(JsonKey.X_AUTHENTICATED_USER_TOKEN); + String sourceUserAuthToken = (String) headers.get(JsonKey.X_SOURCE_USER_TOKEN); + String subDomainUrl = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_SUBDOMAIN_KEYCLOAK_BASE_URL); + ProjectLogger.log( + "UserMergeActor:checkTokenDetails subdomain url value " + subDomainUrl, + LoggerEnum.INFO.name()); + String userId = keyCloakService.verifyToken(userAuthToken); + // Since source token is generated from subdomain , so verification also need with + // same subdomain. + String sourceUserId = keyCloakService.verifyToken(sourceUserAuthToken, subDomainUrl); + if (!(mergeeId.equals(sourceUserId) && mergerId.equals(userId))) { + throw new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ProjectUtil.formatMessage(ResponseMessage.Message.UNAUTHORIZED_USER, mergeeId), + ResponseCode.UNAUTHORIZED.getResponseCode()); + } + } + + /** Initialises Kafka producer required for dispatching messages on Kafka. */ + private void initKafkaClient() { + ProjectLogger.log("UserMergeActor:initKafkaClient: starts = ", LoggerEnum.INFO.name()); + Config config = ConfigUtil.getConfig(); + topic = config.getString(KafkaConfigConstants.SUNBIRD_USER_CERT_KAFKA_TOPIC); + ProjectLogger.log("UserMergeActor:initKafkaClient: topic = " + topic, LoggerEnum.INFO.name()); + try { + producer = KafkaClient.getProducer(); + } catch (Exception e) { + ProjectLogger.log( + "UserMergeActor:initKafkaClient: An exception occurred." + e, LoggerEnum.ERROR.name()); + } + } + + private String deactivateMergeeFromKC(String userId) { + Map userMap = new HashMap<>(); + userMap.put(JsonKey.USER_ID, userId); + ProjectLogger.log( + "UserMergeActor:deactivateMergeeFromKC: request Got to deactivate mergee account from KC:" + + userMap, + LoggerEnum.INFO.name()); + return keyCloakService.removeUser(userMap); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserOnboardingNotificationActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserOnboardingNotificationActor.java new file mode 100644 index 0000000000..b5bd83b994 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserOnboardingNotificationActor.java @@ -0,0 +1,71 @@ +package org.sunbird.user.actors; + +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.util.KeycloakRequiredActionLinkUtil; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.user.util.UserActorOperations; + +@ActorConfig( + tasks = {}, + asyncTasks = {"processOnBoardingMailAndSms", "processPasswordResetMailAndSms"} +) +public class UserOnboardingNotificationActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + if (UserActorOperations.PROCESS_ONBOARDING_MAIL_AND_SMS + .getValue() + .equalsIgnoreCase(request.getOperation())) { + sendEmailAndSms(request); + } else { + onReceiveUnsupportedOperation("ProcessOnBoardingMailAndSmsActor"); + } + } + + private void sendEmailAndSms(Request request) { + Map requestMap = request.getRequest(); + // generate required action link and shorten the url + UserUtility.decryptUserData(requestMap); + requestMap.put(JsonKey.USERNAME, requestMap.get(JsonKey.USERNAME)); + requestMap.put(JsonKey.REDIRECT_URI, Util.getSunbirdWebUrlPerTenent(requestMap)); + Util.getUserRequiredActionLink(requestMap); + if (request + .getOperation() + .equals(UserActorOperations.PROCESS_ONBOARDING_MAIL_AND_SMS.getValue())) { + // user created successfully send the onboarding mail + Request welcomeMailReqObj = Util.sendOnboardingMail(requestMap); + if (null != welcomeMailReqObj) { + tellToAnother(welcomeMailReqObj); + } + } else if (request + .getOperation() + .equals(UserActorOperations.PROCESS_PASSWORD_RESET_MAIL_AND_SMS.getValue())) { + Request resetMailReqObj = Util.sendResetPassMail(requestMap); + if (null != resetMailReqObj) { + tellToAnother(resetMailReqObj); + } + } + + if (StringUtils.isNotBlank((String) requestMap.get(JsonKey.PHONE))) { + Util.sendSMS(requestMap); + } + SSOManager ssoManager = SSOServiceFactory.getInstance(); + if (StringUtils.isBlank((String) requestMap.get(JsonKey.PASSWORD))) { + ssoManager.setRequiredAction( + (String) requestMap.get(JsonKey.USER_ID), KeycloakRequiredActionLinkUtil.UPDATE_PASSWORD); + } + + if (StringUtils.isNotBlank((String) requestMap.get(JsonKey.EMAIL))) { + ssoManager.setRequiredAction( + (String) requestMap.get(JsonKey.USER_ID), KeycloakRequiredActionLinkUtil.VERIFY_EMAIL); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserOrgManagementActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserOrgManagementActor.java new file mode 100644 index 0000000000..bf809c2574 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserOrgManagementActor.java @@ -0,0 +1,89 @@ +package org.sunbird.user.actors; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.learner.util.Util; + +@ActorConfig( + tasks = {"insertUserOrgDetails", "updateUserOrgDetails"}, + asyncTasks = {"insertUserOrgDetails", "updateUserOrgDetails"} +) +public class UserOrgManagementActor extends BaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + switch (operation) { + case "insertUserOrgDetails": + insertUserOrgDetails(request); + break; + case "updateUserOrgDetails": + updateUserOrgDetails(request); + break; + + default: + onReceiveUnsupportedOperation("UserOrgManagementActor"); + } + } + + private void insertUserOrgDetails(Request request) { + Map requestMap = request.getRequest(); + String callerId = (String) requestMap.get(JsonKey.CALLER_ID); + // Register user to given orgId(not root orgId) + String organisationId = (String) requestMap.get(JsonKey.ORGANISATION_ID); + if (StringUtils.isNotBlank(organisationId)) { + String hashTagId = + Util.getHashTagIdFromOrgId((String) requestMap.get(JsonKey.ORGANISATION_ID)); + requestMap.put(JsonKey.HASHTAGID, hashTagId); + if (StringUtils.isBlank(callerId)) { + addPublicRole(requestMap); + } + Util.registerUserToOrg(requestMap); + } + if ((StringUtils.isNotBlank(organisationId) + && StringUtils.isNotBlank((String) requestMap.get(JsonKey.ROOT_ORG_ID)) + && !organisationId.equalsIgnoreCase((String) requestMap.get(JsonKey.ROOT_ORG_ID))) + || StringUtils.isBlank(organisationId)) { + // Add user to root org + addPublicRole(requestMap); + requestMap.put(JsonKey.ORGANISATION_ID, requestMap.get(JsonKey.ROOT_ORG_ID)); + String hashTagId = Util.getHashTagIdFromOrgId((String) requestMap.get(JsonKey.ROOT_ORG_ID)); + requestMap.put(JsonKey.HASHTAGID, hashTagId); + Util.registerUserToOrg(requestMap); + } + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + } + + private void addPublicRole(Map requestMap) { + List roles = new ArrayList<>(); + roles.add(ProjectUtil.UserRole.PUBLIC.getValue()); + requestMap.put(JsonKey.ROLES, roles); + } + + private void updateUserOrgDetails(Request request) { + Map requestMap = request.getRequest(); + String organisationId = (String) requestMap.get(JsonKey.ORGANISATION_ID); + if (StringUtils.isNotBlank(organisationId)) { + Util.upsertUserOrgData(requestMap); + } + if ((StringUtils.isNotBlank(organisationId) + && !organisationId.equalsIgnoreCase((String) requestMap.get(JsonKey.ROOT_ORG_ID))) + || StringUtils.isBlank(organisationId)) { + addPublicRole(requestMap); + Util.upsertUserOrgData(requestMap); + } + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileActor.java new file mode 100644 index 0000000000..f94472c113 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileActor.java @@ -0,0 +1,239 @@ +package org.sunbird.user.actors; + +import akka.actor.ActorRef; +import com.typesafe.config.Config; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.SocialMediaType; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.user.dao.UserDao; +import org.sunbird.user.dao.impl.UserDaoImpl; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; + +@ActorConfig( + tasks = {"profileVisibility", "getMediaTypes"}, + asyncTasks = {} +) +public class UserProfileActor extends UserBaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + switch (operation) { + case "getMediaTypes": + getMediaTypes(); + break; + case "profileVisibility": + setProfileVisibility(request); + break; + default: + onReceiveUnsupportedMessage("UserProfileActor"); + break; + } + } + + private void getMediaTypes() { + Response response = SocialMediaType.getMediaTypeFromDB(); + sender().tell(response, self()); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void setProfileVisibility(Request actorMessage) { + Map map = (Map) actorMessage.getRequest(); + + String userId = (String) map.get(JsonKey.USER_ID); + List privateList = (List) map.get(JsonKey.PRIVATE); + List publicList = (List) map.get(JsonKey.PUBLIC); + + validateFields(privateList, JsonKey.PUBLIC_FIELDS); + validateFields(publicList, JsonKey.PRIVATE_FIELDS); + UserService userService = UserServiceImpl.getInstance(); + Map esPublicUserProfile = userService.esGetPublicUserProfileById(userId); + Map esPrivateUserProfile = userService.esGetPrivateUserProfileById(userId); + + updateUserProfile(publicList, privateList, esPublicUserProfile, esPrivateUserProfile); + + updateProfileVisibility(userId, publicList, privateList, esPublicUserProfile); + + userService.syncUserProfile(userId, esPublicUserProfile, esPrivateUserProfile); + + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + sender().tell(response, self()); + + generateTelemetryEvent(null, userId, "profileVisibility", actorMessage.getContext()); + } + + private void validateFields(List values, String listType) { + // Remove duplicate entries from the list + // Visibility of permanent fields cannot be changed + if (CollectionUtils.isNotEmpty(values)) { + List distValues = values.stream().distinct().collect(Collectors.toList()); + validateProfileVisibilityFields(distValues, listType, getSystemSettingActorRef()); + } + } + + public void validateProfileVisibilityFields( + List fieldList, String fieldTypeKey, ActorRef actorRef) { + String conflictingFieldTypeKey = + JsonKey.PUBLIC_FIELDS.equalsIgnoreCase(fieldTypeKey) ? JsonKey.PRIVATE : JsonKey.PUBLIC; + + Config userProfileConfig = Util.getUserProfileConfig(actorRef); + + List fields = userProfileConfig.getStringList(fieldTypeKey); + List fieldsCopy = new ArrayList(fields); + fieldsCopy.retainAll(fieldList); + + if (!fieldsCopy.isEmpty()) { + ProjectCommonException.throwClientErrorException( + ResponseCode.invalidParameterValue, + ProjectUtil.formatMessage( + ResponseCode.invalidParameterValue.getErrorMessage(), + fieldsCopy.toString(), + StringFormatter.joinByDot(JsonKey.PROFILE_VISIBILITY, conflictingFieldTypeKey))); + } + } + + private void updateUserProfile( + List publicList, + List privateList, + Map esPublicUserProfile, + Map esPrivateUserProfile) { + Map privateDataMap = null; + if (CollectionUtils.isNotEmpty(privateList)) { + privateDataMap = getPrivateFieldMap(privateList, esPublicUserProfile, esPrivateUserProfile); + } + if (privateDataMap != null && privateDataMap.size() > 0) { + resetPrivateFieldsInPublicUserProfile(privateDataMap, esPublicUserProfile); + } + + addRemovedPrivateFieldsInPublicUserProfile( + publicList, esPublicUserProfile, esPrivateUserProfile); + } + + private Map getPrivateFieldMap( + List privateFieldList, Map data, Map oldPrivateData) { + Map privateFieldMap = createPrivateFieldMap(data, privateFieldList); + privateFieldMap.putAll(oldPrivateData); + return privateFieldMap; + } + + private Map resetPrivateFieldsInPublicUserProfile( + Map privateDataMap, Map esPublicUserProfile) { + for (String field : privateDataMap.keySet()) { + if ("dob".equalsIgnoreCase(field)) { + esPublicUserProfile.put(field, null); + } else if (privateDataMap.get(field) instanceof List) { + esPublicUserProfile.put(field, new ArrayList<>()); + } else if (privateDataMap.get(field) instanceof Map) { + esPublicUserProfile.put(field, new HashMap<>()); + } else if (privateDataMap.get(field) instanceof String) { + esPublicUserProfile.put(field, ""); + } else { + esPublicUserProfile.put(field, null); + } + } + return esPublicUserProfile; + } + + private void addRemovedPrivateFieldsInPublicUserProfile( + List publicList, + Map esPublicUserProfile, + Map esPrivateUserProfile) { + if (CollectionUtils.isNotEmpty(publicList)) { + for (String field : publicList) { + if (esPrivateUserProfile.containsKey(field)) { + esPublicUserProfile.put(field, esPrivateUserProfile.get(field)); + esPrivateUserProfile.remove(field); + } else { + ProjectLogger.log( + "UserProfileActor:addRemovedPrivateFieldsInPublicUserProfile: private index does not have field = " + + field); + } + } + } + } + + private void updateProfileVisibility( + String userId, + List publicList, + List privateList, + Map esPublicUserProfile) { + Map profileVisibilityMap = + (Map) esPublicUserProfile.get(JsonKey.PROFILE_VISIBILITY); + + if (null == profileVisibilityMap) { + profileVisibilityMap = new HashMap<>(); + } + + prepareProfileVisibilityMap(profileVisibilityMap, publicList, JsonKey.PUBLIC); + prepareProfileVisibilityMap(profileVisibilityMap, privateList, JsonKey.PRIVATE); + + if (profileVisibilityMap.size() > 0) { + saveUserProfileVisibility(userId, profileVisibilityMap); + esPublicUserProfile.put(JsonKey.PROFILE_VISIBILITY, profileVisibilityMap); + } + } + + private void prepareProfileVisibilityMap( + Map profileVisibilityMap, List list, String value) { + if (list != null) { + for (String key : list) { + profileVisibilityMap.put(key, value); + } + } + } + + private void saveUserProfileVisibility(String userId, Map privateFieldMap) { + User user = new User(); + user.setId(userId); + user.setProfileVisibility(privateFieldMap); + UserDao userDao = UserDaoImpl.getInstance(); + Response response = userDao.updateUser(user); + + String responseStr = (String) response.get(JsonKey.RESPONSE); + ProjectLogger.log("UserProfileActor:saveUserProfileVisibility: responseStr = " + responseStr); + } + + private Map createPrivateFieldMap(Map map, List fields) { + Map privateMap = new HashMap<>(); + if (fields != null && !fields.isEmpty()) { + for (String field : fields) { + // If field is nested (e.g. address.someField) then the parent key is marked as private + if (field.contains(JsonKey.ADDRESS + ".")) { + privateMap.put(JsonKey.ADDRESS, map.get(JsonKey.ADDRESS)); + } else if (field.contains(JsonKey.EDUCATION + ".")) { + privateMap.put(JsonKey.EDUCATION, map.get(JsonKey.EDUCATION)); + } else if (field.contains(JsonKey.JOB_PROFILE + ".")) { + privateMap.put(JsonKey.JOB_PROFILE, map.get(JsonKey.JOB_PROFILE)); + } else if (field.contains(JsonKey.SKILLS + ".")) { + privateMap.put(JsonKey.SKILLS, map.get(JsonKey.SKILLS)); + } else if (field.contains(JsonKey.BADGE_ASSERTIONS + ".")) { + privateMap.put(JsonKey.BADGE_ASSERTIONS, map.get(JsonKey.BADGE_ASSERTIONS)); + } else { + if (!map.containsKey(field)) { + throw new ProjectCommonException( + ResponseCode.InvalidColumnError.getErrorCode(), + ResponseCode.InvalidColumnError.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + privateMap.put(field, map.get(field)); + } + } + } + return privateMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileReadActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileReadActor.java new file mode 100644 index 0000000000..5fa1197367 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileReadActor.java @@ -0,0 +1,1109 @@ +package org.sunbird.user.actors; + +import static org.sunbird.learner.util.Util.isNotNull; + +import akka.actor.ActorRef; +import akka.dispatch.Mapper; +import akka.pattern.Patterns; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.text.MessageFormat; +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.user.dao.UserDao; +import org.sunbird.user.dao.impl.UserDaoImpl; +import org.sunbird.user.dao.impl.UserExternalIdentityDaoImpl; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; +import org.sunbird.user.util.UserUtil; +import scala.Tuple2; +import scala.concurrent.Await; +import scala.concurrent.Future; + +@ActorConfig( + tasks = { + "getUserDetailsByLoginId", + "getUserProfile", + "getUserProfileV2", + "getUserByKey", + "checkUserExistence" + }, + asyncTasks = {} +) +public class UserProfileReadActor extends BaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + private Util.DbInfo userOrgDbInfo = Util.dbInfoMap.get(JsonKey.USER_ORG_DB); + private Util.DbInfo geoLocationDbInfo = Util.dbInfoMap.get(JsonKey.GEO_LOCATION_DB); + private ActorRef systemSettingActorRef = null; + private UserExternalIdentityDaoImpl userExternalIdentityDao = new UserExternalIdentityDaoImpl(); + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + private UserService userService = UserServiceImpl.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + if (systemSettingActorRef == null) { + systemSettingActorRef = getActorRef(ActorOperations.GET_SYSTEM_SETTING.getValue()); + } + String operation = request.getOperation(); + switch (operation) { + case "getUserProfile": + getUserProfile(request); + break; + case "getUserProfileV2": + getUserProfileV2(request); + break; + case "getUserDetailsByLoginId": + getUserDetailsByLoginId(request); + break; + case "getUserByKey": + getKey(request); + break; + case "checkUserExistence": + checkUserExistence(request); + break; + default: + onReceiveUnsupportedOperation("UserProfileReadActor"); + } + } + + /** + * Method to get user profile (version 1). + * + * @param actorMessage Request containing user ID + */ + private void getUserProfile(Request actorMessage) { + Response response = getUserProfileData(actorMessage); + sender().tell(response, self()); + } + + private Response getUserProfileData(Request actorMessage) { + Map userMap = actorMessage.getRequest(); + String id = (String) userMap.get(JsonKey.USER_ID); + String userId; + String provider = (String) actorMessage.getContext().get(JsonKey.PROVIDER); + String idType = (String) actorMessage.getContext().get(JsonKey.ID_TYPE); + boolean withTokens = + Boolean.valueOf((String) actorMessage.getContext().get(JsonKey.WITH_TOKENS)); + String managedToken = (String) actorMessage.getContext().get(JsonKey.MANAGED_TOKEN); + boolean showMaskedData = false; + if (!StringUtils.isEmpty(provider)) { + if (StringUtils.isEmpty(idType)) { + userId = null; + ProjectCommonException.throwClientErrorException( + ResponseCode.mandatoryParamsMissing, + MessageFormat.format( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.ID_TYPE)); + } else { + userId = userExternalIdentityDao.getUserIdByExternalId(id, provider, idType); + if (userId == null) { + ProjectCommonException.throwClientErrorException( + ResponseCode.externalIdNotFound, + ProjectUtil.formatMessage( + ResponseCode.externalIdNotFound.getErrorMessage(), id, idType, provider)); + } + showMaskedData = true; + } + + } else { + userId = id; + showMaskedData = false; + } + boolean isPrivate = (boolean) actorMessage.getContext().get(JsonKey.PRIVATE); + Map result = null; + if (!isPrivate) { + Future> resultF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId); + try { + Object object = Await.result(resultF, ElasticSearchHelper.timeout.duration()); + if (object != null) { + result = (Map) object; + } + } catch (Exception e) { + ProjectLogger.log( + String.format( + "%s:%s:User not found with provided id == %s and error %s", + this.getClass().getSimpleName(), "getUserProfileData", e.getMessage()), + LoggerEnum.ERROR.name()); + } + } else { + UserDao userDao = new UserDaoImpl(); + User foundUser = userDao.getUserById(userId); + if (foundUser == null) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + result = objectMapper.convertValue(foundUser, Map.class); + result.put(JsonKey.ORGANISATIONS, Util.getUserOrgDetails(userId)); + } + // check user found or not + if (result == null || result.size() == 0) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + // check whether is_deletd true or false + if (ProjectUtil.isNotNull(result) + && result.containsKey(JsonKey.IS_DELETED) + && ProjectUtil.isNotNull(result.get(JsonKey.IS_DELETED)) + && (Boolean) result.get(JsonKey.IS_DELETED)) { + ProjectCommonException.throwClientErrorException(ResponseCode.userAccountlocked); + } + Future> esResultF = fetchRootAndRegisterOrganisation(result); + Map esResult = + (Map) ElasticSearchHelper.getResponseFromFuture(esResultF); + result.put(JsonKey.ROOT_ORG, esResult); + // having check for removing private filed from user , if call user and response + // user data id is not same. + String requestedById = + (String) actorMessage.getContext().getOrDefault(JsonKey.REQUESTED_BY, ""); + String managedForId = (String) actorMessage.getContext().getOrDefault(JsonKey.MANAGED_FOR, ""); + String managedBy = (String) result.get(JsonKey.MANAGED_BY); + ProjectLogger.log( + "requested By and requested user id == " + + requestedById + + " " + + (String) userId + + " managedForId= " + + managedForId + + " managedBy " + + managedBy + + " showMaskedData= " + + showMaskedData, + LoggerEnum.INFO); + if (StringUtils.isNotEmpty(managedBy) && !managedBy.equals(requestedById)) { + ProjectCommonException.throwUnauthorizedErrorException(); + } + try { + if (!((userId).equalsIgnoreCase(requestedById) || userId.equalsIgnoreCase(managedForId)) + && !showMaskedData) { + result = removeUserPrivateField(result); + } else { + ProjectLogger.log( + "Response with externalIds and complete profile details", LoggerEnum.INFO); + // These values are set to ensure backward compatibility post introduction of global + // settings in user profile visibility + setCompleteProfileVisibilityMap(result); + setDefaultUserProfileVisibility(result); + + // If the user requests his data then we are fetching the private data from + // userprofilevisibility index + // and merge it with user index data + Future> privateResultF = + esUtil.getDataByIdentifier( + ProjectUtil.EsType.userprofilevisibility.getTypeName(), userId); + Map privateResult = + (Map) ElasticSearchHelper.getResponseFromFuture(privateResultF); + // fetch user external identity + List> dbResExternalIds = fetchUserExternalIdentity(userId); + result.put(JsonKey.EXTERNAL_IDS, dbResExternalIds); + result.putAll(privateResult); + } + } catch (Exception e) { + ProjectLogger.log( + "Error in UserProfileReadActor: getUserProfileData: error message " + e.getMessage(), + LoggerEnum.INFO); + ProjectCommonException.throwServerErrorException(ResponseCode.userDataEncryptionError); + } + if (null != actorMessage.getContext().get(JsonKey.FIELDS)) { + String requestFields = (String) actorMessage.getContext().get(JsonKey.FIELDS); + addExtraFieldsInUserProfileResponse(result, requestFields, userId); + } else { + result.remove(JsonKey.MISSING_FIELDS); + result.remove(JsonKey.COMPLETENESS); + } + + Response response = new Response(); + + if (null != result) { + UserUtility.decryptUserDataFrmES(result); + updateSkillWithEndoresmentCount(result); + updateTnc(result); + // loginId is used internally for checking the duplicate user + result.remove(JsonKey.LOGIN_ID); + result.remove(JsonKey.ENC_EMAIL); + result.remove(JsonKey.ENC_PHONE); + // String username = ssoManager.getUsernameById(userId); + // result.put(JsonKey.USERNAME, username); + + if (withTokens && StringUtils.isNotEmpty(managedBy) && MapUtils.isNotEmpty(result)) { + if (StringUtils.isEmpty(managedToken)) { + ProjectLogger.log( + "UserProfileReadActor: getUserProfileData: calling token generation for: " + userId, + LoggerEnum.INFO.name()); + List> userList = new ArrayList>(); + userList.add(result); + // Fetch encrypted token from admin utils + Map encryptedTokenList = + userService.fetchEncryptedToken(managedBy, userList); + // encrypted token for each managedUser in respList + userService.appendEncryptedToken(encryptedTokenList, userList); + result = userList.get(0); + } else { + result.put(JsonKey.MANAGED_TOKEN, managedToken); + } + } + + response.put(JsonKey.RESPONSE, result); + } else { + result = new HashMap<>(); + response.put(JsonKey.RESPONSE, result); + } + return response; + } + + @SuppressWarnings("unchecked") + private List> fetchUserExternalIdentity(String userId) { + Response response = + cassandraOperation.getRecordsByIndexedProperty( + JsonKey.SUNBIRD, JsonKey.USR_EXT_IDNT_TABLE, JsonKey.USER_ID, userId); + List> dbResExternalIds = new ArrayList<>(); + if (null != response && null != response.getResult()) { + dbResExternalIds = (List>) response.getResult().get(JsonKey.RESPONSE); + if (null != dbResExternalIds) { + dbResExternalIds + .stream() + .forEach( + s -> { + if (StringUtils.isNotBlank(s.get(JsonKey.ORIGINAL_EXTERNAL_ID)) + && StringUtils.isNotBlank(s.get(JsonKey.ORIGINAL_ID_TYPE)) + && StringUtils.isNotBlank(s.get(JsonKey.ORIGINAL_PROVIDER))) { + s.put(JsonKey.ID, s.get(JsonKey.ORIGINAL_EXTERNAL_ID)); + s.put(JsonKey.ID_TYPE, s.get(JsonKey.ORIGINAL_ID_TYPE)); + s.put(JsonKey.PROVIDER, s.get(JsonKey.ORIGINAL_PROVIDER)); + + } else { + s.put(JsonKey.ID, s.get(JsonKey.EXTERNAL_ID)); + } + + s.remove(JsonKey.EXTERNAL_ID); + s.remove(JsonKey.ORIGINAL_EXTERNAL_ID); + s.remove(JsonKey.ORIGINAL_ID_TYPE); + s.remove(JsonKey.ORIGINAL_PROVIDER); + s.remove(JsonKey.CREATED_BY); + s.remove(JsonKey.LAST_UPDATED_BY); + s.remove(JsonKey.LAST_UPDATED_ON); + s.remove(JsonKey.CREATED_ON); + s.remove(JsonKey.USER_ID); + s.remove(JsonKey.SLUG); + }); + } + } + return dbResExternalIds; + } + + @SuppressWarnings("unchecked") + private void setCompleteProfileVisibilityMap(Map userMap) { + Map profileVisibilityMap = + (Map) userMap.get(JsonKey.PROFILE_VISIBILITY); + Map completeProfileVisibilityMap = + Util.getCompleteProfileVisibilityMap(profileVisibilityMap, systemSettingActorRef); + userMap.put(JsonKey.PROFILE_VISIBILITY, completeProfileVisibilityMap); + } + + private void setDefaultUserProfileVisibility(Map userMap) { + userMap.put( + JsonKey.DEFAULT_PROFILE_FIELD_VISIBILITY, + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_USER_PROFILE_FIELD_DEFAULT_VISIBILITY)); + } + + /** + * This method will remove user private field from response map + * + * @param responseMap Map + */ + private Map removeUserPrivateField(Map responseMap) { + ProjectLogger.log("Start removing User private field=="); + for (int i = 0; i < ProjectUtil.excludes.length; i++) { + responseMap.remove(ProjectUtil.excludes[i]); + } + ProjectLogger.log("All private filed removed="); + return responseMap; + } + + private Future> fetchRootAndRegisterOrganisation(Map result) { + try { + if (isNotNull(result.get(JsonKey.ROOT_ORG_ID))) { + String rootOrgId = (String) result.get(JsonKey.ROOT_ORG_ID); + return esUtil.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), rootOrgId); + } + } catch (Exception ex) { + ProjectLogger.log(ex.getMessage(), ex); + } + return null; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void addExtraFieldsInUserProfileResponse( + Map result, String fields, String userId) { + if (!StringUtils.isBlank(fields)) { + if (!fields.contains(JsonKey.COMPLETENESS)) { + result.remove(JsonKey.COMPLETENESS); + } + if (!fields.contains(JsonKey.MISSING_FIELDS)) { + result.remove(JsonKey.MISSING_FIELDS); + } + if (fields.contains(JsonKey.LAST_LOGIN_TIME)) { + result.put( + JsonKey.LAST_LOGIN_TIME, + Long.parseLong(getLastLoginTime(userId, (String) result.get(JsonKey.LAST_LOGIN_TIME)))); + } else { + result.remove(JsonKey.LAST_LOGIN_TIME); + } + if (fields.contains(JsonKey.TOPIC)) { + // fetch the topic details of all user associated orgs and append in the result + fetchTopicOfAssociatedOrgs(result); + } + if (fields.contains(JsonKey.ORGANISATIONS)) { + updateUserOrgInfo((List) result.get(JsonKey.ORGANISATIONS)); + } + if (fields.contains(JsonKey.ROLES)) { + updateRoleMasterInfo(result); + } + if (fields.contains(JsonKey.LOCATIONS)) { + result.put( + JsonKey.USER_LOCATIONS, + getUserLocations((List) result.get(JsonKey.LOCATION_IDS))); + result.remove(JsonKey.LOCATION_IDS); + } + } + } + + @SuppressWarnings("unchecked") + private void updateSkillWithEndoresmentCount(Map result) { + if (MapUtils.isNotEmpty(result) && result.containsKey(JsonKey.SKILLS)) { + List> skillList = (List>) result.get(JsonKey.SKILLS); + if (CollectionUtils.isEmpty(skillList)) { + return; + } + for (Map skill : skillList) { + skill.put( + JsonKey.ENDORSEMENT_COUNT.toLowerCase(), + (int) skill.getOrDefault(JsonKey.ENDORSEMENT_COUNT, 0)); + } + } + } + + private String getLastLoginTime(String userId, String time) { + String lastLoginTime = ""; + if (Boolean.parseBoolean(PropertiesCache.getInstance().getProperty(JsonKey.IS_SSO_ENABLED))) { + SSOManager manager = SSOServiceFactory.getInstance(); + lastLoginTime = manager.getLastLoginTime(userId); + } else { + lastLoginTime = time; + } + if (StringUtils.isBlank(lastLoginTime)) { + return "0"; + } + return lastLoginTime; + } + + @SuppressWarnings("unchecked") + private void fetchTopicOfAssociatedOrgs(Map result) { + + String userId = (String) result.get(JsonKey.ID); + Map locationCache = new HashMap<>(); + Set topicSet = new HashSet<>(); + + // fetch all associated user orgs + Response response1 = + cassandraOperation.getRecordsByProperty( + userOrgDbInfo.getKeySpace(), userOrgDbInfo.getTableName(), JsonKey.USER_ID, userId); + + List> list = (List>) response1.get(JsonKey.RESPONSE); + + List orgIdsList = new ArrayList<>(); + if (!list.isEmpty()) { + + for (Map m : list) { + String orgId = (String) m.get(JsonKey.ORGANISATION_ID); + orgIdsList.add(orgId); + } + + // fetch all org details from elasticsearch ... + if (!orgIdsList.isEmpty()) { + + Map filters = new HashMap<>(); + filters.put(JsonKey.ID, orgIdsList); + + List orgfields = new ArrayList<>(); + orgfields.add(JsonKey.ID); + orgfields.add(JsonKey.LOCATION_ID); + + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + searchDTO.setFields(orgfields); + Future> esresultF = + esUtil.search(searchDTO, EsType.organisation.getTypeName()); + Map esresult = + (Map) ElasticSearchHelper.getResponseFromFuture(esresultF); + List> esContent = + (List>) esresult.get(JsonKey.CONTENT); + + if (!esContent.isEmpty()) { + for (Map m : esContent) { + if (!StringUtils.isBlank((String) m.get(JsonKey.LOCATION_ID))) { + String locationId = (String) m.get(JsonKey.LOCATION_ID); + if (locationCache.containsKey(locationId)) { + topicSet.add((String) locationCache.get(locationId)); + } else { + // get the location id info from db and set to the cacche and + // topicSet + Response response3 = + cassandraOperation.getRecordById( + geoLocationDbInfo.getKeySpace(), + geoLocationDbInfo.getTableName(), + locationId); + List> list3 = + (List>) response3.get(JsonKey.RESPONSE); + if (!list3.isEmpty()) { + Map locationInfoMap = list3.get(0); + String topic = (String) locationInfoMap.get(JsonKey.TOPIC); + topicSet.add(topic); + locationCache.put(locationId, topic); + } + } + } + } + } + } + } + result.put(JsonKey.TOPICS, topicSet); + } + + private void updateUserOrgInfo(List> userOrgs) { + Map> orgInfoMap = fetchAllOrgsById(userOrgs); + Map> locationInfoMap = fetchAllLocationsById(orgInfoMap); + prepUserOrgInfoWithAdditionalData(userOrgs, orgInfoMap, locationInfoMap); + } + + private Map> fetchAllOrgsById(List> userOrgs) { + List orgIds = + userOrgs + .stream() + .map(m -> (String) m.get(JsonKey.ORGANISATION_ID)) + .distinct() + .collect(Collectors.toList()); + List fields = + Arrays.asList( + JsonKey.ORG_NAME, JsonKey.CHANNEL, JsonKey.HASHTAGID, JsonKey.LOCATION_IDS, JsonKey.ID); + + Map> orgInfoMap = + getEsResultByListOfIds(orgIds, fields, EsType.organisation); + return orgInfoMap; + } + + @SuppressWarnings("unchecked") + private Map> fetchAllLocationsById( + Map> orgInfoMap) { + List searchLocations = new ArrayList<>(); + for (Map org : orgInfoMap.values()) { + List locations = (List) org.get(JsonKey.LOCATION_IDS); + if (locations != null) { + for (String location : locations) { + if (!searchLocations.contains(location)) { + searchLocations.add(location); + } + } + } + } + List locationFields = + Arrays.asList(JsonKey.CODE, JsonKey.NAME, JsonKey.TYPE, JsonKey.PARENT_ID, JsonKey.ID); + Map> locationInfoMap = + getEsResultByListOfIds(searchLocations, locationFields, EsType.location); + return locationInfoMap; + } + + @SuppressWarnings("unchecked") + private void prepUserOrgInfoWithAdditionalData( + List> userOrgs, + Map> orgInfoMap, + Map> locationInfoMap) { + for (Map usrOrg : userOrgs) { + Map orgInfo = orgInfoMap.get(usrOrg.get(JsonKey.ORGANISATION_ID)); + usrOrg.put(JsonKey.ORG_NAME, orgInfo.get(JsonKey.ORG_NAME)); + usrOrg.put(JsonKey.CHANNEL, orgInfo.get(JsonKey.CHANNEL)); + usrOrg.put(JsonKey.HASHTAGID, orgInfo.get(JsonKey.HASHTAGID)); + usrOrg.put(JsonKey.LOCATION_IDS, orgInfo.get(JsonKey.LOCATION_IDS)); + usrOrg.put( + JsonKey.LOCATIONS, + prepLocationFields((List) orgInfo.get(JsonKey.LOCATION_IDS), locationInfoMap)); + } + } + + private List> prepLocationFields( + List locationIds, Map> locationInfoMap) { + List> retList = new ArrayList<>(); + if (locationIds != null) { + for (String locationId : locationIds) { + retList.add(locationInfoMap.get(locationId)); + } + } + return retList; + } + + @SuppressWarnings("unchecked") + private Map> getEsResultByListOfIds( + List orgIds, List fields, EsType typeToSearch) { + Map filters = new HashMap<>(); + filters.put(JsonKey.ID, orgIds); + + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + searchDTO.setFields(fields); + + Future> resultF = esUtil.search(searchDTO, typeToSearch.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + + List> esContent = (List>) result.get(JsonKey.CONTENT); + return esContent + .stream() + .collect( + Collectors.toMap( + obj -> { + return (String) obj.get("id"); + }, + val -> val)); + } + + private void updateRoleMasterInfo(Map result) { + Set> roleSet = DataCacheHandler.getRoleMap().entrySet(); + List> roleList = new ArrayList<>(); + roleSet + .parallelStream() + .forEach( + (roleSetItem) -> { + Map roleMap = new HashMap<>(); + roleMap.put(JsonKey.ID, roleSetItem.getKey()); + roleMap.put(JsonKey.NAME, (String) roleSetItem.getValue()); + roleList.add(roleMap); + }); + result.put(JsonKey.ROLE_LIST, roleList); + } + + /** + * Method to get user profile (version 2). + * + * @param actorMessage Request containing user ID + */ + @SuppressWarnings("unchecked") + private void getUserProfileV2(Request actorMessage) { + Response response = getUserProfileData(actorMessage); + SystemSettingClient systemSetting = new SystemSettingClientImpl(); + Object excludedFieldList = + systemSetting.getSystemSettingByFieldAndKey( + systemSettingActorRef, + JsonKey.USER_PROFILE_CONFIG, + JsonKey.SUNBIRD_USER_PROFILE_READ_EXCLUDED_FIELDS, + new TypeReference>() {}); + if (excludedFieldList != null) { + removeExcludedFieldsFromUserProfileResponse( + (Map) response.get(JsonKey.RESPONSE), (List) excludedFieldList); + } else { + ProjectLogger.log( + "UserProfileReadActor:getUserProfileV2: System setting userProfileConfig.read.excludedFields not configured.", + LoggerEnum.INFO.name()); + } + sender().tell(response, self()); + } + + private void removeExcludedFieldsFromUserProfileResponse( + Map response, List excludeFields) { + if (CollectionUtils.isNotEmpty(excludeFields)) { + for (String key : excludeFields) { + response.remove(key); + } + } + } + + @SuppressWarnings("unchecked") + private void getUserDetailsByLoginId(Request actorMessage) { + actorMessage.toLower(); + Map userMap = actorMessage.getRequest(); + if (null != userMap.get(JsonKey.LOGIN_ID)) { + String loginId = (String) userMap.get(JsonKey.LOGIN_ID); + try { + loginId = encryptionService.encryptData((String) userMap.get(JsonKey.LOGIN_ID)); + } catch (Exception e) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + SearchDTO searchDto = new SearchDTO(); + Map filter = new HashMap<>(); + filter.put(JsonKey.LOGIN_ID, loginId); + searchDto.getAdditionalProperties().put(JsonKey.FILTERS, filter); + Future> esResponseF = + esUtil.search(searchDto, ProjectUtil.EsType.user.getTypeName()); + Map esResponse = + (Map) ElasticSearchHelper.getResponseFromFuture(esResponseF); + List> userList = + (List>) esResponse.get(JsonKey.CONTENT); + Map result = null; + if (null != userList && !userList.isEmpty()) { + result = userList.get(0); + } else { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + // String username = ssoManager.getUsernameById((String) result.get(JsonKey.USER_ID)); + // result.put(JsonKey.USERNAME, username); + sendResponse(actorMessage, result); + + } else { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + sender().tell(exception, self()); + return; + } + } + + private void sendResponse(Request actorMessage, Map result) { + if (result == null || result.size() == 0) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + + // check whether is_deletd true or false + if (ProjectUtil.isNotNull(result) + && result.containsKey(JsonKey.IS_DELETED) + && ProjectUtil.isNotNull(result.get(JsonKey.IS_DELETED)) + && (Boolean) result.get(JsonKey.IS_DELETED)) { + throw new ProjectCommonException( + ResponseCode.userAccountlocked.getErrorCode(), + ResponseCode.userAccountlocked.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + Future> future = fetchRootAndRegisterOrganisation(result); + Future response = + future.map( + new Mapper, Response>() { + @Override + public Response apply(Map responseMap) { + ProjectLogger.log( + "UserProfileReadActor:handle user profile read async call ", + LoggerEnum.INFO.name()); + result.put(JsonKey.ROOT_ORG, responseMap); + Response response = new Response(); + handleUserCallAsync(result, response, actorMessage); + return response; + } + }, + getContext().dispatcher()); + Patterns.pipe(response, getContext().dispatcher()).to(sender()); + } + + private void handleUserCallAsync( + Map result, Response response, Request actorMessage) { + // having check for removing private filed from user , if call user and response + // user data id is not same. + String requestedById = + (String) actorMessage.getContext().getOrDefault(JsonKey.REQUESTED_BY, ""); + ProjectLogger.log( + "requested By and requested user id == " + + requestedById + + " " + + (String) result.get(JsonKey.USER_ID)); + + try { + if (!(((String) result.get(JsonKey.USER_ID)).equalsIgnoreCase(requestedById))) { + result = removeUserPrivateField(result); + } else { + // These values are set to ensure backward compatibility post introduction of + // global + // settings in user profile visibility + setCompleteProfileVisibilityMap(result); + setDefaultUserProfileVisibility(result); + // If the user requests his data then we are fetching the private data from + // userprofilevisibility index + // and merge it with user index data + Future> privateResultF = + esUtil.getDataByIdentifier( + ProjectUtil.EsType.userprofilevisibility.getTypeName(), + (String) result.get(JsonKey.USER_ID)); + Map privateResult = + (Map) ElasticSearchHelper.getResponseFromFuture(privateResultF); + // fetch user external identity + List> dbResExternalIds = fetchUserExternalIdentity(requestedById); + result.put(JsonKey.EXTERNAL_IDS, dbResExternalIds); + result.putAll(privateResult); + } + } catch (Exception e) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + + if (null != result) { + // remove email and phone no from response + result.remove(JsonKey.ENC_EMAIL); + result.remove(JsonKey.ENC_PHONE); + updateTnc(result); + if (null != actorMessage.getRequest().get(JsonKey.FIELDS)) { + List requestFields = (List) actorMessage.getRequest().get(JsonKey.FIELDS); + if (requestFields != null) { + addExtraFieldsInUserProfileResponse( + result, String.join(",", requestFields), (String) result.get(JsonKey.USER_ID)); + } else { + result.remove(JsonKey.MISSING_FIELDS); + result.remove(JsonKey.COMPLETENESS); + } + } else { + result.remove(JsonKey.MISSING_FIELDS); + result.remove(JsonKey.COMPLETENESS); + } + response.put(JsonKey.RESPONSE, result); + UserUtility.decryptUserDataFrmES(result); + } else { + result = new HashMap<>(); + response.put(JsonKey.RESPONSE, result); + } + } + + private void updateTnc(Map userSearchMap) { + Map tncConfigMap = null; + try { + String tncValue = DataCacheHandler.getConfigSettings().get(JsonKey.TNC_CONFIG); + ObjectMapper mapper = new ObjectMapper(); + tncConfigMap = mapper.readValue(tncValue, Map.class); + + } catch (Exception e) { + ProjectLogger.log( + "UserProfileReadActor:updateTncInfo: Exception occurred while getting system setting for" + + JsonKey.TNC_CONFIG + + e.getMessage(), + LoggerEnum.ERROR.name()); + } + + if (MapUtils.isNotEmpty(tncConfigMap)) { + try { + String tncLatestVersion = (String) tncConfigMap.get(JsonKey.LATEST_VERSION); + userSearchMap.put(JsonKey.TNC_LATEST_VERSION, tncLatestVersion); + String tncUserAcceptedVersion = (String) userSearchMap.get(JsonKey.TNC_ACCEPTED_VERSION); + String tncUserAcceptedOn = (String) userSearchMap.get(JsonKey.TNC_ACCEPTED_ON); + if (StringUtils.isEmpty(tncUserAcceptedVersion) + || !tncUserAcceptedVersion.equalsIgnoreCase(tncLatestVersion) + || StringUtils.isEmpty(tncUserAcceptedOn)) { + userSearchMap.put(JsonKey.PROMPT_TNC, true); + } else { + userSearchMap.put(JsonKey.PROMPT_TNC, false); + } + + if (tncConfigMap.containsKey(tncLatestVersion)) { + String url = (String) ((Map) tncConfigMap.get(tncLatestVersion)).get(JsonKey.URL); + ProjectLogger.log( + "UserProfileReadActor:updateTncInfo: url = " + url, LoggerEnum.INFO.name()); + userSearchMap.put(JsonKey.TNC_LATEST_VERSION_URL, url); + } else { + userSearchMap.put(JsonKey.PROMPT_TNC, false); + ProjectLogger.log( + "UserProfileReadActor:updateTncInfo: TnC version URL is missing from configuration"); + } + } catch (Exception e) { + ProjectLogger.log( + "UserProfileReadActor:updateTncInfo: Exception occurred with error message = " + + e.getMessage(), + LoggerEnum.ERROR.name()); + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); + } + } + } + + private List> getUserLocations(List locationIds) { + if (CollectionUtils.isNotEmpty(locationIds)) { + List locationFields = + Arrays.asList(JsonKey.CODE, JsonKey.NAME, JsonKey.TYPE, JsonKey.PARENT_ID, JsonKey.ID); + Map> locationInfoMap = + getEsResultByListOfIds(locationIds, locationFields, EsType.location); + + return locationInfoMap.values().stream().collect(Collectors.toList()); + } + return new ArrayList<>(); + } + + private void checkUserExistences(Request request) { + + String value = (String) request.get(JsonKey.VALUE); + String type = (String) request.get(JsonKey.KEY); + try { + boolean exists = UserUtil.identifierExists(type, value); + Response response = new Response(); + response.put(JsonKey.EXISTS, exists); + sender().tell(response, self()); + } catch (Exception var11) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + } + + private void checkUserExistence(Request request) { + Map searchMap = new WeakHashMap<>(); + String value = (String) request.get(JsonKey.VALUE); + String encryptedValue = null; + try { + encryptedValue = encryptionService.encryptData(StringUtils.lowerCase(value)); + } catch (Exception var11) { + throw new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + searchMap.put((String) request.get(JsonKey.KEY), encryptedValue); + ProjectLogger.log( + "UserProfileReadActor:checkUserExistence: search map prepared " + searchMap, + LoggerEnum.INFO.name()); + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, searchMap); + Future> esFuture = esUtil.search(searchDTO, EsType.user.getTypeName()); + Future userResponse = + esFuture.map( + new Mapper, Response>() { + @Override + public Response apply(Map responseMap) { + List> respList = (List) responseMap.get(JsonKey.CONTENT); + long size = respList.size(); + Response resp = new Response(); + resp.put(JsonKey.EXISTS, true); + if (size <= 0) { + resp.put(JsonKey.EXISTS, false); + } + return resp; + } + }, + getContext().dispatcher()); + + Patterns.pipe(userResponse, getContext().dispatcher()).to(sender()); + } + + private void getKey(Request actorMessage) { + String key = (String) actorMessage.getRequest().get(JsonKey.KEY); + String value = (String) actorMessage.getRequest().get(JsonKey.VALUE); + if (JsonKey.LOGIN_ID.equalsIgnoreCase(key) || JsonKey.EMAIL.equalsIgnoreCase(key)) { + value = value.toLowerCase(); + } + String encryptedValue = null; + try { + encryptedValue = encryptionService.encryptData(value); + } catch (Exception e) { + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + sender().tell(exception, self()); + return; + } + + Map searchMap = new WeakHashMap<>(); + searchMap.put(key, encryptedValue); + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, searchMap); + handleUserSearchAsyncRequest(searchDTO, actorMessage); + } + + private void handleUserSearchAsyncRequest(SearchDTO searchDto, Request actorMessage) { + Future> futureResponse = + esUtil.search(searchDto, EsType.user.getTypeName()); + + Future> userResponse = + futureResponse.map( + new Mapper, Map>() { + @Override + public Map apply(Map responseMap) { + ProjectLogger.log( + "SearchHandlerActor:handleUserSearchAsyncRequest user search call ", + LoggerEnum.INFO); + List> respList = (List) responseMap.get(JsonKey.CONTENT); + isUserExists(respList); + Map userMap = respList.get(0); + userMap.put(JsonKey.EMAIL, userMap.get(JsonKey.MASKED_EMAIL)); + userMap.put(JsonKey.PHONE, userMap.get(JsonKey.MASKED_PHONE)); + isUserAccountDeleted(userMap); + return userMap; + } + }, + getContext().dispatcher()); + + Future orgResponse = + userResponse.map( + new Mapper, Object>() { + @Override + public Object apply(Map parameter) { + Map esOrgMap = new HashMap<>(); + esOrgMap = + (Map) + ElasticSearchHelper.getResponseFromFuture( + fetchRootAndRegisterOrganisation(parameter)); + return esOrgMap; + } + }, + getContext().dispatcher()); + + Future> userOrgResponse = + userResponse + .zip(orgResponse) + .map( + new Mapper, Object>, Map>() { + @Override + public Map apply(Tuple2, Object> parameter) { + Map userMap = parameter._1; + userMap.put(JsonKey.ROOT_ORG, (Map) parameter._2); + userMap.remove(JsonKey.ENC_EMAIL); + userMap.remove(JsonKey.ENC_PHONE); + String requestedById = + (String) actorMessage.getContext().getOrDefault(JsonKey.REQUESTED_BY, ""); + if (!(((String) userMap.get(JsonKey.USER_ID)) + .equalsIgnoreCase(requestedById))) { + userMap = removeUserPrivateField(userMap); + } + return userMap; + } + }, + getContext().dispatcher()); + + Future> externalIdFuture = + userResponse.map( + new Mapper, Map>() { + @Override + public Map apply(Map result) { + Map extIdMap = new HashMap<>(); + String requestedById = + (String) actorMessage.getContext().getOrDefault(JsonKey.REQUESTED_BY, ""); + if (((String) result.get(JsonKey.USER_ID)).equalsIgnoreCase(requestedById)) { + List> dbResExternalIds = + fetchUserExternalIdentity((String) result.get(JsonKey.USER_ID)); + extIdMap.put(JsonKey.EXTERNAL_IDS, dbResExternalIds); + return extIdMap; + } + return extIdMap; + } + }, + getContext().dispatcher()); + + Future> tncFuture = + userOrgResponse.map( + new Mapper, Map>() { + @Override + public Map apply(Map result) { + updateTnc(result); + if (null != actorMessage.getRequest().get(JsonKey.FIELDS)) { + List requestFields = + (List) actorMessage.getRequest().get(JsonKey.FIELDS); + if (requestFields != null) { + addExtraFieldsInUserProfileResponse( + result, + String.join(",", requestFields), + (String) result.get(JsonKey.USER_ID)); + } else { + result.remove(JsonKey.MISSING_FIELDS); + result.remove(JsonKey.COMPLETENESS); + } + } else { + result.remove(JsonKey.MISSING_FIELDS); + result.remove(JsonKey.COMPLETENESS); + } + UserUtility.decryptUserDataFrmES(result); + return result; + } + }, + getContext().dispatcher()); + + Future sumFuture = + externalIdFuture + .zip(tncFuture) + .map( + new Mapper, Map>, Response>() { + @Override + public Response apply( + Tuple2, Map> parameter) { + Map externalIdMap = parameter._1; + System.out.println("the externalId maap is " + externalIdMap); + Map tncMap = parameter._2; + tncMap.putAll(externalIdMap); + Response response = new Response(); + response.put(JsonKey.RESPONSE, tncMap); + return response; + } + }, + getContext().dispatcher()); + + Patterns.pipe(sumFuture, getContext().dispatcher()).to(sender()); + } + + private void isUserAccountDeleted(Map responseMap) { + if (BooleanUtils.isTrue((Boolean) responseMap.get(JsonKey.IS_DELETED))) { + throw new ProjectCommonException( + ResponseCode.userAccountlocked.getErrorCode(), + ResponseCode.userAccountlocked.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + + private void isUserExists(List> respList) { + if (null == respList || respList.size() == 0) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileUpdateActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileUpdateActor.java new file mode 100644 index 0000000000..30355f376c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserProfileUpdateActor.java @@ -0,0 +1,186 @@ +package org.sunbird.user.actors; + +import akka.dispatch.Futures; +import akka.dispatch.Mapper; +import akka.pattern.Patterns; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.request.Request; +import org.sunbird.user.util.UserActorOperations; +import scala.concurrent.Future; + +@ActorConfig( + tasks = {"saveUserAttributes"}, + asyncTasks = {"saveUserAttributes"} +) +public class UserProfileUpdateActor extends BaseActor { + + private static InterServiceCommunication interServiceCommunication = + InterServiceCommunicationFactory.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + if (UserActorOperations.SAVE_USER_ATTRIBUTES + .getValue() + .equalsIgnoreCase(request.getOperation())) { + saveUserAttributes(request); + } else { + onReceiveUnsupportedOperation("UserAttributesProcessingActor"); + } + } + + private void saveUserAttributes(Request request) { + Map userMap = request.getRequest(); + String operationType = (String) userMap.get(JsonKey.OPERATION_TYPE); + userMap.remove(JsonKey.OPERATION_TYPE); + List> futures = getFutures(userMap, operationType); + Future> futuresSequence = Futures.sequence(futures, getContext().dispatcher()); + Future consolidatedFutureResponse = getConsolidatedFutureResponse(futuresSequence); + Patterns.pipe(consolidatedFutureResponse, getContext().dispatcher()).to(sender()); + } + + private Future getConsolidatedFutureResponse(Future> futuresSequence) { + return futuresSequence.map( + new Mapper, Response>() { + Map map = new HashMap<>(); + List errorList = new ArrayList<>(); + + @Override + public Response apply(Iterable futureResult) { + for (Object object : futureResult) { + if (object instanceof Response) { + Response response = (Response) object; + Map result = response.getResult(); + String key = (String) result.get(JsonKey.KEY); + if (StringUtils.isNotBlank(key)) { + map.put(key, result.get(key)); + } + @SuppressWarnings("unchecked") + List errMsgList = (List) result.get(JsonKey.ERROR_MSG); + if (CollectionUtils.isNotEmpty(errMsgList)) { + for (String err : errMsgList) { + Map map = new HashMap<>(); + map.put(JsonKey.ATTRIBUTE, key); + map.put(JsonKey.MESSAGE, err); + errorList.add(map); + } + } + } else if (object instanceof ProjectCommonException) { + errorList.add(((ProjectCommonException) object).getMessage()); + } else if (object instanceof Exception) { + errorList.add(((Exception) object).getMessage()); + } + } + map.put(JsonKey.ERRORS, errorList); + Response response = new Response(); + response.put(JsonKey.RESPONSE, map); + return response; + } + }, + getContext().dispatcher()); + } + + @SuppressWarnings("unchecked") + private List> getFutures(Map userMap, String operationType) { + List> futures = new ArrayList<>(); + + if (userMap.containsKey(JsonKey.ADDRESS) + && CollectionUtils.isNotEmpty((List>) userMap.get(JsonKey.ADDRESS))) { + futures.add(saveAddress(userMap, operationType)); + } + + if (userMap.containsKey(JsonKey.EDUCATION) + && CollectionUtils.isNotEmpty((List>) userMap.get(JsonKey.EDUCATION))) { + futures.add(saveEducation(userMap, operationType)); + } + + if (userMap.containsKey(JsonKey.JOB_PROFILE) + && CollectionUtils.isNotEmpty( + (List>) userMap.get(JsonKey.JOB_PROFILE))) { + futures.add(saveJobProfile(userMap, operationType)); + } + + if (CollectionUtils.isNotEmpty((List>) userMap.get(JsonKey.EXTERNAL_IDS))) { + futures.add(saveUserExternalIds(userMap)); + } + + if (StringUtils.isNotBlank((String) userMap.get(JsonKey.ORGANISATION_ID)) + || StringUtils.isNotBlank((String) userMap.get(JsonKey.ROOT_ORG_ID))) { + futures.add(saveUserOrgDetails(userMap, operationType)); + } + + return futures; + } + + private Future saveAddress(Map userMap, String operationType) { + String actorOperation = UserActorOperations.UPDATE_USER_ADDRESS.getValue(); + + if (JsonKey.CREATE.equalsIgnoreCase(operationType)) { + actorOperation = UserActorOperations.INSERT_USER_ADDRESS.getValue(); + } + + return saveUserAttributes(userMap, actorOperation); + } + + private Future saveEducation(Map userMap, String operationType) { + String actorOperation = UserActorOperations.UPDATE_USER_EDUCATION.getValue(); + + if (JsonKey.CREATE.equalsIgnoreCase(operationType)) { + actorOperation = UserActorOperations.INSERT_USER_EDUCATION.getValue(); + } + + return saveUserAttributes(userMap, actorOperation); + } + + private Future saveJobProfile(Map userMap, String operationType) { + String actorOperation = UserActorOperations.UPDATE_USER_JOB_PROFILE.getValue(); + + if (JsonKey.CREATE.equalsIgnoreCase(operationType)) { + actorOperation = UserActorOperations.INSERT_USER_JOB_PROFILE.getValue(); + } + + return saveUserAttributes(userMap, actorOperation); + } + + private Future saveUserExternalIds(Map userMap) { + return saveUserAttributes( + userMap, UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS.getValue()); + } + + private Future saveUserOrgDetails(Map userMap, String operationType) { + String actorOperation = UserActorOperations.UPDATE_USER_ORG_DETAILS.getValue(); + + if (JsonKey.CREATE.equalsIgnoreCase(operationType)) { + actorOperation = UserActorOperations.INSERT_USER_ORG_DETAILS.getValue(); + } + + return saveUserAttributes(userMap, actorOperation); + } + + private Future saveUserAttributes(Map userMap, String actorOperation) { + try { + Request request = new Request(); + request.getRequest().putAll(userMap); + request.setOperation(actorOperation); + return interServiceCommunication.getFuture(getActorRef(actorOperation), request); + } catch (Exception ex) { + ProjectLogger.log( + "UserProfileUpdateActor:saveUserAttributes: Exception occurred with error message = " + + ex.getMessage(), + ex); + } + return null; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserRoleActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserRoleActor.java new file mode 100644 index 0000000000..5442644670 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserRoleActor.java @@ -0,0 +1,200 @@ +package org.sunbird.user.actors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.actorutil.org.OrganisationClient; +import org.sunbird.actorutil.org.impl.OrganisationClientImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.role.service.RoleService; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.models.organisation.Organisation; +import org.sunbird.models.user.org.UserOrg; +import org.sunbird.user.dao.UserOrgDao; +import org.sunbird.user.dao.impl.UserOrgDaoImpl; + +@ActorConfig( + tasks = {"getRoles", "assignRoles"}, + asyncTasks = {} +) +public class UserRoleActor extends UserBaseActor { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + + switch (operation) { + case "getRoles": + getRoles(); + break; + + case "assignRoles": + assignRoles(request); + break; + + default: + onReceiveUnsupportedOperation("UserRoleActor"); + } + } + + private void getRoles() { + ProjectLogger.log("UserRoleActor: getRoles called", LoggerEnum.INFO.name()); + Response response = DataCacheHandler.getRoleResponse(); + if (response == null) { + response = RoleService.getUserRoles(); + DataCacheHandler.setRoleResponse(response); + } + sender().tell(response, self()); + } + + @SuppressWarnings("unchecked") + private void assignRoles(Request actorMessage) { + ProjectLogger.log("UserRoleActor: assignRoles called"); + + Map requestMap = actorMessage.getRequest(); + RoleService.validateRoles((List) requestMap.get(JsonKey.ROLES)); + + boolean orgNotFound = initializeHashTagIdFromOrg(requestMap); + if (orgNotFound) return; + + String userId = (String) requestMap.get(JsonKey.USER_ID); + String hashTagId = (String) requestMap.get(JsonKey.HASHTAGID); + String organisationId = (String) requestMap.get(JsonKey.ORGANISATION_ID); + // update userOrg role with requested roles. + Map userOrgDBMap = new HashMap<>(); + + Map searchMap = new HashMap<>(); + searchMap.put(JsonKey.USER_ID, userId); + searchMap.put(JsonKey.ORGANISATION_ID, organisationId); + searchMap.put(JsonKey.IS_DELETED, false); + Response res = + cassandraOperation.getRecordsByProperties(JsonKey.SUNBIRD, JsonKey.USER_ORG, searchMap); + List> responseList = (List>) res.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(responseList)) { + userOrgDBMap.put(JsonKey.ORGANISATION, responseList.get(0)); + } + + if (MapUtils.isEmpty(userOrgDBMap)) { + ProjectCommonException.throwClientErrorException(ResponseCode.invalidUsrOrgData, null); + } + + UserOrg userOrg = prepareUserOrg(requestMap, hashTagId, userOrgDBMap); + UserOrgDao userOrgDao = UserOrgDaoImpl.getInstance(); + + Response response = userOrgDao.updateUserOrg(userOrg); + sender().tell(response, self()); + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + syncUserRoles(requestMap, JsonKey.ORGANISATION, userId, organisationId); + } else { + ProjectLogger.log("UserRoleActor: No ES call to save user roles"); + } + generateTelemetryEvent(requestMap, userId, "userLevel", actorMessage.getContext()); + } + + private boolean initializeHashTagIdFromOrg(Map requestMap) { + + String externalId = (String) requestMap.get(JsonKey.EXTERNAL_ID); + String provider = (String) requestMap.get(JsonKey.PROVIDER); + String organisationId = (String) requestMap.get(JsonKey.ORGANISATION_ID); + + // try find organisation and fetch hashTagId from organisation. + Map map = null; + Organisation organisation = null; + OrganisationClient orgClient = new OrganisationClientImpl(); + if (StringUtils.isNotBlank(organisationId)) { + + organisation = + orgClient.getOrgById( + getActorRef(ActorOperations.GET_ORG_DETAILS.getValue()), organisationId); + if (organisation != null) { + requestMap.put(JsonKey.HASHTAGID, organisation.getHashTagId()); + } + } else { + organisation = orgClient.esGetOrgByExternalId(externalId, provider); + if (organisation != null) { + requestMap.put(JsonKey.ORGANISATION_ID, organisation.getId()); + requestMap.put(JsonKey.HASHTAGID, organisation.getHashTagId()); + } + } + // throw error if provided orgId or ExtenralId with Provider is not valid + boolean orgNotFound = MapUtils.isEmpty(map) && organisation == null; + if (orgNotFound) { + handleOrgNotFound(externalId, provider, organisationId); + } + return orgNotFound; + } + + private void handleOrgNotFound(String externalId, String provider, String organisationId) { + String errorMsg = + StringUtils.isNotEmpty(organisationId) + ? ProjectUtil.formatMessage( + ResponseMessage.Message.INVALID_PARAMETER_VALUE, + organisationId, + JsonKey.ORGANISATION_ID) + : ProjectUtil.formatMessage( + ResponseMessage.Message.INVALID_PARAMETER_VALUE, + StringFormatter.joinByComma(externalId, provider), + StringFormatter.joinByAnd(JsonKey.EXTERNAL_ID, JsonKey.PROVIDER)); + ProjectCommonException exception = + new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + errorMsg, + ResponseCode.CLIENT_ERROR.getResponseCode()); + sender().tell(exception, self()); + } + + private UserOrg prepareUserOrg( + Map requestMap, String hashTagId, Map userOrgDBMap) { + ObjectMapper mapper = new ObjectMapper(); + Map userOrgMap = (Map) userOrgDBMap.get(JsonKey.ORGANISATION); + UserOrg userOrg = mapper.convertValue(userOrgMap, UserOrg.class); + List roles = (List) requestMap.get(JsonKey.ROLES); + if (!roles.contains(ProjectUtil.UserRole.PUBLIC.name())) { + roles.add(ProjectUtil.UserRole.PUBLIC.name()); + } + userOrg.setRoles(roles); + + if (StringUtils.isNotBlank(hashTagId)) { + userOrg.setHashTagId(hashTagId); + } + userOrg.setUpdatedDate(ProjectUtil.getFormattedDate()); + userOrg.setUpdatedBy((String) requestMap.get(JsonKey.REQUESTED_BY)); + return userOrg; + } + + private void syncUserRoles( + Map tempMap, String type, String userid, String orgId) { + ProjectLogger.log("UserRoleActor: syncUserRoles called"); + + Request request = new Request(); + request.setOperation(ActorOperations.UPDATE_USER_ROLES_ES.getValue()); + request.getRequest().put(JsonKey.ROLES, tempMap.get(JsonKey.ROLES)); + request.getRequest().put(JsonKey.TYPE, type); + request.getRequest().put(JsonKey.USER_ID, userid); + request.getRequest().put(JsonKey.ORGANISATION_ID, orgId); + ProjectLogger.log("UserRoleActor:syncUserRoles: Syncing to ES"); + try { + tellToAnother(request); + } catch (Exception ex) { + ProjectLogger.log( + "UserRoleActor:syncUserRoles: Exception occurred with error message = " + ex.getMessage(), + ex); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserStatusActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserStatusActor.java new file mode 100644 index 0000000000..207503704b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserStatusActor.java @@ -0,0 +1,128 @@ +package org.sunbird.user.actors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.Status; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.user.dao.UserDao; +import org.sunbird.user.dao.impl.UserDaoImpl; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; + +@ActorConfig( + tasks = {"unblockUser", "blockUser"}, + asyncTasks = {} +) +public class UserStatusActor extends UserBaseActor { + + private UserService userService = UserServiceImpl.getInstance(); + + @Override + public void onReceive(Request request) throws Throwable { + Util.initializeContext(request, TelemetryEnvKey.USER); + String operation = request.getOperation(); + switch (operation) { + case "blockUser": + blockUser(request); + break; + + case "unblockUser": + unblockUser(request); + break; + + default: + onReceiveUnsupportedOperation("UserStatusActor"); + } + } + + private void blockUser(Request actorMessage) { + updateUserStatus(actorMessage, true); + } + + private void unblockUser(Request actorMessage) { + updateUserStatus(actorMessage, false); + } + + private void updateUserStatus(Request request, boolean isBlocked) { + String operation = request.getOperation(); + String userId = (String) request.getRequest().get(JsonKey.USER_ID); + String logMsgPrefix = + MessageFormat.format("UserStatusActor:updateUserStatus:{0}:{1}: ", operation, userId); + User user = userService.getUserById(userId); + + if (operation.equals(ActorOperations.BLOCK_USER.getValue()) + && Boolean.TRUE.equals(user.getIsDeleted())) { + throw new ProjectCommonException( + ResponseCode.userAlreadyInactive.getErrorCode(), + ResponseCode.userAlreadyInactive.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + if (operation.equals(ActorOperations.UNBLOCK_USER.getValue()) + && Boolean.FALSE.equals(user.getIsDeleted())) { + throw new ProjectCommonException( + ResponseCode.userAlreadyActive.getErrorCode(), + ResponseCode.userAlreadyActive.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + Map userMapES = + getUserMapES(userId, (String) request.getContext().get(JsonKey.REQUESTED_BY), isBlocked); + + ObjectMapper mapper = new ObjectMapper(); + User updatedUser = mapper.convertValue(userMapES, User.class); + SSOManager ssoManager = SSOServiceFactory.getInstance(); + UserDao userDao = UserDaoImpl.getInstance(); + if (isBlocked) { + ssoManager.deactivateUser(userMapES); + } else { + ssoManager.activateUser(userMapES); + } + + Response response = userDao.updateUser(updatedUser); + sender().tell(response, self()); + + // Update status in ES + if (((String) response.get(JsonKey.RESPONSE)).equalsIgnoreCase(JsonKey.SUCCESS)) { + ProjectLogger.log(logMsgPrefix + "Update user data to ES."); + + Request userRequest = new Request(); + userRequest.setOperation(ActorOperations.UPDATE_USER_INFO_ELASTIC.getValue()); + userRequest.getRequest().put(JsonKey.ID, userId); + + try { + tellToAnother(userRequest); + } catch (Exception e) { + ProjectLogger.log( + logMsgPrefix + "Exception occurred with error message = " + e.getMessage(), e); + } + } else { + ProjectLogger.log(logMsgPrefix + "Update user data to ES is skipped."); + } + + generateTelemetryEvent(request.getRequest(), userId, operation, request.getContext()); + } + + private Map getUserMapES(String userId, String updatedBy, boolean isDeleted) { + Map esUserMap = new HashMap<>(); + esUserMap.put(JsonKey.IS_DELETED, isDeleted); + esUserMap.put( + JsonKey.STATUS, isDeleted ? Status.INACTIVE.getValue() : Status.ACTIVE.getValue()); + esUserMap.put(JsonKey.ID, userId); + esUserMap.put(JsonKey.USER_ID, userId); + esUserMap.put(JsonKey.UPDATED_DATE, ProjectUtil.getFormattedDate()); + esUserMap.put(JsonKey.UPDATED_BY, updatedBy); + return esUserMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserTypeActor.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserTypeActor.java new file mode 100644 index 0000000000..80cb31bed3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/actors/UserTypeActor.java @@ -0,0 +1,49 @@ +package org.sunbird.user.actors; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.sunbird.actor.router.ActorConfig; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.models.user.UserType; + +@ActorConfig( + tasks = {"getUserTypes"}, + asyncTasks = {} +) +public class UserTypeActor extends UserBaseActor { + + @Override + public void onReceive(Request request) throws Throwable { + String operation = request.getOperation(); + switch (operation) { + case "getUserTypes": + getUserTypes(); + break; + } + } + + @SuppressWarnings("unchecked") + private void getUserTypes() { + + Response response = new Response(); + List> userTypeList = getUserTypeList(); + response.getResult().put(JsonKey.RESPONSE, userTypeList); + sender().tell(response, self()); + } + + private List> getUserTypeList() { + List> userTypeList = new ArrayList<>(); + + for (UserType userType : UserType.values()) { + Map userTypeMap = new HashMap<>(); + userTypeMap.put(JsonKey.ID, userType.getTypeName()); + userTypeMap.put(JsonKey.NAME, userType.getTypeName()); + userTypeList.add(userTypeMap); + } + return userTypeList; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/AddressDao.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/AddressDao.java new file mode 100644 index 0000000000..bd7758f9e4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/AddressDao.java @@ -0,0 +1,15 @@ +package org.sunbird.user.dao; + +import java.util.Map; +import org.sunbird.common.models.response.Response; + +public interface AddressDao { + + void createAddress(Map address); + + void updateAddress(Map address); + + Response upsertAddress(Map address); + + void deleteAddress(String addressId); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/EducationDao.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/EducationDao.java new file mode 100644 index 0000000000..cb5dca0013 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/EducationDao.java @@ -0,0 +1,17 @@ +package org.sunbird.user.dao; + +import java.util.Map; +import org.sunbird.common.models.response.Response; + +public interface EducationDao { + + void createEducation(Map education); + + void updateEducation(Map education); + + void upsertEducation(Map education); + + void deleteEducation(String educationId); + + Response getPropertiesValueById(String propertyName, String identifier); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/JobProfileDao.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/JobProfileDao.java new file mode 100644 index 0000000000..1d73ff7ba1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/JobProfileDao.java @@ -0,0 +1,17 @@ +package org.sunbird.user.dao; + +import java.util.Map; +import org.sunbird.common.models.response.Response; + +public interface JobProfileDao { + + void createJobProfile(Map jobProfile); + + void updateJobProfile(Map jobProfile); + + void upsertJobProfile(Map jobProfile); + + void deleteJobProfile(String jobProfileId); + + Response getPropertiesValueById(String propertyName, String identifier); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserDao.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserDao.java new file mode 100644 index 0000000000..29e5e5416f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserDao.java @@ -0,0 +1,61 @@ +package org.sunbird.user.dao; + +import java.util.List; +import java.util.Map; +import org.sunbird.common.models.response.Response; +import org.sunbird.models.user.User; + +/** + * This interface will have all methods required for user service api. + * + * @author Amit Kumar + */ +public interface UserDao { + + /** + * This method will create user and return userId as success response or throw + * ProjectCommonException. + * + * @param user User Details. + * @return User ID. + */ + String createUser(User user); + + /** + * This method will update existing user info or throw ProjectCommonException. + * + * @param user User Details. + */ + Response updateUser(User user); + + /** + * This method will update existing user info even if some fields need to be nullify or throw + * ProjectCommonException. + * + * @param userMap User Details. + */ + Response updateUser(Map userMap); + + /** + * This method will search user from ES and return list of user details matching filter criteria. + * + * @param searchQueryMap search query for ES as a Map. + * @return List List of user. + */ + List searchUser(Map searchQueryMap); + + /** + * This method will user based on userId and return user if found else throw + * ProjectCommonException. + * + * @param userId User id. + * @return User User Details. + */ + User getUserById(String userId); + + /** + * @param propertyMap Map of user property and its value + * @return List List of user. + */ + List getUsersByProperties(Map propertyMap); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserExternalIdentityDao.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserExternalIdentityDao.java new file mode 100644 index 0000000000..f077ffc980 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserExternalIdentityDao.java @@ -0,0 +1,8 @@ +package org.sunbird.user.dao; + +import org.sunbird.common.request.Request; + +public interface UserExternalIdentityDao { + + String getUserId(Request request); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserOrgDao.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserOrgDao.java new file mode 100644 index 0000000000..3f33e8b2e0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/UserOrgDao.java @@ -0,0 +1,10 @@ +package org.sunbird.user.dao; + +import org.sunbird.common.models.response.Response; +import org.sunbird.models.user.org.UserOrg; + +public interface UserOrgDao { + Response updateUserOrg(UserOrg userOrg); + + Response createUserOrg(UserOrg userOrg); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/AddressDaoImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/AddressDaoImpl.java new file mode 100644 index 0000000000..32209bd8a1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/AddressDaoImpl.java @@ -0,0 +1,52 @@ +package org.sunbird.user.dao.impl; + +import java.util.Map; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.user.dao.AddressDao; + +public class AddressDaoImpl implements AddressDao { + + private Util.DbInfo addrDbInfo = Util.dbInfoMap.get(JsonKey.ADDRESS_DB); + + private AddressDaoImpl() {} + + private static class LazyInitializer { + private static AddressDao INSTANCE = new AddressDaoImpl(); + } + + public static AddressDao getInstance() { + return LazyInitializer.INSTANCE; + } + + @Override + public void createAddress(Map address) { + getCassandraOperation() + .insertRecord(addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), address); + } + + @Override + public void updateAddress(Map address) { + getCassandraOperation() + .updateRecord(addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), address); + } + + @Override + public void deleteAddress(String addressId) { + getCassandraOperation() + .deleteRecord(addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), addressId); + } + + @Override + public Response upsertAddress(Map address) { + return getCassandraOperation() + .upsertRecord(addrDbInfo.getKeySpace(), addrDbInfo.getTableName(), address); + } + + private CassandraOperation getCassandraOperation() { + return ServiceFactory.getInstance(); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/EducationDaoImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/EducationDaoImpl.java new file mode 100644 index 0000000000..aee064cb8a --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/EducationDaoImpl.java @@ -0,0 +1,51 @@ +package org.sunbird.user.dao.impl; + +import java.util.Map; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.user.dao.EducationDao; + +public class EducationDaoImpl implements EducationDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private Util.DbInfo eduDbInfo = Util.dbInfoMap.get(JsonKey.EDUCATION_DB); + + private EducationDaoImpl() {} + + private static class LazyInitializer { + private static EducationDao INSTANCE = new EducationDaoImpl(); + } + + public static EducationDao getInstance() { + return LazyInitializer.INSTANCE; + } + + @Override + public void createEducation(Map education) { + cassandraOperation.insertRecord(eduDbInfo.getKeySpace(), eduDbInfo.getTableName(), education); + } + + @Override + public void updateEducation(Map education) { + cassandraOperation.updateRecord(eduDbInfo.getKeySpace(), eduDbInfo.getTableName(), education); + } + + @Override + public void deleteEducation(String educationId) { + cassandraOperation.deleteRecord(eduDbInfo.getKeySpace(), eduDbInfo.getTableName(), educationId); + } + + @Override + public void upsertEducation(Map education) { + cassandraOperation.upsertRecord(eduDbInfo.getKeySpace(), eduDbInfo.getTableName(), education); + } + + @Override + public Response getPropertiesValueById(String propertyName, String identifier) { + return cassandraOperation.getPropertiesValueById( + eduDbInfo.getKeySpace(), eduDbInfo.getTableName(), identifier, JsonKey.ADDRESS_ID); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/JobProfileDaoImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/JobProfileDaoImpl.java new file mode 100644 index 0000000000..a1f42cb81c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/JobProfileDaoImpl.java @@ -0,0 +1,55 @@ +package org.sunbird.user.dao.impl; + +import java.util.Map; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.user.dao.JobProfileDao; + +public class JobProfileDaoImpl implements JobProfileDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private Util.DbInfo jobProDbInfo = Util.dbInfoMap.get(JsonKey.JOB_PROFILE_DB); + + private JobProfileDaoImpl() {} + + private static class LazyInitializer { + private static JobProfileDao INSTANCE = new JobProfileDaoImpl(); + } + + public static JobProfileDao getInstance() { + return LazyInitializer.INSTANCE; + } + + @Override + public void createJobProfile(Map jobProfile) { + cassandraOperation.insertRecord( + jobProDbInfo.getKeySpace(), jobProDbInfo.getTableName(), jobProfile); + } + + @Override + public void updateJobProfile(Map jobProfile) { + cassandraOperation.updateRecord( + jobProDbInfo.getKeySpace(), jobProDbInfo.getTableName(), jobProfile); + } + + @Override + public void upsertJobProfile(Map jobProfile) { + cassandraOperation.upsertRecord( + jobProDbInfo.getKeySpace(), jobProDbInfo.getTableName(), jobProfile); + } + + @Override + public void deleteJobProfile(String jobProfileId) { + cassandraOperation.deleteRecord( + jobProDbInfo.getKeySpace(), jobProDbInfo.getTableName(), jobProfileId); + } + + @Override + public Response getPropertiesValueById(String propertyName, String identifier) { + return cassandraOperation.getPropertiesValueById( + jobProDbInfo.getKeySpace(), jobProDbInfo.getTableName(), identifier, JsonKey.ADDRESS_ID); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserDaoImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserDaoImpl.java new file mode 100644 index 0000000000..3470892ec5 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserDaoImpl.java @@ -0,0 +1,116 @@ +package org.sunbird.user.dao.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.user.dao.UserDao; +import scala.concurrent.Future; + +/** + * Implementation class of UserDao interface. + * + * @author Amit Kumar + */ +public class UserDaoImpl implements UserDao { + + private static final String TABLE_NAME = "user"; + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private ObjectMapper mapper = new ObjectMapper(); + private static UserDao userDao = null; + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + + public static UserDao getInstance() { + if (userDao == null) { + userDao = new UserDaoImpl(); + } + return userDao; + } + + @Override + public String createUser(User user) { + Map map = mapper.convertValue(user, Map.class); + cassandraOperation.insertRecord(Util.KEY_SPACE_NAME, TABLE_NAME, map); + return (String) map.get(JsonKey.ID); + } + + @Override + public Response updateUser(User user) { + Map map = mapper.convertValue(user, Map.class); + return cassandraOperation.updateRecord(Util.KEY_SPACE_NAME, TABLE_NAME, map); + } + + @Override + public Response updateUser(Map userMap) { + return cassandraOperation.updateRecord(Util.KEY_SPACE_NAME, TABLE_NAME, userMap); + } + + @Override + public List searchUser(Map searchQueryMap) { + List userList = new ArrayList<>(); + Map searchRequestMap = new HashMap<>(); + SearchDTO searchDto = Util.createSearchDto(searchRequestMap); + searchRequestMap.put(JsonKey.FILTERS, searchQueryMap); + String type = ProjectUtil.EsType.user.getTypeName(); + Future> resultF = esUtil.search(searchDto, type); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + + if (MapUtils.isNotEmpty(result)) { + List> searchResult = + (List>) result.get(JsonKey.CONTENT); + if (CollectionUtils.isNotEmpty(searchResult)) { + userList = + searchResult + .stream() + .map(s -> mapper.convertValue(s, User.class)) + .collect(Collectors.toList()); + } + } + return userList; + } + + @Override + public User getUserById(String userId) { + Response response = cassandraOperation.getRecordById(Util.KEY_SPACE_NAME, TABLE_NAME, userId); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(responseList)) { + Map userMap = responseList.get(0); + return mapper.convertValue(userMap, User.class); + } + return null; + } + + @Override + public List getUsersByProperties(Map propertyMap) { + List userList = new ArrayList<>(); + Response response = + cassandraOperation.getRecordsByProperties(Util.KEY_SPACE_NAME, TABLE_NAME, propertyMap); + List> responseList = + (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(responseList)) { + userList = + responseList + .stream() + .map(s -> mapper.convertValue(s, User.class)) + .collect(Collectors.toList()); + } + return userList; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserExternalIdentityDaoImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserExternalIdentityDaoImpl.java new file mode 100644 index 0000000000..aae85d035c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserExternalIdentityDaoImpl.java @@ -0,0 +1,77 @@ +package org.sunbird.user.dao.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.user.dao.UserExternalIdentityDao; + +public class UserExternalIdentityDaoImpl implements UserExternalIdentityDao { + + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + + @Override + public String getUserId(Request reqObj) { + String userId; + + if (null != reqObj.getRequest().get(JsonKey.USER_ID)) { + userId = (String) reqObj.getRequest().get(JsonKey.USER_ID); + } else { + userId = (String) reqObj.getRequest().get(JsonKey.ID); + } + + if (StringUtils.isBlank(userId)) { + String extId = (String) reqObj.getRequest().get(JsonKey.EXTERNAL_ID); + String provider = (String) reqObj.getRequest().get(JsonKey.EXTERNAL_ID_PROVIDER); + String idType = (String) reqObj.getRequest().get(JsonKey.EXTERNAL_ID_TYPE); + + userId = getUserIdByExternalId(extId, provider, idType); + } + + return userId; + } + + @SuppressWarnings({"unchecked"}) + public String getUserIdByExternalId(String extId, String provider, String idType) { + Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Map externalIdReq = new HashMap<>(); + externalIdReq.put(JsonKey.PROVIDER, provider.toLowerCase()); + externalIdReq.put(JsonKey.ID_TYPE, idType.toLowerCase()); + externalIdReq.put(JsonKey.EXTERNAL_ID, extId.toLowerCase()); + Response response = + cassandraOperation.getRecordsByProperties( + usrDbInfo.getKeySpace(), JsonKey.USR_EXT_IDNT_TABLE, externalIdReq); + + List> userRecordList = + (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(userRecordList)) { + return (String) userRecordList.get(0).get(JsonKey.USER_ID); + } + + return null; + } + + private String getEncryptedData(String value) { + try { + return encryptionService.encryptData(value); + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserOrgDaoImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserOrgDaoImpl.java new file mode 100644 index 0000000000..418000f702 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/dao/impl/UserOrgDaoImpl.java @@ -0,0 +1,40 @@ +package org.sunbird.user.dao.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.org.UserOrg; +import org.sunbird.user.dao.UserOrgDao; + +public final class UserOrgDaoImpl implements UserOrgDao { + + private static final String TABLE_NAME = "user_org"; + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + + private ObjectMapper mapper = new ObjectMapper(); + + private UserOrgDaoImpl() {} + + private static class LazyInitializer { + private static UserOrgDao INSTANCE = new UserOrgDaoImpl(); + } + + public static UserOrgDao getInstance() { + return LazyInitializer.INSTANCE; + } + + @Override + public Response updateUserOrg(UserOrg userOrg) { + return cassandraOperation.updateRecord( + Util.KEY_SPACE_NAME, TABLE_NAME, mapper.convertValue(userOrg, Map.class)); + } + + @Override + public Response createUserOrg(UserOrg userOrg) { + return cassandraOperation.insertRecord( + Util.KEY_SPACE_NAME, TABLE_NAME, mapper.convertValue(userOrg, Map.class)); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/UserEncryptionService.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/UserEncryptionService.java new file mode 100644 index 0000000000..df58e434f1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/UserEncryptionService.java @@ -0,0 +1,11 @@ +package org.sunbird.user.service; + +import java.util.List; +import java.util.Map; + +public interface UserEncryptionService { + + List getDecryptedFields(Map userMap); + + List getEncryptedFields(Map userMap); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/UserService.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/UserService.java new file mode 100644 index 0000000000..001f3807ed --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/UserService.java @@ -0,0 +1,47 @@ +package org.sunbird.user.service; + +import akka.actor.ActorRef; +import java.util.List; +import java.util.Map; +import org.sunbird.common.request.Request; +import org.sunbird.models.user.User; + +public interface UserService { + + Map esGetUserOrg(String userId, String orgId); + + User getUserById(String userId); + + void validateUserId(Request request, String managedById); + + void validateUploader(Request request); + + Map esGetPublicUserProfileById(String userId); + + Map esGetPrivateUserProfileById(String userId); + + void syncUserProfile( + String userId, Map userDataMap, Map userPrivateDataMap); + + String getValidatedCustodianOrgId(Map userMap, ActorRef actorRef); + + String getRootOrgIdFromChannel(String channel); + + String getCustodianChannel(Map userMap, ActorRef actorRef); + + Map getUserByUsername(String userName); + + List> esSearchUserByFilters(Map filters); + + List generateUsernames(String name, List excludedUsernames); + + List getEncryptedList(List dataList); + + boolean checkUsernameUniqueness(String username, boolean isEncrypted); + + String getCustodianOrgId(ActorRef actorRef); + + Map fetchEncryptedToken(String parentId, List> respList); + + void appendEncryptedToken(Map encryptedTokenList, List> respList); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/impl/UserEncryptionServiceImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/impl/UserEncryptionServiceImpl.java new file mode 100644 index 0000000000..04f52c808c --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/impl/UserEncryptionServiceImpl.java @@ -0,0 +1,101 @@ +package org.sunbird.user.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.PhoneValidator; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.models.util.datasecurity.impl.ServiceFactory; +import org.sunbird.user.service.UserEncryptionService; + +public class UserEncryptionServiceImpl implements UserEncryptionService { + + private DecryptionService decryptionService = ServiceFactory.getDecryptionServiceInstance(null); + private EncryptionService encryptionService = ServiceFactory.getEncryptionServiceInstance(null); + private List userEncryptedFieldList = + Arrays.asList(JsonKey.USERNAME, JsonKey.LOGIN_ID, JsonKey.LOCATION); + + private UserEncryptionServiceImpl() {}; + + public static class LazyInitialisation { + private static UserEncryptionService INSTANCE = new UserEncryptionServiceImpl(); + } + + public static UserEncryptionService getInstance() { + return LazyInitialisation.INSTANCE; + } + + @Override + public List getDecryptedFields(Map userMap) { + List decryptedFields = new ArrayList<>(); + if (ProjectUtil.isEmailvalid((String) userMap.get(JsonKey.EMAIL))) { + decryptedFields.add(JsonKey.EMAIL); + } + + if (PhoneValidator.validatePhoneNumber((String) userMap.get(JsonKey.PHONE))) { + decryptedFields.add(JsonKey.PHONE); + } + List otherDecryptedFields = getOtherDecryptedFields(userMap); + decryptedFields.addAll(otherDecryptedFields); + return decryptedFields; + } + + @Override + public List getEncryptedFields(Map userMap) { + List encryptedFields = new ArrayList<>(); + if (StringUtils.isNotEmpty((String) userMap.get(JsonKey.EMAIL)) + && !ProjectUtil.isEmailvalid((String) userMap.get(JsonKey.EMAIL))) { + encryptedFields.add(JsonKey.EMAIL); + } + + if (StringUtils.isNotEmpty((String) userMap.get(JsonKey.PHONE)) + && !PhoneValidator.validatePhoneNumber((String) userMap.get(JsonKey.PHONE))) { + encryptedFields.add(JsonKey.PHONE); + } + + List otherEncryptedFields = getOtherEncryptedFields(userMap); + encryptedFields.addAll(otherEncryptedFields); + return encryptedFields; + } + + private List getOtherEncryptedFields(Map userMap) { + List decryptedFields = new ArrayList<>(); + for (String field : userEncryptedFieldList) { + try { + if (StringUtils.isNotBlank((String) userMap.get(field))) { + decryptionService.decryptData((String) userMap.get(field), true); + decryptedFields.add(field); + } + } catch (ProjectCommonException e) { + ProjectLogger.log( + "UserEncryptionServiceImpl:getOtherEncryptedFields: Field is not encrypted " + field, + LoggerEnum.INFO.name()); + } + } + return decryptedFields; + } + + private List getOtherDecryptedFields(Map userMap) { + List decryptedFields = new ArrayList<>(); + for (String field : userEncryptedFieldList) { + try { + if (StringUtils.isNotBlank((String) userMap.get(field)) + && ((String) userMap.get(field)) + .equals(decryptionService.decryptData((String) userMap.get(field)))) { + decryptedFields.add(field); + } + } catch (Exception e) { + decryptedFields.add(field); + } + } + return decryptedFields; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/impl/UserServiceImpl.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/impl/UserServiceImpl.java new file mode 100644 index 0000000000..32e503b10e --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/service/impl/UserServiceImpl.java @@ -0,0 +1,533 @@ +package org.sunbird.user.service.impl; + +import akka.actor.ActorRef; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.actorutil.systemsettings.SystemSettingClient; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.*; +import org.sunbird.common.models.util.ProjectUtil.EsType; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.models.util.datasecurity.impl.DefaultDecryptionServiceImpl; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.AdminUtilHandler; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.models.adminutil.AdminUtilRequestData; +import org.sunbird.models.systemsetting.SystemSetting; +import org.sunbird.models.user.User; +import org.sunbird.user.dao.UserDao; +import org.sunbird.user.dao.UserExternalIdentityDao; +import org.sunbird.user.dao.impl.UserDaoImpl; +import org.sunbird.user.dao.impl.UserExternalIdentityDaoImpl; +import org.sunbird.user.service.UserService; +import scala.concurrent.Future; + +public class UserServiceImpl implements UserService { + + private static DecryptionService decryptionService = new DefaultDecryptionServiceImpl(); + private EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + private CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static UserDao userDao = UserDaoImpl.getInstance(); + private static UserService userService = null; + private UserExternalIdentityDao userExtIdentityDao = new UserExternalIdentityDaoImpl(); + private Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + private static final int GENERATE_USERNAME_COUNT = 10; + private ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + + public static UserService getInstance() { + if (userService == null) { + userService = new UserServiceImpl(); + } + return userService; + } + + @SuppressWarnings("unchecked") + @Override + public Map esGetUserOrg(String userId, String orgId) { + Map filters = new HashMap<>(); + filters.put(StringFormatter.joinByDot(JsonKey.ORGANISATIONS, JsonKey.ORGANISATION_ID), orgId); + filters.put(StringFormatter.joinByDot(JsonKey.ORGANISATIONS, JsonKey.USER_ID), userId); + Map map = new HashMap<>(); + map.put(JsonKey.FILTERS, filters); + SearchDTO searchDto = Util.createSearchDto(map); + Future> resultF = + esUtil.search(searchDto, ProjectUtil.EsType.user.getTypeName()); + Map result = + (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + List> userMapList = (List>) result.get(JsonKey.CONTENT); + if (CollectionUtils.isNotEmpty(userMapList)) { + Map userMap = userMapList.get(0); + return decryptionService.decryptData(userMap); + } else { + return Collections.EMPTY_MAP; + } + } + + @Override + public User getUserById(String userId) { + User user = userDao.getUserById(userId); + if (null == user) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + return user; + } + + // This function is called during createUserV4 and update of users. + @Override + public void validateUserId(Request request, String managedById) { + String userId = null; + String ctxtUserId = (String) request.getContext().get(JsonKey.USER_ID); + String managedForId = (String) request.getContext().get(JsonKey.MANAGED_FOR); + if (StringUtils.isEmpty(ctxtUserId)) { + // In case of create, pick the ctxUserId from a different header + // TODO: Unify and rely on one header for the context user identification + ctxtUserId = (String) request.getContext().get(JsonKey.REQUESTED_BY); + } else { + userId = userExtIdentityDao.getUserId(request); + } + ProjectLogger.log( + "validateUserId :: ctxtUserId : " + + ctxtUserId + + " userId: " + + userId + + " managedById: " + + managedById + + " managedForId: " + + managedForId, + LoggerEnum.INFO); + // LIUA token is validated when LIUA is updating own account details or LIUA token is validated + // when updating MUA details + if ((StringUtils.isNotEmpty(managedForId) && !managedForId.equals(userId)) + || (StringUtils.isEmpty(managedById) + && (!StringUtils.isBlank(userId) && !userId.equals(ctxtUserId))) // UPDATE + || (StringUtils.isNotEmpty(managedById) + && !(ctxtUserId.equals(managedById)))) // CREATE NEW USER/ UPDATE MUA { + throw new ProjectCommonException( + ResponseCode.unAuthorized.getErrorCode(), + ResponseCode.unAuthorized.getErrorMessage(), + ResponseCode.UNAUTHORIZED.getResponseCode()); + } + + @Override + public void syncUserProfile( + String userId, Map userDataMap, Map userPrivateDataMap) { + esUtil.save(ProjectUtil.EsType.userprofilevisibility.getTypeName(), userId, userPrivateDataMap); + esUtil.save(ProjectUtil.EsType.user.getTypeName(), userId, userDataMap); + } + + @Override + public Map esGetPublicUserProfileById(String userId) { + Future> esResultF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId); + Map esResult = + (Map) ElasticSearchHelper.getResponseFromFuture(esResultF); + if (esResult == null || esResult.size() == 0) { + throw new ProjectCommonException( + ResponseCode.userNotFound.getErrorCode(), + ResponseCode.userNotFound.getErrorMessage(), + ResponseCode.RESOURCE_NOT_FOUND.getResponseCode()); + } + return esResult; + } + + @Override + public Map esGetPrivateUserProfileById(String userId) { + Future> resultF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.userprofilevisibility.getTypeName(), userId); + return (Map) ElasticSearchHelper.getResponseFromFuture(resultF); + } + + @Override + public String getValidatedCustodianOrgId(Map userMap, ActorRef actorRef) { + String custodianOrgId = ""; + try { + SystemSettingClient client = SystemSettingClientImpl.getInstance(); + SystemSetting systemSetting = + client.getSystemSettingByField(actorRef, JsonKey.CUSTODIAN_ORG_ID); + if (null != systemSetting && StringUtils.isNotBlank(systemSetting.getValue())) { + custodianOrgId = systemSetting.getValue(); + } + } catch (Exception ex) { + ProjectLogger.log( + "UserUtil:getValidatedCustodianOrgId: Exception occurred with error message = " + + ex.getMessage(), + ex); + ProjectCommonException.throwServerErrorException( + ResponseCode.errorSystemSettingNotFound, + ProjectUtil.formatMessage( + ResponseCode.errorSystemSettingNotFound.getErrorMessage(), JsonKey.CUSTODIAN_ORG_ID)); + } + Map custodianOrg = null; + if (StringUtils.isNotBlank(custodianOrgId)) { + Future> custodianOrgF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.organisation.getTypeName(), custodianOrgId); + custodianOrg = (Map) ElasticSearchHelper.getResponseFromFuture(custodianOrgF); + if (MapUtils.isNotEmpty(custodianOrg)) { + + if (null != custodianOrg.get(JsonKey.STATUS)) { + int status = (int) custodianOrg.get(JsonKey.STATUS); + if (1 != status) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorInactiveCustodianOrg); + } + } else { + ProjectCommonException.throwClientErrorException(ResponseCode.errorInactiveCustodianOrg); + } + } else { + ProjectCommonException.throwServerErrorException( + ResponseCode.errorSystemSettingNotFound, + ProjectUtil.formatMessage( + ResponseCode.errorSystemSettingNotFound.getErrorMessage(), + JsonKey.CUSTODIAN_ORG_ID)); + } + } else { + ProjectCommonException.throwServerErrorException( + ResponseCode.errorSystemSettingNotFound, + ProjectUtil.formatMessage( + ResponseCode.errorSystemSettingNotFound.getErrorMessage(), JsonKey.CUSTODIAN_ORG_ID)); + } + userMap.put(JsonKey.ROOT_ORG_ID, custodianOrgId); + userMap.put(JsonKey.CHANNEL, custodianOrg.get(JsonKey.CHANNEL)); + return custodianOrgId; + } + + @Override + public String getRootOrgIdFromChannel(String channel) { + + Map filters = new HashMap<>(); + filters.put(JsonKey.IS_ROOT_ORG, true); + if (StringUtils.isNotBlank(channel)) { + filters.put(JsonKey.CHANNEL, channel); + } else { + // If channel value is not coming in request then read the default channel value provided from + // ENV. + if (StringUtils.isNotBlank(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_DEFAULT_CHANNEL))) { + filters.put(JsonKey.CHANNEL, ProjectUtil.getConfigValue(JsonKey.SUNBIRD_DEFAULT_CHANNEL)); + } else { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.CHANNEL), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + SearchDTO searchDTO = new SearchDTO(); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + Future> esResultF = + esUtil.search(searchDTO, EsType.organisation.getTypeName()); + Map esResult = + (Map) ElasticSearchHelper.getResponseFromFuture(esResultF); + if (MapUtils.isNotEmpty(esResult) + && CollectionUtils.isNotEmpty((List) esResult.get(JsonKey.CONTENT))) { + Map esContent = + ((List>) esResult.get(JsonKey.CONTENT)).get(0); + if (null != esContent.get(JsonKey.STATUS)) { + int status = (int) esContent.get(JsonKey.STATUS); + if (1 != status) { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorInactiveOrg, + ProjectUtil.formatMessage( + ResponseCode.errorInactiveOrg.getErrorMessage(), JsonKey.CHANNEL, channel)); + } + } else { + ProjectCommonException.throwClientErrorException( + ResponseCode.errorInactiveOrg, + ProjectUtil.formatMessage( + ResponseCode.errorInactiveOrg.getErrorMessage(), JsonKey.CHANNEL, channel)); + } + return (String) esContent.get(JsonKey.ID); + } else { + if (StringUtils.isNotBlank(channel)) { + throw new ProjectCommonException( + ResponseCode.invalidParameterValue.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.invalidParameterValue.getErrorMessage(), channel, JsonKey.CHANNEL), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.CHANNEL), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } + + @Override + public String getCustodianChannel(Map userMap, ActorRef actorRef) { + String channel = (String) userMap.get(JsonKey.CHANNEL); + if (StringUtils.isBlank(channel)) { + try { + Map configSettingMap = DataCacheHandler.getConfigSettings(); + channel = configSettingMap.get(JsonKey.CUSTODIAN_ORG_CHANNEL); + if (StringUtils.isBlank(channel)) { + SystemSettingClient client = SystemSettingClientImpl.getInstance(); + SystemSetting custodianOrgChannelSetting = + client.getSystemSettingByField(actorRef, JsonKey.CUSTODIAN_ORG_CHANNEL); + if (custodianOrgChannelSetting != null + && StringUtils.isNotBlank(custodianOrgChannelSetting.getValue())) { + configSettingMap.put( + custodianOrgChannelSetting.getId(), custodianOrgChannelSetting.getValue()); + channel = custodianOrgChannelSetting.getValue(); + } + } + } catch (Exception ex) { + ProjectLogger.log( + "Util:getCustodianChannel: Exception occurred while fetching custodian channel from system setting.", + ex); + } + } + if (StringUtils.isBlank(channel)) { + channel = ProjectUtil.getConfigValue(JsonKey.SUNBIRD_DEFAULT_CHANNEL); + userMap.put(JsonKey.CHANNEL, channel); + } + if (StringUtils.isBlank(channel)) { + throw new ProjectCommonException( + ResponseCode.mandatoryParamsMissing.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.mandatoryParamsMissing.getErrorMessage(), JsonKey.CHANNEL), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + return channel; + } + + @Override + public void validateUploader(Request request) { + // uploader and user should belong to same root org, + // then only will allow to update user profile details. + Map userMap = request.getRequest(); + String userId = (String) userMap.get(JsonKey.USER_ID); + String uploaderUserId = (String) userMap.get(JsonKey.UPDATED_BY); + User uploader = userService.getUserById(uploaderUserId); + User user = userService.getUserById(userId); + if (!user.getRootOrgId().equalsIgnoreCase(uploader.getRootOrgId())) { + ProjectCommonException.throwUnauthorizedErrorException(); + } + } + + @SuppressWarnings("unchecked") + @Override + public Map getUserByUsername(String userName) { + Response response = + cassandraOperation.getRecordsByIndexedProperty( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), JsonKey.USERNAME, userName); + List> userList = + (List>) response.getResult().get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(userList)) { + return userList.get(0); + } + return null; + } + + @Override + public List getEncryptedList(List dataList) { + List encryptedDataList = new ArrayList<>(); + for (String data : dataList) { + String encData = ""; + try { + encData = encryptionService.encryptData(data); + } catch (Exception e) { + ProjectLogger.log( + "UserServiceImpl:getEncryptedDataList: Exception occurred with error message = " + + e.getMessage()); + } + if (StringUtils.isNotBlank(encData)) { + encryptedDataList.add(encData); + } + } + return encryptedDataList; + } + + @Override + public List generateUsernames(String name, List excludedUsernames) { + if (name == null || name.isEmpty()) return null; + name = Slug.makeSlug(name, true); + int numOfDigitsToAppend = + Integer.valueOf(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_USERNAME_NUM_DIGITS).trim()); + HashSet userNameSet = new HashSet<>(); + int totalUserNameGenerated = 0; + String nameLowercase = name.toLowerCase().replaceAll("\\-+", ""); + while (totalUserNameGenerated < GENERATE_USERNAME_COUNT) { + int numberSuffix = getRandomFixedLengthInteger(numOfDigitsToAppend); + + StringBuilder userNameSB = new StringBuilder(); + userNameSB.append(nameLowercase).append(numberSuffix); + String generatedUsername = userNameSB.toString(); + + if (!userNameSet.contains(generatedUsername) + && !excludedUsernames.contains(generatedUsername)) { + userNameSet.add(generatedUsername); + totalUserNameGenerated += 1; + } + } + return new ArrayList<>(userNameSet); + } + + private int getRandomFixedLengthInteger(int numDigits) { + int min = (int) Math.pow(10, numDigits - 1); + int max = ((int) Math.pow(10, numDigits)) - 1; + int randomNum = (int) (Math.random() * ((max - min) + 1)) + min; + return randomNum; + } + + @SuppressWarnings("unchecked") + @Override + public List> esSearchUserByFilters(Map filters) { + SearchDTO searchDTO = new SearchDTO(); + + List list = new ArrayList<>(); + list.add(JsonKey.ID); + list.add(JsonKey.USERNAME); + + searchDTO.setFields(list); + searchDTO.getAdditionalProperties().put(JsonKey.FILTERS, filters); + + Future> esResultF = esUtil.search(searchDTO, EsType.user.getTypeName()); + Map esResult = + (Map) ElasticSearchHelper.getResponseFromFuture(esResultF); + + return (List>) esResult.get(JsonKey.CONTENT); + } + + @SuppressWarnings("unchecked") + @Override + public boolean checkUsernameUniqueness(String username, boolean isEncrypted) { + try { + if (!isEncrypted) username = encryptionService.encryptData(username); + } catch (Exception e) { + ProjectLogger.log( + "UserServiceImpl:checkUsernameUniqueness: Exception occurred with error message = " + + e.getMessage(), + e); + ProjectCommonException.throwServerErrorException(ResponseCode.userDataEncryptionError); + } + + Response result = + cassandraOperation.getRecordsByIndexedProperty( + usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), JsonKey.USERNAME, username); + + List> userMapList = + (List>) result.get(JsonKey.RESPONSE); + + if (CollectionUtils.isNotEmpty(userMapList)) { + return false; + } + return true; + } + + @Override + public String getCustodianOrgId(ActorRef actorRef) { + String custodianOrgId = ""; + try { + SystemSettingClient client = SystemSettingClientImpl.getInstance(); + SystemSetting systemSetting = + client.getSystemSettingByField(actorRef, JsonKey.CUSTODIAN_ORG_ID); + if (null != systemSetting && StringUtils.isNotBlank(systemSetting.getValue())) { + custodianOrgId = systemSetting.getValue(); + } + } catch (Exception ex) { + ProjectLogger.log( + "UserServiceImpl:getCustodianOrgId: Exception occurred with error message = " + + ex.getMessage(), + ex); + ProjectCommonException.throwServerErrorException( + ResponseCode.errorSystemSettingNotFound, + ProjectUtil.formatMessage( + ResponseCode.errorSystemSettingNotFound.getErrorMessage(), JsonKey.CUSTODIAN_ORG_ID)); + } + return custodianOrgId; + } + + /** + * Fetch encrypted token list from admin utils + * + * @param parentId + * @param respList + * @return encryptedTokenList + */ + public Map fetchEncryptedToken( + String parentId, List> respList) { + Map encryptedTokenList = null; + try { + // create AdminUtilRequestData list of managedUserId and parentId + List managedUsers = createManagedUserList(parentId, respList); + // Fetch encrypted token list from admin utils + encryptedTokenList = + AdminUtilHandler.fetchEncryptedToken( + AdminUtilHandler.prepareAdminUtilPayload(managedUsers)); + } catch (ProjectCommonException pe) { + throw pe; + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.unableToParseData.getErrorCode(), + ResponseCode.unableToParseData.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + return encryptedTokenList; + } + + /** + * Append encrypted token to the user list + * + * @param encryptedTokenList + * @param respList + */ + public void appendEncryptedToken( + Map encryptedTokenList, List> respList) { + ArrayList> data = + (ArrayList>) encryptedTokenList.get(JsonKey.DATA); + for (Object object : data) { + Map tempMap = (Map) object; + respList + .stream() + .filter(o -> o.get(JsonKey.ID).equals(tempMap.get(JsonKey.SUB))) + .forEach( + o -> { + o.put(JsonKey.MANAGED_TOKEN, tempMap.get(JsonKey.TOKEN)); + }); + } + } + + /** + * Create managed user user list with parentId(managedBY) and childId(managedUser) in admin util + * request format + * + * @param parentId + * @param respList + * @return reqData List + */ + private List createManagedUserList( + String parentId, List> respList) { + List reqData = + respList + .stream() + .map(p -> new AdminUtilRequestData(parentId, (String) p.get(JsonKey.ID))) + .collect(Collectors.toList()); + reqData.forEach(System.out::println); + return reqData; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/KafkaConfigConstants.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/KafkaConfigConstants.java new file mode 100644 index 0000000000..f68f6741e3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/KafkaConfigConstants.java @@ -0,0 +1,9 @@ +package org.sunbird.user.util; + +public class KafkaConfigConstants { + + public static final String SUNBIRD_USER_CERT_KAFKA_SERVICE_CONFIG = + "sunbird_user_cert_kafka_servers_config"; + public static final String SUNBIRD_USER_CERT_KAFKA_TOPIC = "sunbird_user_cert_kafka_topic"; + public static final String KAFKA_CLIENT_USER_CERT_PRODUCER = "KafkaClientUserCertProducer"; +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/MigrationUtils.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/MigrationUtils.java new file mode 100644 index 0000000000..005452279b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/MigrationUtils.java @@ -0,0 +1,150 @@ +package org.sunbird.user.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.sql.Timestamp; +import java.util.*; +import org.sunbird.bean.ClaimStatus; +import org.sunbird.bean.ShadowUser; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.helper.ServiceFactory; + +public class MigrationUtils { + + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static ObjectMapper mapper = new ObjectMapper(); + + /** + * this method will search user in userids attribute in shadow_user table + * + * @param userId + * @return + */ + public static ShadowUser getRecordByUserId(String userId) { + ShadowUser shadowUser = null; + Response response = + cassandraOperation.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USERIDS, userId); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + shadowUser = + mapper.convertValue( + ((List) response.getResult().get(JsonKey.RESPONSE)).get(0), ShadowUser.class); + } + return shadowUser; + } + + /** + * this method will update the record in the shadow_user table + * + * @param propertiesMap + * @param channel + * @param userExtId + */ + public static boolean updateRecord( + Map propertiesMap, String channel, String userExtId) { + Map compositeKeysMap = new HashMap<>(); + compositeKeysMap.put(JsonKey.USER_EXT_ID, userExtId); + compositeKeysMap.put(JsonKey.CHANNEL, channel); + Response response = + cassandraOperation.updateRecord( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, propertiesMap, compositeKeysMap); + ProjectLogger.log( + "MigrationUtils:updateRecord:update in cassandra with userExtId" + + userExtId + + ":and response is:" + + response, + LoggerEnum.INFO.name()); + return true; + } + + /** + * this method will mark the user rejected(2) in shadow_user table if the user doesn't want to + * migrate + * + * @param shadowUser + */ + public static boolean markUserAsRejected(ShadowUser shadowUser) { + Map propertiesMap = new HashMap<>(); + propertiesMap.put(JsonKey.CLAIM_STATUS, ClaimStatus.REJECTED.getValue()); + propertiesMap.put(JsonKey.UPDATED_ON, new Timestamp(System.currentTimeMillis())); + boolean isRecordUpdated = + updateRecord(propertiesMap, shadowUser.getChannel(), shadowUser.getUserExtId()); + ProjectLogger.log( + "MigrationUtils:markUserAsRejected:update in cassandra with userExtId" + + shadowUser.getUserExtId(), + LoggerEnum.INFO.name()); + return isRecordUpdated; + } + /** + * this method will mark the user Failed(3) in shadow_user table if the user doesn't want to + * migrate + * + * @param shadowUser + */ + public static boolean updateClaimStatus(ShadowUser shadowUser, int claimStatus) { + Map propertiesMap = new WeakHashMap<>(); + propertiesMap.put(JsonKey.CLAIM_STATUS, claimStatus); + propertiesMap.put(JsonKey.UPDATED_ON, new Timestamp(System.currentTimeMillis())); + updateRecord(propertiesMap, shadowUser.getChannel(), shadowUser.getUserExtId()); + ProjectLogger.log( + "MigrationUtils:markUserAsRejected:update in cassandra with userExtId" + + shadowUser.getUserExtId(), + LoggerEnum.INFO.name()); + return true; + } + + /** + * this method will return all the ELIGIBLE(claimStatus 6) user with same userId and properties + * from shadow_user table + * + * @param userId + * @param propsMap + * @return + */ + public static List getEligibleUsersById(String userId, Map propsMap) { + List shadowUsersList = new ArrayList<>(); + Response response = + cassandraOperation.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USERIDS, userId, propsMap); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + ((List) response.getResult().get(JsonKey.RESPONSE)) + .stream() + .forEach( + shadowMap -> { + ShadowUser shadowUser = mapper.convertValue(shadowMap, ShadowUser.class); + if (shadowUser.getClaimStatus() == ClaimStatus.ELIGIBLE.getValue()) { + shadowUsersList.add(shadowUser); + } + }); + } + return shadowUsersList; + } + /** + * this method will return all the ELIGIBLE(claimStatus 6) user with same userId from shadow_user + * table + * + * @param userId + * @return + */ + public static List getEligibleUsersById(String userId) { + List shadowUsersList = new ArrayList<>(); + Response response = + cassandraOperation.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USERIDS, userId); + if (!((List) response.getResult().get(JsonKey.RESPONSE)).isEmpty()) { + ((List) response.getResult().get(JsonKey.RESPONSE)) + .stream() + .forEach( + shadowMap -> { + ShadowUser shadowUser = mapper.convertValue(shadowMap, ShadowUser.class); + if (shadowUser.getClaimStatus() == ClaimStatus.ELIGIBLE.getValue()) { + shadowUsersList.add(shadowUser); + } + }); + } + return shadowUsersList; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserActorOperations.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserActorOperations.java new file mode 100644 index 0000000000..6f4c6f5cf0 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserActorOperations.java @@ -0,0 +1,31 @@ +package org.sunbird.user.util; + +public enum UserActorOperations { + INSERT_USER_ADDRESS("insertUserAddress"), + UPDATE_USER_ADDRESS("updateUserAddress"), + INSERT_USER_EDUCATION("insertUserEducation"), + UPDATE_USER_EDUCATION("updateUserEducation"), + INSERT_USER_JOB_PROFILE("insertUserJobProfile"), + UPDATE_USER_JOB_PROFILE("updateUserJobProfile"), + INSERT_USER_ORG_DETAILS("insertUserOrgDetails"), + UPDATE_USER_ORG_DETAILS("updateUserOrgDetails"), + UPSERT_USER_EXTERNAL_IDENTITY_DETAILS("upsertUserExternalIdentityDetails"), + PROCESS_ONBOARDING_MAIL_AND_SMS("processOnBoardingMailAndSms"), + PROCESS_PASSWORD_RESET_MAIL_AND_SMS("processPasswordResetMailAndSms"), + SAVE_USER_ATTRIBUTES("saveUserAttributes"), + UPSERT_USER_DETAILS_TO_ES("upsertUserDetailsToES"), + UPSERT_USER_ADDRESS_TO_ES("upsertUserAddressToES"), + UPSERT_USER_EDUCATION_TO_ES("upsertUserEducationToES"), + UPSERT_USER_JOB_PROFILE_TO_ES("upsertUserJobProfileToES"), + UPSERT_USER_ORG_DETAILS_TO_ES("upsertUserOrgDetailsToES"); + + private String value; + + UserActorOperations(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserConstants.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserConstants.java new file mode 100644 index 0000000000..075a43cebe --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserConstants.java @@ -0,0 +1,9 @@ +package org.sunbird.user.util; + +public final class UserConstants { + + public static final String SIGNUP_TYPE = "signupType"; + public static final String USER_TYPE = "userType"; + + private UserConstants() {} +} diff --git a/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserUtil.java b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserUtil.java new file mode 100644 index 0000000000..2c23f0b292 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/main/java/org/sunbird/user/util/UserUtil.java @@ -0,0 +1,812 @@ +package org.sunbird.user.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Random; +import java.util.WeakHashMap; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.models.util.PropertiesCache; +import org.sunbird.common.models.util.datasecurity.DataMaskingService; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.responsecode.ResponseMessage; +import org.sunbird.common.services.ProfileCompletenessService; +import org.sunbird.common.services.impl.ProfileCompletenessFactory; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.SocialMediaType; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.learner.util.Util.DbInfo; +import org.sunbird.models.user.User; +import org.sunbird.services.sso.SSOManager; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.user.dao.UserExternalIdentityDao; +import org.sunbird.user.dao.impl.UserExternalIdentityDaoImpl; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; +import scala.concurrent.Future; + +public class UserUtil { + + private static CassandraOperation cassandraOperation = ServiceFactory.getInstance(); + private static EncryptionService encryptionService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getEncryptionServiceInstance( + null); + private static DbInfo userDb = Util.dbInfoMap.get(JsonKey.USER_DB); + private static ObjectMapper mapper = new ObjectMapper(); + private static SSOManager ssoManager = SSOServiceFactory.getInstance(); + private static PropertiesCache propertiesCache = PropertiesCache.getInstance(); + private static DataMaskingService maskingService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getMaskingServiceInstance( + null); + private static DecryptionService decService = + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.getDecryptionServiceInstance( + null); + private static UserService userService = UserServiceImpl.getInstance(); + private static UserExternalIdentityDao userExternalIdentityDao = + new UserExternalIdentityDaoImpl(); + private static ElasticSearchService esUtil = EsClientFactory.getInstance(JsonKey.REST); + static Random rand = new Random(System.nanoTime()); + private static final String[] alphabet = + new String[] { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", + "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" + }; + + private static String stripChars = "0"; + private static BigDecimal largePrimeNumber = new BigDecimal(1679979167); + + private UserUtil() {} + + @SuppressWarnings("unchecked") + public static void checkPhoneUniqueness(User user, String opType) { + // Get Phone configuration if not found , by default phone will be unique across + // the application + String phoneSetting = DataCacheHandler.getConfigSettings().get(JsonKey.PHONE_UNIQUE); + if (StringUtils.isNotBlank(phoneSetting) && Boolean.parseBoolean(phoneSetting)) { + String phone = user.getPhone(); + if (StringUtils.isNotBlank(phone)) { + try { + phone = encryptionService.encryptData(phone); + } catch (Exception e) { + ProjectLogger.log("Exception occurred while encrypting phone number ", e); + } + Response result = + cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), (JsonKey.PHONE), phone); + List> userMapList = + (List>) result.get(JsonKey.RESPONSE); + if (!userMapList.isEmpty()) { + if (opType.equalsIgnoreCase(JsonKey.CREATE)) { + ProjectCommonException.throwClientErrorException(ResponseCode.PhoneNumberInUse, null); + } else { + Map userMap = userMapList.get(0); + if (!(((String) userMap.get(JsonKey.ID)).equalsIgnoreCase(user.getId()))) { + ProjectCommonException.throwClientErrorException(ResponseCode.PhoneNumberInUse, null); + } + } + } + } + } + } + + @SuppressWarnings("unchecked") + public static void checkPhoneUniqueness(String phone) { + // Get Phone configuration if not found , by default phone will be unique across + // the application + String phoneSetting = DataCacheHandler.getConfigSettings().get(JsonKey.PHONE_UNIQUE); + if (StringUtils.isNotBlank(phoneSetting) && Boolean.parseBoolean(phoneSetting)) { + if (StringUtils.isNotBlank(phone)) { + try { + phone = encryptionService.encryptData(phone); + } catch (Exception e) { + ProjectLogger.log("Exception occurred while encrypting phone number ", e); + } + Response result = + cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), (JsonKey.PHONE), phone); + List> userMapList = + (List>) result.get(JsonKey.RESPONSE); + if (!userMapList.isEmpty()) { + ProjectCommonException.throwClientErrorException(ResponseCode.PhoneNumberInUse, null); + } + } + } + } + + public static boolean identifierExists(String type, String value) { + + if (StringUtils.isNotBlank(value)) { + try { + value = encryptionService.encryptData(value); + } catch (Exception e) { + ProjectLogger.log("Exception occurred while encrypting email/phone", e); + } + Response result = + cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), type, value); + @SuppressWarnings("unchecked") + List> userMapList = + (List>) result.get(JsonKey.RESPONSE); + return !userMapList.isEmpty(); + } else { + return false; + } + } + + public static void checkEmailUniqueness(String email) { + // Get Phone configuration if not found , by default phone will be unique across + // the application + String emailSetting = DataCacheHandler.getConfigSettings().get(JsonKey.EMAIL_UNIQUE); + if (StringUtils.isNotBlank(emailSetting) && Boolean.parseBoolean(emailSetting)) { + if (StringUtils.isNotBlank(email)) { + try { + email = encryptionService.encryptData(email); + } catch (Exception e) { + ProjectLogger.log("Exception occurred while encrypting phone number ", e); + } + Response result = + cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), (JsonKey.EMAIL), email); + List> userMapList = + (List>) result.get(JsonKey.RESPONSE); + if (!userMapList.isEmpty()) { + ProjectCommonException.throwClientErrorException( + ResponseCode.emailAlreadyExistError, null); + } + } + } + } + + public static Map validateExternalIdsAndReturnActiveUser( + Map userMap) { + String extId = (String) userMap.get(JsonKey.EXTERNAL_ID); + String provider = (String) userMap.get(JsonKey.EXTERNAL_ID_PROVIDER); + String idType = (String) userMap.get(JsonKey.EXTERNAL_ID_TYPE); + Map user = null; + if ((StringUtils.isBlank((String) userMap.get(JsonKey.USER_ID)) + && StringUtils.isBlank((String) userMap.get(JsonKey.ID))) + && StringUtils.isNotEmpty(extId) + && StringUtils.isNotEmpty(provider) + && StringUtils.isNotEmpty(idType)) { + user = getUserFromExternalId(userMap); + if (MapUtils.isEmpty(user)) { + ProjectCommonException.throwClientErrorException( + ResponseCode.externalIdNotFound, + ProjectUtil.formatMessage( + ResponseCode.externalIdNotFound.getErrorMessage(), extId, idType, provider)); + } + } else if (StringUtils.isNotBlank((String) userMap.get(JsonKey.USER_ID)) + || StringUtils.isNotBlank((String) userMap.get(JsonKey.ID))) { + String userId = + (StringUtils.isNotBlank((String) userMap.get(JsonKey.USER_ID))) + ? ((String) userMap.get(JsonKey.USER_ID)) + : ((String) userMap.get(JsonKey.ID)); + Future> userF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId); + user = (Map) ElasticSearchHelper.getResponseFromFuture(userF); + if (MapUtils.isEmpty(user)) { + ProjectCommonException.throwClientErrorException(ResponseCode.userNotFound, null); + } + } + if (MapUtils.isNotEmpty(user)) { + if (null != user.get(JsonKey.IS_DELETED) && (boolean) (user.get(JsonKey.IS_DELETED))) { + ProjectCommonException.throwClientErrorException(ResponseCode.inactiveUser, null); + } + // In request if userId or id not present (when you are sending only externalIds to verify the + // user) + if (StringUtils.isBlank((String) userMap.get(JsonKey.USER_ID))) { + userMap.put(JsonKey.USER_ID, user.get(JsonKey.ID)); + } + if (StringUtils.isBlank((String) userMap.get(JsonKey.ID))) { + userMap.put(JsonKey.ID, user.get(JsonKey.ID)); + } + } + return user; + } + + @SuppressWarnings("unchecked") + public static Map getUserFromExternalId(Map userMap) { + Map user = null; + String userId = getUserIdFromExternalId(userMap); + if (!StringUtils.isEmpty(userId)) { + Future> userF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId); + user = (Map) ElasticSearchHelper.getResponseFromFuture(userF); + } + return user; + } + + public static String getUserIdFromExternalId(Map userMap) { + Request request = new Request(); + request.setRequest(userMap); + return userExternalIdentityDao.getUserId(request); + } + + @SuppressWarnings("unchecked") + public static void checkEmailUniqueness(User user, String opType) { + + String emailSetting = DataCacheHandler.getConfigSettings().get(JsonKey.EMAIL_UNIQUE); + if (StringUtils.isNotBlank(emailSetting) && Boolean.parseBoolean(emailSetting)) { + String email = user.getEmail(); + if (StringUtils.isNotBlank(email)) { + try { + email = encryptionService.encryptData(email); + } catch (Exception e) { + ProjectLogger.log("Exception occurred while encrypting email:", e); + } + Response result = + cassandraOperation.getRecordsByIndexedProperty( + userDb.getKeySpace(), userDb.getTableName(), (JsonKey.EMAIL), email); + List> userMapList = + (List>) result.get(JsonKey.RESPONSE); + if (!userMapList.isEmpty()) { + if (opType.equalsIgnoreCase(JsonKey.CREATE)) { + ProjectCommonException.throwClientErrorException(ResponseCode.emailInUse, null); + } else { + Map userMap = userMapList.get(0); + if (!(((String) userMap.get(JsonKey.ID)).equalsIgnoreCase(user.getId()))) { + ProjectCommonException.throwClientErrorException(ResponseCode.emailInUse, null); + } + } + } + } + } + } + + public static void validateUserPhoneEmailAndWebPages(User user, String operationType) { + checkPhoneUniqueness(user, operationType); + checkEmailUniqueness(user, operationType); + if (CollectionUtils.isNotEmpty(user.getWebPages())) { + SocialMediaType.validateSocialMedia(user.getWebPages()); + } + } + + public static String getEncryptedData(String value) { + try { + return encryptionService.encryptData(value); + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + public static List> copyAndConvertExternalIdsToLower( + List> externalIds) { + List> list = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(externalIds)) { + storeOriginalExternalIdsValue(externalIds); + list = convertExternalIdsValueToLowerCase(externalIds); + } + return list; + } + + public static void storeOriginalExternalIdsValue(List> externalIds) { + externalIds.forEach( + externalIdMap -> { + externalIdMap.put(JsonKey.ORIGINAL_EXTERNAL_ID, externalIdMap.get(JsonKey.ID)); + externalIdMap.put(JsonKey.ORIGINAL_PROVIDER, externalIdMap.get(JsonKey.PROVIDER)); + externalIdMap.put(JsonKey.ORIGINAL_ID_TYPE, externalIdMap.get(JsonKey.ID_TYPE)); + }); + } + + public static List> convertExternalIdsValueToLowerCase( + List> externalIds) { + ConvertValuesToLowerCase mapper = + s -> { + s.put(JsonKey.ID, s.get(JsonKey.ID).toLowerCase()); + s.put(JsonKey.PROVIDER, s.get(JsonKey.PROVIDER).toLowerCase()); + s.put(JsonKey.ID_TYPE, s.get(JsonKey.ID_TYPE).toLowerCase()); + return s; + }; + return externalIds.stream().map(s -> mapper.convertToLowerCase(s)).collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + public static void checkExternalIdUniqueness(User user, String operation) { + if (CollectionUtils.isNotEmpty(user.getExternalIds())) { + for (Map externalId : user.getExternalIds()) { + if (StringUtils.isNotBlank(externalId.get(JsonKey.ID)) + && StringUtils.isNotBlank(externalId.get(JsonKey.PROVIDER)) + && StringUtils.isNotBlank(externalId.get(JsonKey.ID_TYPE))) { + Map externalIdReq = new HashMap<>(); + externalIdReq.put(JsonKey.PROVIDER, externalId.get(JsonKey.PROVIDER)); + externalIdReq.put(JsonKey.ID_TYPE, externalId.get(JsonKey.ID_TYPE)); + externalIdReq.put(JsonKey.EXTERNAL_ID, externalId.get(JsonKey.ID)); + Response response = + cassandraOperation.getRecordsByProperties( + JsonKey.SUNBIRD, JsonKey.USR_EXT_IDNT_TABLE, externalIdReq); + List> externalIdsRecord = + (List>) response.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(externalIdsRecord)) { + if (JsonKey.CREATE.equalsIgnoreCase(operation)) { + throwUserAlreadyExistsException( + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)); + } else if (JsonKey.UPDATE.equalsIgnoreCase(operation)) { + // If end user will try to add,edit or remove other user extIds throw exception + String userId = (String) externalIdsRecord.get(0).get(JsonKey.USER_ID); + if (!(user.getUserId().equalsIgnoreCase(userId))) { + if (JsonKey.ADD.equalsIgnoreCase(externalId.get(JsonKey.OPERATION)) + || StringUtils.isBlank(externalId.get(JsonKey.OPERATION))) { + throw new ProjectCommonException( + ResponseCode.externalIdAssignedToOtherUser.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.externalIdAssignedToOtherUser.getErrorMessage(), + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } else { + throwExternalIDNotFoundException( + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)); + } + } + } + } else { + // if user will try to delete non existing extIds + if (JsonKey.UPDATE.equalsIgnoreCase(operation) + && JsonKey.REMOVE.equalsIgnoreCase(externalId.get(JsonKey.OPERATION))) { + throwExternalIDNotFoundException( + externalId.get(JsonKey.ID), + externalId.get(JsonKey.ID_TYPE), + externalId.get(JsonKey.PROVIDER)); + } + } + } + } + } + } + + private static void throwUserAlreadyExistsException( + String externalId, String idType, String provider) { + throw new ProjectCommonException( + ResponseCode.userAlreadyExists.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.userAlreadyExists.getErrorMessage(), + ProjectUtil.formatMessage( + ResponseMessage.Message.EXTERNAL_ID_FORMAT, externalId, idType, provider)), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + private static void throwExternalIDNotFoundException( + String externalId, String idType, String provider) { + throw new ProjectCommonException( + ResponseCode.externalIdNotFound.getErrorCode(), + ProjectUtil.formatMessage( + ResponseCode.externalIdNotFound.getErrorMessage(), externalId, idType, provider), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + + public static String encryptData(String value) { + try { + return encryptionService.encryptData(value); + } catch (Exception e) { + throw new ProjectCommonException( + ResponseCode.userDataEncryptionError.getErrorCode(), + ResponseCode.userDataEncryptionError.getErrorMessage(), + ResponseCode.SERVER_ERROR.getResponseCode()); + } + } + + public static boolean updatePassword(Map userMap) { + if (StringUtils.isNotBlank((String) userMap.get(JsonKey.PASSWORD))) { + return ssoManager.updatePassword( + (String) userMap.get(JsonKey.ID), (String) userMap.get(JsonKey.PASSWORD)); + } + return true; + } + + public static void addMaskEmailAndPhone(Map userMap) { + String phone = (String) userMap.get(JsonKey.PHONE); + String email = (String) userMap.get(JsonKey.EMAIL); + if (!StringUtils.isBlank(phone)) { + userMap.put(JsonKey.ENC_PHONE, phone); + userMap.put(JsonKey.PHONE, maskingService.maskPhone(decService.decryptData(phone))); + } + if (!StringUtils.isBlank(email)) { + userMap.put(JsonKey.ENC_EMAIL, email); + userMap.put(JsonKey.EMAIL, maskingService.maskEmail(decService.decryptData(email))); + } + } + + public static void addMaskEmailAndMaskPhone(Map userMap) { + String phone = (String) userMap.get(JsonKey.PHONE); + String email = (String) userMap.get(JsonKey.EMAIL); + if (!StringUtils.isBlank(phone)) { + userMap.put(JsonKey.MASKED_PHONE, maskingService.maskPhone(decService.decryptData(phone))); + } + if (!StringUtils.isBlank(email)) { + userMap.put(JsonKey.MASKED_EMAIL, maskingService.maskEmail(decService.decryptData(email))); + } + } + + @SuppressWarnings("unchecked") + public static Map encryptUserData(Map userMap) { + try { + UserUtility.encryptUserData(userMap); + } catch (Exception e1) { + ProjectCommonException.throwServerErrorException(ResponseCode.userDataEncryptionError, null); + } + Map requestMap = new HashMap<>(); + User user = mapper.convertValue(userMap, User.class); + requestMap.putAll(mapper.convertValue(user, Map.class)); + return requestMap; + } + + public static Map checkProfileCompleteness(Map userMap) { + ProfileCompletenessService profileService = ProfileCompletenessFactory.getInstance(); + return profileService.computeProfile(userMap); + } + + public static void setUserDefaultValueForV3(Map userMap) { + List roles = new ArrayList<>(); + roles.add(ProjectUtil.UserRole.PUBLIC.getValue()); + userMap.put(JsonKey.ROLES, roles); + userMap.put( + JsonKey.COUNTRY_CODE, propertiesCache.getProperty(JsonKey.SUNBIRD_DEFAULT_COUNTRY_CODE)); + // Since global settings are introduced, profile visibility map should be empty during user + // creation + userMap.put(JsonKey.PROFILE_VISIBILITY, new HashMap()); + userMap.put(JsonKey.IS_DELETED, false); + userMap.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + userMap.put(JsonKey.STATUS, ProjectUtil.Status.ACTIVE.getValue()); + + if (StringUtils.isBlank((String) userMap.get(JsonKey.USERNAME))) { + String firstName = (String) userMap.get(JsonKey.FIRST_NAME); + firstName = firstName.split(" ")[0]; + userMap.put(JsonKey.USERNAME, firstName + "_" + generateUniqueString(4)); + } else { + if (!userService.checkUsernameUniqueness((String) userMap.get(JsonKey.USERNAME), false)) { + ProjectCommonException.throwClientErrorException(ResponseCode.userNameAlreadyExistError); + } + } + } + + public static String generateUniqueString(int length) { + int totalChars = alphabet.length; + BigDecimal exponent = BigDecimal.valueOf(totalChars); + exponent = exponent.pow(length); + String code = ""; + BigDecimal number = new BigDecimal(rand.nextInt(1000000)); + BigDecimal num = number.multiply(largePrimeNumber).remainder(exponent); + code = baseN(num, totalChars); + int codeLenght = code.length(); + if (codeLenght < length) { + for (int i = codeLenght; i < length; i++) { + code = code + alphabet[rand.nextInt(totalChars - 1)]; + } + } + if (NumberUtils.isNumber(code.substring(1, 2)) || NumberUtils.isNumber(code.substring(2, 3))) { + return code; + } else { + code = code.substring(0, 1) + alphabet[rand.nextInt(9)] + code.substring(2); + return code; + } + } + + private static String baseN(BigDecimal num, int base) { + if (num.doubleValue() == 0) { + return "0"; + } + double div = Math.floor(num.doubleValue() / base); + String val = baseN(new BigDecimal(div), base); + return StringUtils.stripStart(val, stripChars) + + alphabet[num.remainder(new BigDecimal(base)).intValue()]; + } + + public static void setUserDefaultValue(Map userMap, String callerId) { + if (StringUtils.isBlank(callerId)) { + List roles = new ArrayList<>(); + roles.add(ProjectUtil.UserRole.PUBLIC.getValue()); + userMap.put(JsonKey.ROLES, roles); + } + if (null == userMap.get(JsonKey.EMAIL_VERIFIED)) { + userMap.put(JsonKey.EMAIL_VERIFIED, false); + } + if (null == userMap.get(JsonKey.PHONE_VERIFIED)) { + userMap.put(JsonKey.PHONE_VERIFIED, false); + } + if (!StringUtils.isBlank((String) userMap.get(JsonKey.COUNTRY_CODE))) { + userMap.put( + JsonKey.COUNTRY_CODE, propertiesCache.getProperty(JsonKey.SUNBIRD_DEFAULT_COUNTRY_CODE)); + } + // Since global settings are introduced, profile visibility map should be empty during user + // creation + userMap.put(JsonKey.PROFILE_VISIBILITY, new HashMap()); + userMap.put(JsonKey.IS_DELETED, false); + userMap.put(JsonKey.CREATED_DATE, ProjectUtil.getFormattedDate()); + userMap.put(JsonKey.STATUS, ProjectUtil.Status.ACTIVE.getValue()); + + if (StringUtils.isBlank((String) userMap.get(JsonKey.USERNAME))) { + String firstName = (String) userMap.get(JsonKey.FIRST_NAME); + String lastName = (String) userMap.get(JsonKey.LAST_NAME); + + String name = String.join(" ", firstName, StringUtils.isNotBlank(lastName) ? lastName : ""); + + String userName = null; + while (StringUtils.isBlank(userName)) { + userName = getUsername(name); + if (StringUtils.isNotBlank(userName)) { + userMap.put(JsonKey.USERNAME, userName); + } + } + } else { + if (!userService.checkUsernameUniqueness((String) userMap.get(JsonKey.USERNAME), false)) { + ProjectCommonException.throwClientErrorException(ResponseCode.userNameAlreadyExistError); + } + } + // create loginId to ensure uniqueness for combination of userName and channel + String loginId = Util.getLoginId(userMap); + userMap.put(JsonKey.LOGIN_ID, loginId); + } + + private static String getUsername(String name) { + List> users = null; + List esUserNameList = new ArrayList<>(); + List encryptedUserNameList = new ArrayList<>(); + List excludedUsernames = new ArrayList<>(); + List userNameList = new ArrayList<>(); + + String userName = ""; + do { + do { + encryptedUserNameList.clear(); + excludedUsernames.addAll(userNameList); + + // Generate usernames + userNameList = userService.generateUsernames(name, excludedUsernames); + + // Encrypt each user name + userService + .getEncryptedList(userNameList) + .stream() + .forEach(value -> encryptedUserNameList.add(value)); + + // Throw an error in case of encryption failures + if (encryptedUserNameList.isEmpty()) { + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); + } + + // Search if any user names are taking using ES + List filtersEncryptedUserNameList = new ArrayList<>(encryptedUserNameList); + Map filters = new HashMap<>(); + filters.put(JsonKey.USERNAME, filtersEncryptedUserNameList); + users = userService.esSearchUserByFilters(filters); + } while (CollectionUtils.isNotEmpty(users) && users.size() >= encryptedUserNameList.size()); + + esUserNameList.clear(); + + // Map list of user results (from ES) into list of usernames + users + .stream() + .forEach( + user -> { + esUserNameList.add((String) user.get(JsonKey.USERNAME)); + }); + // Query cassandra to find first username that is not yet assigned + Optional result = + encryptedUserNameList + .stream() + .filter( + value -> { + if (!esUserNameList.contains(value)) { + return userService.checkUsernameUniqueness(value, true); + } + return false; + }) + .findFirst(); + + if (result.isPresent()) { + userName = result.get(); + } + + } while (StringUtils.isBlank(userName)); + return decService.decryptData(userName); + } + // validateExternalIds For CREATE USER and MIGRATE USER + public static void validateExternalIds(User user, String operationType) { + if (CollectionUtils.isNotEmpty(user.getExternalIds())) { + List> list = copyAndConvertExternalIdsToLower(user.getExternalIds()); + user.setExternalIds(list); + } + checkExternalIdUniqueness(user, operationType); + } + // validateExternalIds For UPDATE USER + public static void validateExternalIdsForUpdateUser(User user, boolean isCustodianOrg) { + if (CollectionUtils.isNotEmpty(user.getExternalIds())) { + List> list = copyAndConvertExternalIdsToLower(user.getExternalIds()); + user.setExternalIds(list); + } + // If operation is update and user is custodian org, ignore uniqueness check + if (!isCustodianOrg) { + checkExternalIdUniqueness(user, JsonKey.UPDATE); + } + if (CollectionUtils.isNotEmpty(user.getExternalIds())) { + validateUserExternalIds(user); + } + } + + public static void checkEmailSameOrDiff( + Map userRequestMap, Map userDbRecord) { + if (StringUtils.isNotBlank((String) userRequestMap.get(JsonKey.EMAIL))) { + String email = (String) userDbRecord.get(JsonKey.EMAIL); + String encEmail = (String) userRequestMap.get(JsonKey.EMAIL); + if (StringUtils.isNotBlank(email)) { + try { + encEmail = encryptionService.encryptData((String) userRequestMap.get(JsonKey.EMAIL)); + } catch (Exception ex) { + ProjectLogger.log("Exception occurred while encrypting user email."); + } + if ((encEmail).equalsIgnoreCase(email)) { + userRequestMap.remove(JsonKey.EMAIL); + } + } + } + } + + private static Optional> checkExternalID( + List> dbResExternalIds, Map extIdMap) { + Optional> extMap = + dbResExternalIds + .stream() + .filter( + s -> { + if (((s.get(JsonKey.ID_TYPE)).equalsIgnoreCase(extIdMap.get(JsonKey.ID_TYPE))) + && ((s.get(JsonKey.PROVIDER)) + .equalsIgnoreCase(extIdMap.get(JsonKey.PROVIDER)))) { + return true; + } else { + return false; + } + }) + .findFirst(); + return extMap; + } + + public static void validateUserExternalIds(User user) { + List> dbResExternalIds = getUserExternalIds(user.getUserId()); + List> externalIds = user.getExternalIds(); + if (CollectionUtils.isNotEmpty(externalIds)) { + for (Map extIdMap : externalIds) { + Optional> extMap = checkExternalID(dbResExternalIds, extIdMap); + Map map = extMap.orElse(null); + // Allowed operation type for externalIds ("add", "remove", "edit") + if (!(JsonKey.ADD.equalsIgnoreCase(extIdMap.get(JsonKey.OPERATION)) + || StringUtils.isBlank(extIdMap.get(JsonKey.OPERATION))) + && MapUtils.isEmpty(map)) { + // operation is either edit or remove + throwExternalIDNotFoundException( + extIdMap.get(JsonKey.ID), + extIdMap.get(JsonKey.ID_TYPE), + extIdMap.get(JsonKey.PROVIDER)); + } + } + } + } + + @SuppressWarnings("unchecked") + private static List> getUserExternalIds(String userId) { + List> dbResExternalIds = new ArrayList<>(); + Response response = + cassandraOperation.getRecordsByIndexedProperty( + JsonKey.SUNBIRD, JsonKey.USR_EXT_IDNT_TABLE, JsonKey.USER_ID, userId); + if (null != response && null != response.getResult()) { + dbResExternalIds = (List>) response.getResult().get(JsonKey.RESPONSE); + } + return dbResExternalIds; + } + + public static List> getActiveUserOrgDetails(String userId) { + return getUserOrgDetails(false, userId); + } + + @SuppressWarnings("unchecked") + private static List> getUserOrgDetails(boolean isdeleted, String userId) { + List> userOrgList = null; + List> organisations = new ArrayList<>(); + try { + Map reqMap = new WeakHashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + if (!isdeleted) { + reqMap.put(JsonKey.IS_DELETED, false); + } + Util.DbInfo orgUsrDbInfo = Util.dbInfoMap.get(JsonKey.USER_ORG_DB); + Response result = + cassandraOperation.getRecordsByProperties( + orgUsrDbInfo.getKeySpace(), orgUsrDbInfo.getTableName(), reqMap); + userOrgList = (List>) result.get(JsonKey.RESPONSE); + if (CollectionUtils.isNotEmpty(userOrgList)) { + for (Map tempMap : userOrgList) { + organisations.add(tempMap); + } + } + } catch (Exception e) { + ProjectLogger.log(e.getMessage(), e); + } + return organisations; + } + + public static List> getAllUserOrgDetails(String userId) { + return getUserOrgDetails(true, userId); + } + + public static void toLower(Map userMap) { + Arrays.asList( + ProjectUtil.getConfigValue(JsonKey.SUNBIRD_API_REQUEST_LOWER_CASE_FIELDS).split(",")) + .stream() + .forEach( + field -> { + if (StringUtils.isNotBlank((String) userMap.get(field))) { + userMap.put(field, ((String) userMap.get(field)).toLowerCase()); + } + }); + } + + public static Map validateManagedByUser(String managedBy) { + Future> managedByInfoF = + esUtil.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), managedBy); + Map managedByInfo = + (Map) ElasticSearchHelper.getResponseFromFuture(managedByInfoF); + if (ProjectUtil.isNull(managedByInfo) + || StringUtils.isBlank((String) managedByInfo.get(JsonKey.FIRST_NAME)) + || StringUtils.isNotBlank((String) managedByInfo.get(JsonKey.MANAGED_BY)) + || (null != managedByInfo.get(JsonKey.IS_DELETED) + && (boolean) (managedByInfo.get(JsonKey.IS_DELETED)))) { + throw new ProjectCommonException( + ResponseCode.invalidRequestData.getErrorCode(), + ResponseCode.invalidRequestData.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + UserUtility.decryptUserDataFrmES(managedByInfo); + return managedByInfo; + } + + public static void validateManagedUserLimit(String managedBy) { + if (Boolean.valueOf(ProjectUtil.getConfigValue(JsonKey.LIMIT_MANAGED_USER_CREATION))) { + Map searchQueryMap = new HashMap<>(); + searchQueryMap.put(JsonKey.MANAGED_BY, managedBy); + List managedUserList = Util.searchUser(searchQueryMap); + if (CollectionUtils.isNotEmpty(managedUserList) + && managedUserList.size() + >= Integer.valueOf(ProjectUtil.getConfigValue(JsonKey.MANAGED_USER_LIMIT))) { + throw new ProjectCommonException( + ResponseCode.managedUserLimitExceeded.getErrorCode(), + ResponseCode.managedUserLimitExceeded.getErrorMessage(), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } + } + } +} + +@FunctionalInterface +interface ConvertValuesToLowerCase { + Map convertToLowerCase(Map map); +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/AddressManagementActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/AddressManagementActorTest.java new file mode 100644 index 0000000000..c15724d8e4 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/AddressManagementActorTest.java @@ -0,0 +1,144 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.user.actors.AddressManagementActor; +import org.sunbird.user.util.UserActorOperations; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class AddressManagementActorTest { + + private static final ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(AddressManagementActor.class); + + @Before + public void beforeEachTest() { + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + EncryptionService encryptionService = Mockito.mock(EncryptionService.class); + Mockito.when( + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null)) + .thenReturn(encryptionService); + + try { + Mockito.when(encryptionService.encryptData(Mockito.anyString())).thenReturn("encrptUserId"); + } catch (Exception e) { + fail( + "AddressManagementActorTest initialization failed, with exception message: " + + e.getMessage()); + } + CassandraOperationImpl cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + when(cassandraOperation.deleteRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getSuccessResponse()); + } + + @Test + public void testInsertUserAddressSuccess() { + boolean result = testScenario(UserActorOperations.INSERT_USER_ADDRESS, true, true, true); + assertTrue(result); + } + + @Test + public void testUpdateAddressSuccessWithDeleteAddress() { + boolean result = testScenario(UserActorOperations.UPDATE_USER_ADDRESS, true, true, false); + assertTrue(result); + } + + @Test + public void testUpdateUserAddressSuccessWithAddNewAddress() { + boolean result = testScenario(UserActorOperations.UPDATE_USER_ADDRESS, false, true, false); + assertTrue(result); + } + + @Test + public void testUpdateUserAddressSuccessWithUpdateExistingAddress() { + boolean result = testScenario(UserActorOperations.UPDATE_USER_ADDRESS, false, true, true); + assertTrue(result); + } + + @Test + public void testInsertUserAddressFailureWithoutReqParams() { + boolean result = testScenario(UserActorOperations.INSERT_USER_ADDRESS, false, false, false); + assertTrue(result); + } + + private boolean testScenario( + UserActorOperations actorOperation, boolean isDelete, boolean success, boolean isIdReq) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(getRequestObject(actorOperation, isDelete, success, isIdReq), probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + if (success) { + return res != null && "SUCCESS".equals(res.getResult().get(JsonKey.RESPONSE)); + } else { + return res != null && res.getResult().get(JsonKey.ERROR_MSG) != null; + } + } + + private Request getRequestObject( + UserActorOperations actorOperation, boolean isDelete, boolean success, boolean isIdReq) { + Request reqObj = new Request(); + reqObj.setOperation(actorOperation.getValue()); + if (success) { + reqObj.put(JsonKey.ADDRESS, getAddressList(isDelete, isIdReq)); + } + reqObj.put(JsonKey.CREATED_BY, "createdBy"); + return reqObj; + } + + private List> getAddressList(boolean isDelete, boolean isIdReq) { + List> lst = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ADDRESS, "anyAddress"); + if (isIdReq) { + map.put(JsonKey.ID, "someUserId"); + } + map.put(JsonKey.IS_DELETED, isDelete); + lst.add(map); + return lst; + } + + private Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, "SUCCESS"); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/CertificateActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/CertificateActorTest.java new file mode 100644 index 0000000000..a25c01ee31 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/CertificateActorTest.java @@ -0,0 +1,210 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.models.user.User; +import org.sunbird.user.actors.CertificateActor; +import org.sunbird.user.service.impl.UserServiceImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({UserServiceImpl.class, ServiceFactory.class}) +@PowerMockIgnore({"javax.management.*"}) +public class CertificateActorTest { + public static CassandraOperationImpl cassandraOperationImpl; + public static UserServiceImpl userServiceImpl; + Props props = Props.create(CertificateActor.class); + ActorSystem system = ActorSystem.create("CertificateActor"); + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(UserServiceImpl.class); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperationImpl = mock(CassandraOperationImpl.class); + userServiceImpl = mock(UserServiceImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperationImpl); + when(UserServiceImpl.getInstance()).thenReturn(userServiceImpl); + } + + @Test + public void testAddCertificate() { + when(userServiceImpl.getUserById(Mockito.anyString())) + .thenReturn(getUserDetails(new User(), false)); + when(cassandraOperationImpl.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getRecordsById(true)); + when(cassandraOperationImpl.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsById(true)); + boolean result = testScenario(getAddCertRequest(ActorOperations.ADD_CERTIFICATE, null), null); + assertTrue(result); + } + + @Ignore + @Test + public void testAddReIssueCertificate() { + when(userServiceImpl.getUserById(Mockito.anyString())) + .thenReturn(getUserDetails(new User(), false)); + when(cassandraOperationImpl.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getRecordsById(true)); + when(cassandraOperationImpl.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordsById(true)); + boolean result = + testScenario(getAddCertRequest(ActorOperations.ADD_CERTIFICATE, "anyOldId"), null); + assertTrue(result); + } + + @Test + public void testValidateCertificate() { + when(cassandraOperationImpl.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getValidRecordDetails(false, true)); + boolean result = + testScenario(getValidateCertRequest(ActorOperations.VALIDATE_CERTIFICATE), null); + assertTrue(result); + } + + @Test + public void testInValidateCertificateAccessCode() { + when(cassandraOperationImpl.getRecordById( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getValidRecordDetails(false, false)); + boolean result = + testScenario( + getValidateCertRequest(ActorOperations.VALIDATE_CERTIFICATE), + ResponseCode.invalidParameter); + assertTrue(result); + } + + @Ignore + @Test + public void testMergeCertificate() { + when(cassandraOperationImpl.getRecordsByProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(getRecordsById(false)); + boolean result = + testScenario(getMergeCertRequest(ActorOperations.MERGE_USER_CERTIFICATE), null); + assertTrue(result); + } + + private Request getMergeCertRequest(ActorOperations actorOperation) { + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.FROM_ACCOUNT_ID, "anyUserId"); + reqMap.put(JsonKey.TO_ACCOUNT_ID, "anyUserId"); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation.getValue()); + return reqObj; + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + Request getAddCertRequest(ActorOperations actorOperation, String oldId) { + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.ID, "anyId"); + reqMap.put(JsonKey.ACCESS_CODE, "anyAccessCode"); + reqMap.put(JsonKey.JSON_DATA, "anyJsonDate"); + reqMap.put(JsonKey.PDF_URL, "anyPdfUrl"); + if (oldId != null) { + reqMap.put(JsonKey.OLD_ID, oldId); + } + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation.getValue()); + return reqObj; + } + + Request getValidateCertRequest(ActorOperations actorOperation) { + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.CERT_ID, "anyId"); + reqMap.put(JsonKey.ACCESS_CODE, "anyAccessCode"); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation.getValue()); + return reqObj; + } + + private User getUserDetails(User user, boolean b) { + if (user != null) user.setIsDeleted(b); + user.setRootOrgId("AnyRootOrgId"); + return user; + } + + private Response getRecordsById(boolean empty) { + Response res = new Response(); + List> list = new ArrayList<>(); + if (!empty) { + Map map = new HashMap<>(); + map.put(JsonKey.ID, "certId"); + map.put(JsonKey.IS_DELETED, true); + list.add(map); + } + res.put(JsonKey.RESPONSE, list); + return res; + } + + private Response getValidRecordDetails(boolean exists, boolean accessCode) { + Response res = new Response(); + List> list = new ArrayList<>(); + Map map = new HashMap<>(); + Map recordStore = new HashMap<>(); + recordStore.put(JsonKey.PDF, "anyPDF"); + recordStore.put(JsonKey.JSON_DATA, "{\n" + " \"jsonData\":\"jsonData\"\n" + "}"); + recordStore.put(JsonKey.COURSE_ID, "anyCourseId"); + recordStore.put(JsonKey.BATCH_ID, "anyBatchId"); + map.put(JsonKey.ID, "certId"); + map.put(JsonKey.IS_DELETED, exists); + if (accessCode) { + map.put("accesscode", "anyAccessCode"); + } else { + map.put("accesscode", "anyNonAccessCode"); + } + map.put(JsonKey.STORE, recordStore); + list.add(map); + res.put(JsonKey.RESPONSE, list); + return res; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/EducationManagementActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/EducationManagementActorTest.java new file mode 100644 index 0000000000..d51e17c386 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/EducationManagementActorTest.java @@ -0,0 +1,307 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.*; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.user.actors.EducationManagementActor; +import org.sunbird.user.dao.AddressDao; +import org.sunbird.user.dao.EducationDao; +import org.sunbird.user.dao.impl.AddressDaoImpl; +import org.sunbird.user.dao.impl.EducationDaoImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ServiceFactory.class, EducationDaoImpl.class, AddressDaoImpl.class}) +@PowerMockIgnore({"javax.management.*"}) +public class EducationManagementActorTest { + + private static final ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(EducationManagementActor.class); + private AddressDao addressDao; + private EducationDao educationDao; + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(AddressDaoImpl.class); + PowerMockito.mockStatic(EducationDaoImpl.class); + addressDao = PowerMockito.mock(AddressDao.class); + educationDao = PowerMockito.mock(EducationDaoImpl.class); + when(AddressDaoImpl.getInstance()).thenReturn(addressDao); + when(EducationDaoImpl.getInstance()).thenReturn(educationDao); + } + + @Test + public void testInsertUserEducationWithAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = + testScenario(getInsertEducationRequestWithAddress("insertUserEducation"), null); + assertTrue(result); + } + + @Test + public void testInsertUserEducationWithOutAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = + testScenario(getInsertEducationRequestWithOutAddress("insertUserEducation"), null); + assertTrue(result); + } + + @Test + public void testInsertUserEducationWithAddressIdSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = + testScenario(getInsertEducationRequestWithAddressId("insertUserEducation"), null); + assertTrue(result); + } + + @Test + public void testInsertUserEducationWithOutAddressFailure() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + Response result = testScenario(getInsertEducationInvalidRequest("insertUserEducation")); + Assert.assertEquals( + "Error occurred while inserting education details.", + ((List) result.get(JsonKey.ERROR_MSG)).get(0)); + } + + @Test + public void testEducationActorWithInvalidOperation() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + Request request = getInsertEducationRequestWithAddress("insertUserEducation"); + request.setOperation("invalidOperation"); + boolean result = testScenario(request, ResponseCode.CLIENT_ERROR); + Assert.assertTrue(result); + } + + @Test + public void testUpdateUserEducationWithAddressIdSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = + testScenario(getInsertEducationRequestWithAddressId("updateUserEducation"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserEducationWithAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = + testScenario(getUpdateEducationRequestWithAddress("updateUserEducation"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserEducationWithOutAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + when(educationDao.getPropertiesValueById(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getAddressIdInResponse()); + boolean result = + testScenario(getInsertEducationRequestWithOutAddress("updateUserEducation"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserEducationWithAddressAndWithoutIdSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + when(educationDao.getPropertiesValueById(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getAddressIdInResponse()); + boolean result = testScenario(getUpdateEducReqWithoutEducId("updateUserEducation"), null); + assertTrue(result); + } + + private Response getAddressIdInResponse() { + List> addressList = new ArrayList<>(); + addressList.add(getAddressRequestWithId()); + Response response = new Response(); + response.put(JsonKey.RESPONSE, addressList); + return response; + } + + private Request getInsertEducationRequestWithAddress(String operationName) { + Request request = new Request(); + Map educationMap = getBaseEducationRequest(); + educationMap.put(JsonKey.ADDRESS, getBaseAddressRequest()); + List> educationList = new ArrayList<>(); + educationList.add(educationMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.EDUCATION, educationList); + reqMap.put(JsonKey.ID, "anyUserId"); + request.setOperation(operationName); + request.setRequest(reqMap); + return request; + } + + private Request getUpdateEducationRequestWithAddress(String operationName) { + Request request = new Request(); + Map educationMap = getBaseEducationRequest(); + educationMap.replace(JsonKey.IS_DELETED, false); + educationMap.put(JsonKey.ADDRESS, getBaseAddressRequest()); + List> educationList = new ArrayList<>(); + educationList.add(educationMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.EDUCATION, educationList); + reqMap.put(JsonKey.ID, "anyUserId"); + request.setOperation(operationName); + request.setRequest(reqMap); + return request; + } + + private Request getUpdateEducReqWithoutEducId(String operationName) { + Request request = new Request(); + Map educationMap = getBaseEducationRequest(); + educationMap.replace(JsonKey.IS_DELETED, false); + educationMap.remove(JsonKey.ID); + educationMap.put(JsonKey.ADDRESS, getBaseAddressRequest()); + List> educationList = new ArrayList<>(); + educationList.add(educationMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.EDUCATION, educationList); + reqMap.put(JsonKey.ID, "anyUserId"); + request.setOperation(operationName); + request.setRequest(reqMap); + return request; + } + + private Request getInsertEducationRequestWithAddressId(String operationName) { + Request request = new Request(); + Map educationMap = getBaseEducationRequest(); + educationMap.put(JsonKey.ADDRESS, getAddressRequestWithId()); + List> educationList = new ArrayList<>(); + educationList.add(educationMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.EDUCATION, educationList); + reqMap.put(JsonKey.ID, "anyUserId"); + request.setOperation(operationName); + request.setRequest(reqMap); + return request; + } + + private Request getInsertEducationInvalidRequest(String operationName) { + Request request = new Request(); + Map educationMap = getBaseEducationRequest(); + List> educationList = new ArrayList<>(); + educationList.add(educationMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.EDUCATION, educationList); + reqMap.put(JsonKey.ID, new HashMap<>()); + request.setOperation(operationName); + request.setRequest(reqMap); + return request; + } + + private Request getInsertEducationRequestWithOutAddress(String operationName) { + Request request = new Request(); + List> educationList = new ArrayList<>(); + educationList.add(getBaseEducationRequest()); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.EDUCATION, educationList); + reqMap.put(JsonKey.ID, "anyUserId"); + request.setOperation(operationName); + request.setRequest(reqMap); + return request; + } + + private Map getBaseEducationRequest() { + Map educationMap = new HashMap<>(); + educationMap.put(JsonKey.DEGREE, "anyDegree"); + educationMap.put(JsonKey.NAME, "collegeName"); + educationMap.put("boardOrUniversity", "CBSE"); + educationMap.put(JsonKey.YEAR_OF_PASSING, BigInteger.valueOf(2017)); + educationMap.put(JsonKey.COURSE_NAME, "BTECH"); + educationMap.put(JsonKey.GRADE, "A"); + educationMap.put(JsonKey.IS_DELETED, true); + educationMap.put(JsonKey.PERCENTAGE, "98"); + educationMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(0)); + return educationMap; + } + + private Map getBaseAddressRequest() { + Map addressMap = new HashMap<>(); + addressMap.put(JsonKey.ADD_TYPE, ProjectUtil.AddressType.home.getTypeName()); + addressMap.put(JsonKey.ADDRESS_LINE1, "any address"); + addressMap.put(JsonKey.CITY, "anyCity"); + addressMap.put(JsonKey.TYPE, "DISTRICT"); + addressMap.put(JsonKey.STATE, "KARANATAKA"); + addressMap.put(JsonKey.ZIPCODE, "anyZipCode"); + return addressMap; + } + + private Map getAddressRequestWithId() { + Map addressMap = new HashMap<>(); + addressMap.put(JsonKey.ADD_TYPE, ProjectUtil.AddressType.home.getTypeName()); + addressMap.put(JsonKey.ADDRESS_LINE1, "any address"); + addressMap.put(JsonKey.CITY, "anyCity"); + addressMap.put(JsonKey.ID, ProjectUtil.getUniqueIdFromTimestamp(0)); + addressMap.put(JsonKey.TYPE, "DISTRICT"); + addressMap.put(JsonKey.STATE, "KARANATAKA"); + + addressMap.put(JsonKey.ZIPCODE, "anyZipCode"); + return addressMap; + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + System.out.println("the error in SUCCESS is" + res.get(JsonKey.ERROR_MSG)); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + public Response testScenario(Request reqObj) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return res; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/SupportMultipleExternalIdsTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/SupportMultipleExternalIdsTest.java new file mode 100644 index 0000000000..c63b25f3a9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/SupportMultipleExternalIdsTest.java @@ -0,0 +1,147 @@ +package org.sunbird.user; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.EncryptionService; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + CassandraOperationImpl.class, + ServiceFactory.class, + EncryptionService.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class +}) +@PowerMockIgnore({ + "javax.management.*", + "javax.net.ssl.*", + "javax.security.*", + "javax.crypto.*", + "javax.script.*" +}) +public class SupportMultipleExternalIdsTest { + + private static User user; + + @Before + public void beforeEach() { + + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + EncryptionService encryptionService = Mockito.mock(EncryptionService.class); + Mockito.when( + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null)) + .thenReturn(encryptionService); + try { + Mockito.when(encryptionService.encryptData(Mockito.anyString())).thenReturn("abc123"); + } catch (Exception e) { // TODO Auto-generated catch block + Assert.fail("Initialization failed"); + } + } + + @BeforeClass + public static void setUp() { + + List> externalIds = new ArrayList<>(); + Map externalIdReqMap = new HashMap<>(); + externalIdReqMap.put(JsonKey.ID, "userId"); + externalIdReqMap.put(JsonKey.PROVIDER, "someProvider"); + externalIdReqMap.put(JsonKey.ID_TYPE, "someIdType"); + externalIdReqMap.put(JsonKey.USER_ID, "reqUserId"); + externalIdReqMap.put(JsonKey.EXTERNAL_ID, "someExternalId"); + + externalIds.add(externalIdReqMap); + user = new User(); + user.setExternalIds(externalIds); + + Map externalIdResMap = new HashMap<>(); + externalIdResMap.put(JsonKey.PROVIDER, "someProvider"); + externalIdResMap.put(JsonKey.ID_TYPE, "someIdType"); + externalIdResMap.put(JsonKey.USER_ID, "someUserId"); + externalIdResMap.put(JsonKey.EXTERNAL_ID, "someExternalId"); + + PowerMockito.mockStatic(ServiceFactory.class); + CassandraOperation cassandraOperation = PowerMockito.mock(CassandraOperationImpl.class); + PowerMockito.when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + Response response1 = new Response(); + + List> resMapList = new ArrayList<>(); + resMapList.add(externalIdResMap); + response1.put(JsonKey.RESPONSE, resMapList); + PowerMockito.when( + cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response1); + } + + @Test + public void testCheckExternalIdUniquenessSuccessForCreate() { + + try { + Util.checkExternalIdUniqueness(user, JsonKey.CREATE); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.userAlreadyExists.getErrorCode(), e.getCode()); + } + } + + @Test + public void testCheckExternalIdUniquenessSuccessWithUpdateOperation() { + + try { + user.setUserId("someUserId2"); + user.getExternalIds().get(0).put(JsonKey.OPERATION, JsonKey.UPDATE); + Util.checkExternalIdUniqueness(user, JsonKey.UPDATE); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.externalIdNotFound.getErrorCode(), e.getCode()); + } + } + + @Test + public void testCheckExternalIdUniquenessSuccessForUpdate() { + + try { + user.setUserId("someUserId2"); + user.getExternalIds().get(0).remove(JsonKey.OPERATION); + Util.checkExternalIdUniqueness(user, JsonKey.UPDATE); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.externalIdAssignedToOtherUser.getErrorCode(), e.getCode()); + } + } + + @Test + public void testCheckExternalIdUniquenessSuccessWithRemoveOperation() { + + try { + user.setUserId("someUserId2"); + user.getExternalIds().get(0).put(JsonKey.OPERATION, JsonKey.REMOVE); + Util.checkExternalIdUniqueness(user, JsonKey.UPDATE); + } catch (ProjectCommonException e) { + assertEquals(ResponseCode.externalIdNotFound.getErrorCode(), e.getCode()); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserAssignRoleTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserAssignRoleTest.java new file mode 100644 index 0000000000..5889ea0aef --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserAssignRoleTest.java @@ -0,0 +1,225 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.Constants; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.user.actors.UserManagementActor; +import scala.concurrent.Promise; +import scala.concurrent.duration.FiniteDuration; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + EsClientFactory.class, + CassandraOperationImpl.class, + DataCacheHandler.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class +}) +@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*"}) +@SuppressStaticInitializationFor("org.sunbird.common.ElasticSearchUtil") +public class UserAssignRoleTest { + + private static final FiniteDuration ACTOR_MAX_WAIT_DURATION = duration("120 second"); + private static String ID = "id001"; + private static String orgId = "testOrg001"; + private static String userId = "testUser001"; + private static String externalId = "testExternal001"; + private static String provider = "testProvider001"; + private static String hashtagId = "hashTagId001"; + private static List ALL_ROLES = + Arrays.asList( + "CONTENT_CREATOR", + "COURSE_MENTOR", + "BOOK_CREATOR", + "BOOK_REVIEWER", + "OFFICIAL_TEXTBOOK_BADGE_ISSUER", + "TEACHER_BADGE_ISSUER", + "ANNOUNCEMENT_SENDER", + "CONTENT_REVIEWER", + "FLAG_REVIEWER", + "PUBLIC"); + private static Map userOrg = new HashMap<>(); + + private static ActorSystem system; + private static Props props; + private static CassandraOperation cassandraOperation = null; + private static Response response = null; + private static Map esRespone = new HashMap<>(); + private static ElasticSearchService esService; + + @BeforeClass + public static void setUp() throws Exception { + system = ActorSystem.create("system"); + props = Props.create(UserManagementActor.class); + + userOrg.put(JsonKey.ID, ID); + userOrg.put(JsonKey.ORGANISATION_ID, orgId); + userOrg.put(JsonKey.USER_ID, userId); + userOrg.put(JsonKey.HASHTAGID, hashtagId); + userOrg.put(JsonKey.EXTERNAL_ID, externalId); + userOrg.put(JsonKey.PROVIDER, provider); + userOrg.put( + JsonKey.ROLES, + Arrays.asList( + "CONTENT_CREATOR", "COURSE_MENTOR", "BOOK_CREATOR", "BOOK_REVIEWER", "PUBLIC")); + + response = new Response(); + Map responseMap = new HashMap<>(); + + responseMap.put(Constants.RESPONSE, Arrays.asList(userOrg)); + response.getResult().putAll(responseMap); + + esRespone.put(JsonKey.CONTENT, Arrays.asList(userOrg)); + } + + @Before + public void mockClasses() throws Exception { + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + cassandraOperation = PowerMockito.mock(CassandraOperationImpl.class); + PowerMockito.when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + esService = PowerMockito.mock(ElasticSearchRestHighImpl.class); + PowerMockito.when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + Map roleMap = new HashMap<>(); + for (String role : ALL_ROLES) roleMap.put(role, role); + PowerMockito.mockStatic(DataCacheHandler.class); + PowerMockito.when(DataCacheHandler.getRoleMap()).thenReturn(roleMap); + Promise> promise = Futures.promise(); + promise.success(userOrg); + Promise> promise_es = Futures.promise(); + promise_es.success(esRespone); + PowerMockito.when(esService.getDataByIdentifier(Mockito.any(), Mockito.any())) + .thenReturn(promise.future()); + PowerMockito.when(esService.search(Mockito.any(), Mockito.any())) + .thenReturn(promise_es.future()); + } + + private static void initCassandraForSuccess() { + PowerMockito.when( + cassandraOperation.getRecordsByProperties(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(response); + + Response updateResponse = new Response(); + Map responseMap = new HashMap<>(); + responseMap.put(Constants.RESPONSE, Constants.SUCCESS); + updateResponse.getResult().putAll(responseMap); + + PowerMockito.when(cassandraOperation.updateRecord(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(updateResponse); + } + + @Ignore + public void testAssignInvalidRolesFailure() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.ASSIGN_ROLES.getValue()); + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId); + request.put(JsonKey.ORGANISATION_ID, orgId); + request.put(JsonKey.ROLES, new ArrayList<>(Arrays.asList("DUMMY_ROLE"))); + reqObj.setRequest(request); + + initCassandraForSuccess(); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException ex = + probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, ProjectCommonException.class); + assertTrue(null != ex); + } + + @Ignore + public void testAssignValidRolesSuccess() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.ASSIGN_ROLES.getValue()); + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId); + request.put(JsonKey.ORGANISATION_ID, orgId); + List roles = new ArrayList<>(Arrays.asList("CONTENT_CREATOR", "COURSE_MENTOR")); + request.put(JsonKey.ROLES, roles); + reqObj.setRequest(request); + + initCassandraForSuccess(); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + assertTrue(null != res); + } + + @Ignore + public void testAssignEmptyRoleSuccess() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.ASSIGN_ROLES.getValue()); + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId); + request.put(JsonKey.ORGANISATION_ID, orgId); + List roles = new ArrayList<>(); + request.put(JsonKey.ROLES, roles); + reqObj.setRequest(request); + + initCassandraForSuccess(); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + assertTrue(null != res); + } + + @Ignore + public void testAssignValidRolesSuccessWithoutOrgID() throws Exception { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.ASSIGN_ROLES.getValue()); + Map request = new HashMap(); + request.put(JsonKey.USER_ID, userId); + request.put(JsonKey.EXTERNAL_ID, externalId); + request.put(JsonKey.PROVIDER, provider); + List roles = new ArrayList<>(Arrays.asList("CONTENT_CREATOR", "COURSE_MENTOR")); + request.put(JsonKey.ROLES, roles); + reqObj.setRequest(request); + + initCassandraForSuccess(); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(ACTOR_MAX_WAIT_DURATION, Response.class); + assertTrue(null != res); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserDataEncryptionActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserDataEncryptionActorTest.java new file mode 100644 index 0000000000..f7590a2d4b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserDataEncryptionActorTest.java @@ -0,0 +1,96 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.user.actors.UserDataEncryptionActor; + +public class UserDataEncryptionActorTest { + + private TestKit probe; + private ActorRef subject; + + private static final ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(UserDataEncryptionActor.class); + private static final List VALID_USER_IDS_LIST = + Arrays.asList("validUserId1", "validUserId2"); + private static List USER_IDS_LIST_SIZE_GREATER_THAN_ALLOWED; + private static final String ENCRYPTION_OPERATION = ActorOperations.ENCRYPT_USER_DATA.getValue(); + private static final String DECRYPTION_OPERATION = ActorOperations.DECRYPT_USER_DATA.getValue(); + + static { + int maximumLimit = + Integer.valueOf(ProjectUtil.getConfigValue(JsonKey.SUNBIRD_USER_MAX_ENCRYPTION_LIMIT)) + 1; + String userId = "someUserId"; + USER_IDS_LIST_SIZE_GREATER_THAN_ALLOWED = new ArrayList<>(); + for (int i = 0; i < maximumLimit; i++) { + USER_IDS_LIST_SIZE_GREATER_THAN_ALLOWED.add(userId + i); + } + } + + @Before + public void beforeEachTestCase() { + probe = new TestKit(system); + subject = system.actorOf(props); + } + + @Test + public void testEncryptDataSuccessWithUserIdsExceedsMaxAllowedPerInvocation() { + Response response = + encryptionDecryptionSuccessTest( + USER_IDS_LIST_SIZE_GREATER_THAN_ALLOWED, ENCRYPTION_OPERATION); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + @Test + public void testEncryptDataSuccess() { + Response response = encryptionDecryptionSuccessTest(VALID_USER_IDS_LIST, ENCRYPTION_OPERATION); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + @Test + public void testDecryptDataSuccessWithUserIdsExceedsMaxAllowedPerInvocation() { + Response response = + encryptionDecryptionSuccessTest( + USER_IDS_LIST_SIZE_GREATER_THAN_ALLOWED, DECRYPTION_OPERATION); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + @Test + public void testDecryptDataSuccess() { + Response response = encryptionDecryptionSuccessTest(VALID_USER_IDS_LIST, DECRYPTION_OPERATION); + Assert.assertTrue(response.getResponseCode().equals(ResponseCode.OK)); + } + + private Request createRequestForEncryption(List userIds, String operation) { + Request request = new Request(); + request.setOperation(operation); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.USER_IDs, userIds); + request.setRequest(innerMap); + return request; + } + + private Response encryptionDecryptionSuccessTest(List userIds, String operation) { + Request request = createRequestForEncryption(userIds, operation); + subject.tell(request, probe.getRef()); + return probe.expectMsgClass(duration("10 second"), Response.class); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserExternalIdManagementActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserExternalIdManagementActorTest.java new file mode 100644 index 0000000000..2f5c3392e9 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserExternalIdManagementActorTest.java @@ -0,0 +1,207 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.notificationservice.dao.impl.EmailTemplateDaoImpl; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.user.actors.UserExternalIdManagementActor; +import org.sunbird.user.util.UserActorOperations; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + Util.class, + DataCacheHandler.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class, + EmailTemplateDaoImpl.class, + Util.class, + EsClientFactory.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class UserExternalIdManagementActorTest { + + private static final Props props = Props.create(UserExternalIdManagementActor.class); + private ActorSystem system = ActorSystem.create("system"); + private static CassandraOperationImpl cassandraOperation; + + @BeforeClass + public static void setUp() { + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EmailTemplateDaoImpl.class); + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + } + + private static Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + @Before + public void beforeTest() { + + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.upsertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(cassandraUpsertRecord()); + when(cassandraOperation.getRecordsByIndexedProperty( + Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any())) + .thenReturn(getCassandraRecordsByIndexedProperty()); + cassandraOperation.deleteRecord(Mockito.anyString(), Mockito.anyString(), Mockito.anyMap()); + PowerMockito.mockStatic(Util.class); + when(Util.encryptData(Mockito.anyString())).thenReturn("userExtId"); + } + + private Response getCassandraRecordsByIndexedProperty() { + Response response = new Response(); + List list = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ID_TYPE, "anyIdType"); + map.put(JsonKey.PROVIDER, "anyProvider"); + list.add(map); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private Response cassandraUpsertRecord() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + @Test + public void testCreateUserExternalIdentityDetailsSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request request = new Request(); + request.setOperation(UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS.getValue()); + + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.OPERATION_TYPE, "CREATE"); + + List> list = new ArrayList<>(); + Map extIdMap = new HashMap<>(); + extIdMap.put(JsonKey.OPERATION, "ADD"); + list.add(extIdMap); + innerMap.put(JsonKey.EXTERNAL_IDS, list); + request.setRequest(innerMap); + + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testUpsertUserExternalIdentityDetailsAddSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request request = new Request(); + request.setOperation(UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS.getValue()); + + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.OPERATION_TYPE, "UPDATE"); + + List> list = new ArrayList<>(); + Map extIdMap = new HashMap<>(); + extIdMap.put(JsonKey.OPERATION, "ADD"); + extIdMap.put(JsonKey.ID_TYPE, "anyIdType"); + extIdMap.put(JsonKey.PROVIDER, "anyProvider"); + list.add(extIdMap); + innerMap.put(JsonKey.EXTERNAL_IDS, list); + request.setRequest(innerMap); + + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testUpsertUserExternalIdentityDetailsRemoveSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request request = new Request(); + request.setOperation(UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS.getValue()); + + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.OPERATION_TYPE, "UPDATE"); + + List> list = new ArrayList<>(); + Map extIdMap = new HashMap<>(); + extIdMap.put(JsonKey.OPERATION, "REMOVE"); + extIdMap.put(JsonKey.ID_TYPE, "anyIdType"); + extIdMap.put(JsonKey.PROVIDER, "anyProvider"); + list.add(extIdMap); + innerMap.put(JsonKey.EXTERNAL_IDS, list); + innerMap.put(JsonKey.USER_ID, "anyUserId"); + request.setRequest(innerMap); + + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testUpsertUserExternalIdentityDetailsEditSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request request = new Request(); + request.setOperation(UserActorOperations.UPSERT_USER_EXTERNAL_IDENTITY_DETAILS.getValue()); + + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.OPERATION_TYPE, "UPDATE"); + + List> list = new ArrayList<>(); + Map extIdMap = new HashMap<>(); + extIdMap.put(JsonKey.OPERATION, "EDIT"); + extIdMap.put(JsonKey.ID_TYPE, "anyIdType"); + extIdMap.put(JsonKey.PROVIDER, "anyProvider"); + list.add(extIdMap); + innerMap.put(JsonKey.EXTERNAL_IDS, list); + innerMap.put(JsonKey.USER_ID, "anyUserId"); + request.setRequest(innerMap); + + subject.tell(request, probe.getRef()); + Response response = probe.expectMsgClass(duration("100 second"), Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserFeedActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserFeedActorTest.java new file mode 100644 index 0000000000..be496fe0c3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserFeedActorTest.java @@ -0,0 +1,106 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.Constants; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.feed.IFeedService; +import org.sunbird.feed.impl.FeedServiceImpl; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.user.actors.UserFeedActor; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + ElasticSearchHelper.class, + EsClientFactory.class, + CassandraOperationImpl.class, + ElasticSearchService.class, + IFeedService.class, + FeedServiceImpl.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class +}) +@SuppressStaticInitializationFor("org.sunbird.common.ElasticSearchUtil") +@PowerMockIgnore({"javax.management.*"}) +public class UserFeedActorTest { + private static ActorSystem system = ActorSystem.create("system"); + private final Props props = Props.create(UserFeedActor.class); + private static Response response = null; + private static Map esResponse = new HashMap<>(); + private static ElasticSearchService esService; + private static Map userFeed = new HashMap<>(); + private static ElasticSearchService esUtil; + private static EsClientFactory esFactory; + + @Before + public void setUp() throws Exception { + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + esService = mock(ElasticSearchService.class); + esUtil = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esUtil); + + userFeed.put(JsonKey.ID, "123-456-789"); + response = new Response(); + Map responseMap = new HashMap<>(); + responseMap.put(Constants.RESPONSE, Arrays.asList(userFeed)); + response.getResult().putAll(responseMap); + esResponse.put(JsonKey.CONTENT, Arrays.asList(userFeed)); + + Map filters = new HashMap<>(); + filters.put(JsonKey.USER_ID, "123-456-789"); + SearchDTO search = new SearchDTO(); + search.getAdditionalProperties().put(JsonKey.FILTERS, filters); + Promise> promise = Futures.promise(); + promise.success(esResponse); + when(ElasticSearchHelper.getResponseFromFuture(Mockito.any())).thenReturn(esResponse); + PowerMockito.when(esService.search(search, ProjectUtil.EsType.userfeed.getTypeName())) + .thenReturn(promise.future()); + } + + @Test + public void getUserFeedTest() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.GET_USER_FEED_BY_ID.getValue()); + reqObj.put(JsonKey.USER_ID, "123-456-789"); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res && res.getResponseCode() == ResponseCode.OK); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserFrameworkTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserFrameworkTest.java new file mode 100644 index 0000000000..5b2c6faa33 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserFrameworkTest.java @@ -0,0 +1,159 @@ +package org.sunbird.user; + +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.*; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.content.store.util.ContentStoreUtil; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; + +@PrepareForTest({DataCacheHandler.class, ContentStoreUtil.class}) +public class UserFrameworkTest extends UserManagementActorTestBase { + + @Before + public void beforeTest() { + PowerMockito.mockStatic(DataCacheHandler.class); + PowerMockito.mockStatic(ContentStoreUtil.class); + mockForUpdateTest(); + } + + @Test + public void testUpdateUserFrameworkSuccess() { + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + Request reqObj = getRequest(null, null); + boolean res = testScenario(reqObj, null); + assertTrue(res); + } + + @Test + public void testUpdateUserFrameworkFailureInvalidGradeLevel() { + Request reqObj = getRequest("gradeLevel", "SomeWrongGrade"); + boolean res = testScenario(reqObj, ResponseCode.invalidParameterValue); + assertTrue(res); + } + + @Test + public void testUpdateUserFrameworkFailureInvalidMedium() { + Request reqObj = getRequest("medium", "glish"); + boolean res = testScenario(reqObj, ResponseCode.invalidParameterValue); + assertTrue(res); + } + + @Test + public void testUpdateUserFrameworkFailureInvalidBoard() { + Request reqObj = getRequest("board", "RBCS"); + boolean res = testScenario(reqObj, ResponseCode.invalidParameterValue); + assertTrue(res); + } + + @Test + public void testUpdateUserFrameworkFailureInvalidFrameworkId() { + Request reqObj = getRequest(JsonKey.ID, "invalidFrameworkId"); + boolean res = testScenario(reqObj, ResponseCode.errorNoFrameworkFound); + assertTrue(res); + } + + @SuppressWarnings("unchecked") + public void mockForUpdateTest() { + mockUtilsForOrgDetails(); + mockDataCacheHandler(); + mockContentStoreUtil(); + } + + private void mockUtilsForOrgDetails() { + Map rootOrgMap = new HashMap<>(); + String hashTagId = "someHashTagId"; + rootOrgMap.put(JsonKey.HASHTAGID, hashTagId); + when(Util.getOrgDetails(Mockito.anyString())).thenReturn(rootOrgMap); + } + + private void mockContentStoreUtil() { + Map contentMap = new HashMap<>(); + contentMap.put(JsonKey.RESPONSE, null); + when(ContentStoreUtil.readFramework("invalidFrameworkId")).thenReturn(contentMap); + } + + private void mockDataCacheHandler() { + Map> frameworkFieldsConfigMap = new HashMap<>(); + List frameworkFieldConfig = + Arrays.asList("id", "medium", "gradeLevel", "board", "subject"); + List frameworkFieldConfigMan = Arrays.asList("id", "medium", "gradeLevel", "board"); + frameworkFieldsConfigMap.put(JsonKey.FIELDS, frameworkFieldConfig); + frameworkFieldsConfigMap.put(JsonKey.MANDATORY_FIELDS, frameworkFieldConfigMan); + Mockito.when(DataCacheHandler.getFrameworkFieldsConfig()).thenReturn(frameworkFieldsConfigMap); + + Map>> frameworkCategoriesMap = new HashMap<>(); + frameworkCategoriesMap.put("medium", getListForCategoryMap("English")); + frameworkCategoriesMap.put("gradeLevel", getListForCategoryMap("Grade 3")); + frameworkCategoriesMap.put("board", getListForCategoryMap("NCERT")); + + Map>>> frameworkCategory = new HashMap<>(); + frameworkCategory.put("NCF", frameworkCategoriesMap); + when(DataCacheHandler.getFrameworkCategoriesMap()).thenReturn(frameworkCategory); + Map> map1 = new HashMap<>(); + List list1 = Arrays.asList("NCF"); + map1.put("someHashTagId", list1); + when(DataCacheHandler.getHashtagIdFrameworkIdMap()).thenReturn(map1); + } + + private Request getRequest(String key, String value) { + Request reqObj = new Request(); + String userId = "userId"; + reqObj.getRequest().put(JsonKey.USER_ID, userId); + reqObj.setOperation(ActorOperations.UPDATE_USER.getValue()); + Map innerMap = new HashMap<>(); + innerMap.put(JsonKey.ID, userId); + Map frameworkMap = getFrameworkDetails(key, value); + reqObj.getRequest().put(JsonKey.USER_ID, userId); + innerMap.put(JsonKey.FRAMEWORK, frameworkMap); + Map request = new HashMap(); + request.put(JsonKey.USER, innerMap); + request.put(JsonKey.USER_ID, userId); + request.put(JsonKey.FRAMEWORK, frameworkMap); + getUpdateRequestWithDefaultFlags(request); + reqObj.setRequest(request); + Map context = new HashMap<>(); + context.put(JsonKey.REQUESTED_BY, "someValue"); + context.put(JsonKey.USER_ID, userId); + reqObj.setContext(context); + return reqObj; + } + + private List> getListForCategoryMap(String value) { + Map map2 = new HashMap<>(); + map2.put(JsonKey.NAME, value); + List> list2 = new ArrayList<>(); + list2.add(map2); + return list2; + } + + private Map getFrameworkDetails(String key, String value) { + Map frameworkMap = new HashMap<>(); + List medium = new ArrayList<>(); + medium.add("English"); + List gradeLevel = new ArrayList<>(); + gradeLevel.add("Grade 3"); + List board = new ArrayList<>(); + board.add("NCERT"); + frameworkMap.put(JsonKey.ID, "NCF"); + frameworkMap.put("gradeLevel", gradeLevel); + frameworkMap.put("board", board); + frameworkMap.put("medium", medium); + if (key != null) { + List wrongValue = new ArrayList<>(); + wrongValue.add(value); + frameworkMap.put(key, wrongValue); + } + return frameworkMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserLoginActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserLoginActorTest.java new file mode 100644 index 0000000000..f8a5a511cc --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserLoginActorTest.java @@ -0,0 +1,57 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import org.junit.Assert; +import org.junit.Test; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.user.actors.UserLoginActor; + +public class UserLoginActorTest { + + private static final String INVALID_OPERATION = "INVALID_OPERATION"; + private static final Props props = Props.create(UserLoginActor.class); + private static ActorSystem system = ActorSystem.create("system"); + private String userId = "someUserId"; + private TestKit probe = new TestKit(system); + private ActorRef subject = system.actorOf(props); + + @Test + public void testUpdateUserLoginTimeSuccess() { + Request request = new Request(); + + request.setOperation(ActorOperations.USER_CURRENT_LOGIN.getValue()); + request.put(JsonKey.USER_ID, userId); + + subject.tell(request, probe.getRef()); + + Response response = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != response && response.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testUpdateUserLoginTimeFailureWithInvalidMessage() { + Request request = new Request(); + + request.setOperation(INVALID_OPERATION); + request.put(JsonKey.USER_ID, userId); + + subject.tell(request, probe.getRef()); + + ProjectCommonException exception = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue( + ((ProjectCommonException) exception) + .getCode() + .equals(ResponseCode.invalidRequestData.getErrorCode())); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserManagementActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserManagementActorTest.java new file mode 100644 index 0000000000..122137b610 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserManagementActorTest.java @@ -0,0 +1,421 @@ +package org.sunbird.user; + +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.dispatch.Futures; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import akka.pattern.Patterns; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.DataCacheHandler; +import scala.concurrent.Await; +import scala.concurrent.Promise; + +public class UserManagementActorTest extends UserManagementActorTestBase { + + @Test + public void testCreateUserSuccessWithUserCallerId() { + + boolean result = + testScenario( + getRequest(true, true, true, getAdditionalMapData(reqMap), ActorOperations.CREATE_USER), + null); + assertTrue(result); + } + + @Test + public void testCreateUserSuccessWithoutUserCallerId() { + + boolean result = + testScenario( + getRequest( + false, true, true, getAdditionalMapData(reqMap), ActorOperations.CREATE_USER), + null); + assertTrue(result); + } + + @Test + public void testCreateUserSuccessWithoutUserCallerIdChannelAndRootOrgId() { + + boolean result = + testScenario(getRequest(false, false, true, reqMap, ActorOperations.CREATE_USER), null); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithInvalidChannelAndOrgId() { + + reqMap.put(JsonKey.CHANNEL, "anyReqChannel"); + reqMap.put(JsonKey.ORGANISATION_ID, "anyOrgId"); + boolean result = + testScenario( + getRequest(false, false, false, reqMap, ActorOperations.CREATE_USER), + ResponseCode.parameterMismatch); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithInvalidLocationCodes() { + when(InterServiceCommunicationFactory.getInstance()) + .thenReturn(interServiceCommunication) + .thenReturn(interServiceCommunication); + when(interServiceCommunication.getResponse( + Mockito.any(ActorRef.class), Mockito.any(Request.class))) + .thenReturn(null); + reqMap.put(JsonKey.LOCATION_CODES, Arrays.asList("invalidLocationCode")); + boolean result = + testScenario( + getRequest(false, false, false, reqMap, ActorOperations.CREATE_USER), + ResponseCode.invalidParameterValue); + assertTrue(result); + } + + @Test + public void testCreateUserSuccessWithoutVersion() { + + boolean result = + testScenario(getRequest(false, false, false, reqMap, ActorOperations.CREATE_USER), null); + assertTrue(result); + } + + @Test + public void testCreateUserSuccessWithLocationCodes() { + when(InterServiceCommunicationFactory.getInstance()) + .thenReturn(interServiceCommunication) + .thenReturn(interServiceCommunication); + when(interServiceCommunication.getResponse( + Mockito.any(ActorRef.class), Mockito.any(Request.class))) + .thenReturn(getEsResponseForLocation()) + .thenReturn(getEsResponse()); + reqMap.put(JsonKey.LOCATION_CODES, Arrays.asList("locationCode")); + boolean result = + testScenario(getRequest(true, true, true, reqMap, ActorOperations.CREATE_USER), null); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithInvalidExternalIds() { + + reqMap.put(JsonKey.EXTERNAL_IDS, "anyExternalId"); + boolean result = + testScenario( + getRequest(false, false, false, reqMap, ActorOperations.CREATE_USER), + ResponseCode.dataTypeError); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithInvalidRoles() { + + reqMap.put(JsonKey.ROLES, "anyRoles"); + boolean result = + testScenario( + getRequest(false, false, false, reqMap, ActorOperations.CREATE_USER), + ResponseCode.dataTypeError); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithInvalidCountryCode() { + + reqMap.put(JsonKey.COUNTRY_CODE, "anyCode"); + boolean result = + testScenario( + getRequest(false, false, false, reqMap, ActorOperations.CREATE_USER), + ResponseCode.invalidCountryCode); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithInvalidOrg() { + Promise> promise = Futures.promise(); + promise.success(null); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + boolean result = + testScenario( + getRequest( + false, false, false, getAdditionalMapData(reqMap), ActorOperations.CREATE_USER), + ResponseCode.invalidOrgData); + assertTrue(result); + } + + @Test + public void testUpdateUserFailureWithLocationCodes() { + when(interServiceCommunication.getResponse( + Mockito.any(ActorRef.class), Mockito.any(Request.class))) + .thenReturn(null); + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + boolean result = + testScenario( + getRequest( + true, true, true, getUpdateRequestWithLocationCodes(), ActorOperations.UPDATE_USER), + ResponseCode.invalidParameterValue); + assertTrue(result); + } + + @Test + public void testUpdateUserSuccess() { + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + Map req = getExternalIdMap(); + getUpdateRequestWithDefaultFlags(req); + boolean result = + testScenario(getRequest(true, true, true, req, ActorOperations.UPDATE_USER), null); + assertTrue(result); + } + + @Test + public void testUpdateUserSuccessWithLocationCodes() { + when(InterServiceCommunicationFactory.getInstance()) + .thenReturn(interServiceCommunication) + .thenReturn(interServiceCommunication); + when(interServiceCommunication.getResponse( + Mockito.any(ActorRef.class), Mockito.any(Request.class))) + .thenReturn(getEsResponseForLocation()) + .thenReturn(getEsResponse()); + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + boolean result = + testScenario( + getRequest( + true, true, true, getUpdateRequestWithLocationCodes(), ActorOperations.UPDATE_USER), + null); + assertTrue(result); + } + + @Test + public void testUpdateUserSuccessWithoutUserCallerId() { + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + Map req = getExternalIdMap(); + getUpdateRequestWithDefaultFlags(req); + boolean result = + testScenario(getRequest(false, true, true, req, ActorOperations.UPDATE_USER), null); + assertTrue(result); + } + + @Test + public void testCreateUserSuccessWithUserTypeAsTeacher() { + reqMap.put(JsonKey.USER_TYPE, JsonKey.TEACHER); + + when(userService.getRootOrgIdFromChannel(Mockito.anyString())) + .thenReturn("rootOrgId") + .thenReturn(""); + + boolean result = + testScenario( + getRequest(true, true, true, getAdditionalMapData(reqMap), ActorOperations.CREATE_USER), + null); + assertTrue(result); + } + + @Test + public void testCreateUserSuccessWithUserTypeAsOther() { + reqMap.put(JsonKey.USER_TYPE, JsonKey.OTHER); + + boolean result = + testScenario( + getRequest(true, true, true, getAdditionalMapData(reqMap), ActorOperations.CREATE_USER), + null); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithUserTypeAsTeacherAndCustodianOrg() { + reqMap.put(JsonKey.USER_TYPE, JsonKey.TEACHER); + + boolean result = + testScenario( + getRequest(false, false, true, reqMap, ActorOperations.CREATE_USER), + ResponseCode.errorTeacherCannotBelongToCustodianOrg); + assertTrue(result); + } + + @Test + public void testUpdateUserSuccessWithUserTypeTeacher() { + Map req = getExternalIdMap(); + getUpdateRequestWithDefaultFlags(req); + req.put(JsonKey.USER_TYPE, JsonKey.TEACHER); + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + when(userService.getRootOrgIdFromChannel(Mockito.anyString())).thenReturn("rootOrgId1"); + boolean result = + testScenario(getRequest(false, true, true, req, ActorOperations.UPDATE_USER), null); + assertTrue(result); + } + + @Test + public void testUpdateUserFailureWithUserTypeTeacher() { + Map req = getExternalIdMap(); + req.put(JsonKey.USER_TYPE, JsonKey.TEACHER); + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + when(userService.getRootOrgIdFromChannel(Mockito.anyString())).thenReturn("rootOrgId"); + boolean result = + testScenario( + getRequest(false, true, true, req, ActorOperations.UPDATE_USER), + ResponseCode.errorTeacherCannotBelongToCustodianOrg); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithoutUserIdPrivateApi() { + Map req = getUserOrgUpdateRequest(false); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + boolean result = testScenario(request, ResponseCode.errorUnsupportedField); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithPublicApi() { + Map req = getUserOrgUpdateRequest(false); + req.remove(JsonKey.USER_ID); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + boolean result = testScenario(request, ResponseCode.mandatoryParamsMissing); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithOrganisationsPrivateApi() { + Map req = getUserOrgUpdateRequest(false); + req.put(JsonKey.ORGANISATIONS, new HashMap<>()); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + boolean result = testScenario(request, ResponseCode.dataTypeError); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithInvalidOrganisationsPrivateApi() { + Map req = getUserOrgUpdateRequest(true); + req.put(JsonKey.ORGANISATIONS, Arrays.asList("a", "b")); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + boolean result = testScenario(request, ResponseCode.dataTypeError); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithoutOrganisationsPrivateApi() { + Map req = getUserOrgUpdateRequest(true); + ((Map) ((List) req.get(JsonKey.ORGANISATIONS)).get(0)).put(JsonKey.ORGANISATION_ID, ""); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + boolean result = testScenario(request, ResponseCode.mandatoryParamsMissing); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithInvalidRolesDataTypePrivateApi() { + Map req = getUserOrgUpdateRequest(true); + ((Map) ((List) req.get(JsonKey.ORGANISATIONS)).get(0)).put(JsonKey.ROLES, "String"); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + boolean result = testScenario(request, ResponseCode.dataTypeError); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithEmptyRolesReqPrivateApi() { + Map req = getUserOrgUpdateRequest(true); + ((Map) ((List) req.get(JsonKey.ORGANISATIONS)).get(0)).put(JsonKey.ROLES, new ArrayList<>()); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + boolean result = testScenario(request, ResponseCode.emptyRolesProvided); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgSuccessPrivateApi() { + Map req = getUserOrgUpdateRequest(true); + getUpdateRequestWithDefaultFlags(req); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + mockForUserOrgUpdate(); + boolean result = testScenario(request, null); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgSuccessWithoutRolesPrivateApi() { + Map req = getUserOrgUpdateRequest(true); + getUpdateRequestWithDefaultFlags(req); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + mockForUserOrgUpdate(); + boolean result = testScenario(request, null); + assertTrue(result); + } + + @Test + public void testUpdateUserOrgFailureWithInvalidRolesPrivateApi() { + Map req = getUserOrgUpdateRequest(true); + Request request = getRequest(false, false, true, req, ActorOperations.UPDATE_USER); + request.getContext().put(JsonKey.PRIVATE, true); + mockForUserOrgUpdate(); + when(DataCacheHandler.getRoleMap()).thenReturn(roleMap(false)); + boolean result = testScenario(request, ResponseCode.invalidRole); + assertTrue(result); + } + + @Test + public void testCreateUserSuccessWithUserSync() { + reqMap.put("sync", true); + boolean result = + testScenario( + getRequest(true, true, true, getAdditionalMapData(reqMap), ActorOperations.CREATE_USER), + null); + assertTrue(result); + } + + @Test + public void testCreateUserFailureWithManagedUserLimit() { + Map reqMap = getUserOrgUpdateRequest(true); + getUpdateRequestWithDefaultFlags(reqMap); + boolean result = + testScenario( + getRequest( + false, false, false, getAdditionalMapData(reqMap), ActorOperations.CREATE_USER_V4), + null); + assertTrue(result); + } + + @Test + @Ignore + public void testGetManagedUsers() throws Exception{ + HashMap reqMap = new HashMap<>(); + reqMap.put(JsonKey.ID, "102fcbd2-8ec1-4870-b9e1-5dc01f2acc75"); + reqMap.put(JsonKey.WITH_TOKENS, "true"); + + Map map = new HashMap<>(); + map.put("anyString", new Object()); + + Response response = new Response(); + response.put(JsonKey.RESPONSE, map); + + when(Await.result(Patterns.ask(Mockito.any(ActorRef.class), Mockito.any(Request.class), Mockito.anyLong()), Mockito.anyObject())) + .thenReturn(response) + .thenReturn(map); + boolean result = + testScenario( + getRequest(false, false, false, reqMap, ActorOperations.GET_MANAGED_USERS), + null); + assertTrue(result); + } + + private Map getSearchResults(){ + Map searchRequestMap = new HashMap<>(); + + return searchRequestMap; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserManagementActorTestBase.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserManagementActorTestBase.java new file mode 100644 index 0000000000..7c949027b1 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserManagementActorTestBase.java @@ -0,0 +1,326 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.actorutil.impl.InterServiceCommunicationImpl; +import org.sunbird.actorutil.location.impl.LocationClientImpl; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.actorutil.user.UserClient; +import org.sunbird.actorutil.user.impl.UserClientImpl; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.user.actors.UserManagementActor; +import org.sunbird.user.service.impl.UserServiceImpl; +import org.sunbird.user.util.UserUtil; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + EsClientFactory.class, + Util.class, + RequestRouter.class, + SystemSettingClientImpl.class, + UserServiceImpl.class, + UserUtil.class, + InterServiceCommunicationFactory.class, + LocationClientImpl.class, + DataCacheHandler.class, + ElasticSearchRestHighImpl.class, + SunbirdMWService.class, + UserClientImpl.class +}) +@PowerMockIgnore({"javax.management.*"}) +public abstract class UserManagementActorTestBase { + + public ActorSystem system = ActorSystem.create("system"); + public static final Props props = Props.create(UserManagementActor.class); + public static Map reqMap; + static InterServiceCommunication interServiceCommunication = + mock(InterServiceCommunicationImpl.class); + public static UserServiceImpl userService; + public static CassandraOperationImpl cassandraOperation; + public static ElasticSearchService esService; + public static UserClient userClient; + + @Before + public void beforeEachTest() { + + ActorRef actorRef = mock(ActorRef.class); + PowerMockito.mockStatic(RequestRouter.class); + when(RequestRouter.getActor(Mockito.anyString())).thenReturn(actorRef); + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(SunbirdMWService.class); + SunbirdMWService.tellToBGRouter(Mockito.any(), Mockito.any()); + cassandraOperation = mock(CassandraOperationImpl.class); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getSuccessResponse()); + + PowerMockito.mockStatic(InterServiceCommunicationFactory.class); + when(InterServiceCommunicationFactory.getInstance()).thenReturn(interServiceCommunication); + when(interServiceCommunication.getResponse( + Mockito.any(ActorRef.class), Mockito.any(Request.class))) + .thenReturn(getEsResponse()); + + PowerMockito.mockStatic(SystemSettingClientImpl.class); + SystemSettingClientImpl systemSettingClient = mock(SystemSettingClientImpl.class); + when(SystemSettingClientImpl.getInstance()).thenReturn(systemSettingClient); + when(systemSettingClient.getSystemSettingByFieldAndKey( + Mockito.any(ActorRef.class), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyObject())) + .thenReturn(new HashMap<>()); + + PowerMockito.mockStatic(UserClientImpl.class); + userClient = mock(UserClientImpl.class); + + PowerMockito.mockStatic(UserServiceImpl.class); + userService = mock(UserServiceImpl.class); + when(UserServiceImpl.getInstance()).thenReturn(userService); + when(userService.getRootOrgIdFromChannel(Mockito.anyString())).thenReturn("anyId"); + when(userService.getCustodianChannel(Mockito.anyMap(), Mockito.any(ActorRef.class))) + .thenReturn("anyChannel"); + when(userService.getRootOrgIdFromChannel(Mockito.anyString())).thenReturn("rootOrgId"); + + Promise> promise = Futures.promise(); + promise.success(getEsResponseMap()); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + Map map = new HashMap<>(); + Promise esPromise = Futures.promise(); + esPromise.success("success"); + when(esService.save(Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(esPromise.future()); + PowerMockito.mockStatic(Util.class); + Util.getUserProfileConfig(Mockito.any(ActorRef.class)); + + PowerMockito.mockStatic(UserUtil.class); + UserUtil.setUserDefaultValue(Mockito.anyMap(), Mockito.anyString()); + + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.ROOT_ORG_ID, "rootOrgId"); + requestMap.put(JsonKey.TNC_ACCEPTED_ON, 12345678L); + when(UserUtil.encryptUserData(Mockito.anyMap())).thenReturn(requestMap); + PowerMockito.mockStatic(DataCacheHandler.class); + when(DataCacheHandler.getRoleMap()).thenReturn(roleMap(true)); + when(UserUtil.getActiveUserOrgDetails(Mockito.anyString())).thenReturn(getUserOrgDetails()); + reqMap = getMapObject(); + } + + public void mockForUserOrgUpdate() { + Promise> promise = Futures.promise(); + promise.success(getListOrgResponse()); + when(esService.search(Mockito.any(), Mockito.anyString())).thenReturn(promise.future()); + when(userService.getUserById(Mockito.anyString())).thenReturn(getUser(false)); + when(cassandraOperation.insertRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(null); + } + + public Map getListOrgResponse() { + Map map = new HashMap<>(); + map.put(JsonKey.ID, "org1"); + map.put(JsonKey.HASHTAGID, "hashtagId"); + map.put(JsonKey.CONTACT_DETAILS, "any"); + Map response = new HashMap<>(); + List> content = new ArrayList<>(); + content.add(map); + response.put(JsonKey.CONTENT, content); + return response; + } + + public Map getUserOrgUpdateRequest(boolean validOrgReq) { + Map req = new HashMap<>(); + req.put(JsonKey.USER_ID, "userId"); + req.put(JsonKey.ORGANISATIONS, "any"); + if (validOrgReq) { + Map map = new HashMap<>(); + List> list = new ArrayList<>(); + map.put(JsonKey.ORGANISATION_ID, "org1"); + map.put(JsonKey.ROLES, Arrays.asList("PUBLIC")); + list.add(map); + req.put(JsonKey.ORGANISATIONS, list); + } + return req; + } + + public List> getUserOrgDetails() { + List> list = new ArrayList<>(); + Map map = new HashMap<>(); + map.put(JsonKey.ORGANISATION_ID, "any"); + list.add(map); + return list; + } + + public Map roleMap(boolean validRole) { + Map map = new HashMap<>(); + if (validRole) { + map.put("PUBLIC", "PUBLIC"); + } + map.put("Invalid", "Invalid"); + return map; + } + + public Map getAdditionalMapData(Map reqMap) { + reqMap.put(JsonKey.ORGANISATION_ID, "anyOrgId"); + reqMap.put(JsonKey.CHANNEL, "anyChannel"); + return reqMap; + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + public Map getExternalIdMap() { + + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.EXTERNAL_ID, "externalId"); + reqMap.put(JsonKey.EXTERNAL_ID_PROVIDER, "externalIdProvider"); + reqMap.put(JsonKey.EXTERNAL_ID_TYPE, "externalIdType"); + return reqMap; + } + + public HashMap getMapObject() { + + HashMap reqMap = new HashMap<>(); + reqMap.put(JsonKey.FIRST_NAME, "firstname"); + reqMap.put(JsonKey.USERNAME, "userName"); + reqMap.put(JsonKey.EMAIL, "email@email.com"); + reqMap.put(JsonKey.LANGUAGE, new ArrayList<>()); + reqMap.put(JsonKey.DOB, "1992-12-31"); + reqMap.put(JsonKey.EMAIL_VERIFIED, true); + reqMap.put(JsonKey.PHONE_VERIFIED, true); + reqMap.put(JsonKey.ADDRESS, new ArrayList<>()); + return reqMap; + } + + public Request getRequest( + boolean isCallerIdReq, + boolean isRootOrgIdReq, + boolean isVersionReq, + Map reqMap, + ActorOperations actorOperation) { + + Request reqObj = new Request(); + HashMap innerMap = new HashMap<>(); + if (isCallerIdReq) innerMap.put(JsonKey.CALLER_ID, "anyCallerId"); + if (isVersionReq) innerMap.put(JsonKey.VERSION, "v2"); + if (isRootOrgIdReq) innerMap.put(JsonKey.ROOT_ORG_ID, "MY_ROOT_ORG_ID"); + innerMap.put(JsonKey.REQUESTED_BY, "requestedBy"); + reqObj.setRequest(reqMap); + reqObj.setContext(innerMap); + reqObj.setOperation(actorOperation.getValue()); + return reqObj; + } + + public Map getUpdateRequestWithLocationCodes() { + Map reqObj = new HashMap(); + reqObj.put(JsonKey.LOCATION_CODES, Arrays.asList("locationCode")); + reqObj.put(JsonKey.USER_ID, "userId"); + getUpdateRequestWithDefaultFlags(reqObj); + return reqObj; + } + + public Map getUpdateRequestWithDefaultFlags(Map reqObj) { + reqObj.put(JsonKey.EMAIL_VERIFIED, false); + reqObj.put(JsonKey.PHONE_VERIFIED, false); + reqObj.put(JsonKey.STATE_VALIDATED, false); + return reqObj; + } + + public static Response getEsResponse() { + + Response response = new Response(); + Map map = new HashMap<>(); + map.put("anyString", new Object()); + response.put(JsonKey.RESPONSE, map); + return response; + } + + public static Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + public static Map getEsResponseMap() { + Map map = new HashMap<>(); + map.put(JsonKey.IS_ROOT_ORG, true); + map.put(JsonKey.ID, "rootOrgId"); + map.put(JsonKey.CHANNEL, "anyChannel"); + return map; + } + + public Object getEsResponseForLocation() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, Arrays.asList("id")); + return response; + } + + public User getUser(boolean isCustodian) { + User user = new User(); + user.setRootOrgId("rootOrgId"); + if (isCustodian) { + user.setRootOrgId("custodianOrgId"); + } + return user; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserMergeActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserMergeActorTest.java new file mode 100644 index 0000000000..d8552132e3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserMergeActorTest.java @@ -0,0 +1,181 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import com.typesafe.config.Config; +import java.util.HashMap; +import java.util.Map; +import org.apache.kafka.clients.producer.Producer; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.core.BaseActor; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.common.util.ConfigUtil; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.kafka.client.KafkaClient; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.models.user.User; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.services.sso.impl.KeyCloakServiceImpl; +import org.sunbird.user.actors.UserMergeActor; +import org.sunbird.user.dao.impl.UserDaoImpl; +import org.sunbird.user.service.impl.UserServiceImpl; +import org.sunbird.user.util.KafkaConfigConstants; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + SSOServiceFactory.class, + DataCacheHandler.class, + BaseActor.class, + UserServiceImpl.class, + UserDaoImpl.class, + ServiceFactory.class, + CassandraOperationImpl.class, + ConfigUtil.class, + Config.class, + KafkaClient.class +}) +@PowerMockIgnore({"javax.management.*"}) +@SuppressStaticInitializationFor("org.sunbird.kafka.client.KafkaClient") +public class UserMergeActorTest { + private static int userCounter; + private static final Props props = Props.create(UserMergeActor.class); + private static ActorSystem system = ActorSystem.create("system"); + public static UserServiceImpl userService; + public static UserDaoImpl userDao; + public static Config config; + public static Producer producer; + public static KafkaClient kafkaClient; + public static CassandraOperationImpl cassandraOperation; + private static KeyCloakServiceImpl ssoManager; + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(UserServiceImpl.class); + PowerMockito.mockStatic(UserDaoImpl.class); + PowerMockito.mockStatic(ConfigUtil.class); + PowerMockito.mockStatic(KafkaClient.class); + PowerMockito.mockStatic(SSOServiceFactory.class); + PowerMockito.mockStatic(DataCacheHandler.class); + userService = mock(UserServiceImpl.class); + userDao = mock(UserDaoImpl.class); + config = mock(Config.class); + kafkaClient = mock(KafkaClient.class); + producer = mock(Producer.class); + ssoManager = mock(KeyCloakServiceImpl.class); + when(ConfigUtil.getConfig()).thenReturn(config); + when(config.getString(KafkaConfigConstants.SUNBIRD_USER_CERT_KAFKA_TOPIC)).thenReturn("topic"); + when(UserServiceImpl.getInstance()).thenReturn(userService); + when(UserDaoImpl.getInstance()).thenReturn(userDao); + when(KafkaClient.getProducer()).thenReturn(producer); + when(SSOServiceFactory.getInstance()).thenReturn(ssoManager); + cassandraOperation = mock(CassandraOperationImpl.class); + userCounter = 0; + } + + @Test + public void testMergeUserIsAlreadyDeleted() { + when(userService.getUserById(Mockito.anyString())) + .thenReturn(getUserDetails(true)) + .thenReturn(getUserDetails(true)); + when(userDao.updateUser(Mockito.anyMap())).thenReturn(getSuccessResponse()); + when(ssoManager.verifyToken(Mockito.anyString())).thenReturn("anyUserId"); + when(ssoManager.verifyToken(Mockito.anyString(), Mockito.anyString())).thenReturn("anyUserId"); + when(DataCacheHandler.getConfigSettings()).thenReturn(configSettingsMap()); + boolean result = + testScenario(getRequest(ActorOperations.MERGE_USER), ResponseCode.invalidIdentifier); + assertTrue(result); + } + + @Test + public void testValidMergeUser() throws Exception { + when(userService.getUserById(Mockito.anyString())) + .thenReturn(getUserDetails(false)) + .thenReturn(getUserDetails(false)); + when(userDao.updateUser(Mockito.anyMap())).thenReturn(getSuccessResponse()); + when(ssoManager.verifyToken(Mockito.anyString())).thenReturn("anyUserId"); + when(ssoManager.verifyToken(Mockito.anyString(), Mockito.anyString())).thenReturn("anyUserId"); + when(DataCacheHandler.getConfigSettings()).thenReturn(configSettingsMap()); + boolean result = testScenario(getRequest(ActorOperations.MERGE_USER), null); + assertTrue(result); + } + + private Map configSettingsMap() { + Map configMap = new HashMap<>(); + configMap.put(JsonKey.CUSTODIAN_ORG_ID, "anyOrgId"); + return configMap; + } + + public static Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + private User getUserDetails(boolean b) { + User user = new User(); + if (userCounter == 0) { + user.setIsDeleted(b); + user.setRootOrgId("anyOrgId"); + } else { + user.setIsDeleted(b); + user.setRootOrgId("orgId"); + } + userCounter++; + return user; + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + Request getRequest(ActorOperations actorOperation) { + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + Map contextMap = new HashMap<>(); + Map header = new HashMap<>(); + String authToken = "authUserToken"; + reqMap.put(JsonKey.FROM_ACCOUNT_ID, "anyUserId"); + reqMap.put(JsonKey.TO_ACCOUNT_ID, "anyUserId"); + header.put(JsonKey.X_AUTHENTICATED_USER_TOKEN, authToken); + header.put(JsonKey.X_SOURCE_USER_TOKEN, authToken); + contextMap.put("header", header); + reqObj.setRequest(reqMap); + reqObj.setContext(contextMap); + reqObj.setOperation(actorOperation.getValue()); + return reqObj; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserProfileActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserProfileActorTest.java new file mode 100644 index 0000000000..85310d7c5f --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserProfileActorTest.java @@ -0,0 +1,143 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.user.actors.UserProfileActor; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + EsClientFactory.class, + ElasticSearchHelper.class, + Util.class, +}) +@PowerMockIgnore({"javax.management.*"}) +public class UserProfileActorTest { + + private ActorSystem system = ActorSystem.create("system"); + + private final Props props = Props.create(UserProfileActor.class); + private CassandraOperationImpl cassandraOperation; + private ElasticSearchService esUtil; + + @Before + public void beforeEachTest() { + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + PowerMockito.mockStatic(Util.class); + SearchDTO searchDTO = Mockito.mock(SearchDTO.class); + when(Util.createSearchDto(Mockito.anyMap())).thenReturn(searchDTO); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + esUtil = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esUtil); + } + + @Test + public void testGetMediaTypesSuccess() { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.GET_MEDIA_TYPES.getValue()); + when(cassandraOperation.getAllRecords(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getSuccessResponse()); + + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res && res.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testSetProfileVisibilitySuccess() { + final String userId = "USER-ID"; + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Promise> promise = Futures.promise(); + promise.success(createGetResponse(true)); + when(esUtil.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId)) + .thenReturn(promise.future()); + when(ElasticSearchHelper.getResponseFromFuture(Mockito.any())) + .thenReturn(createGetResponse(true)); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.PROFILE_VISIBILITY.getValue()); + reqObj.put(JsonKey.USER_ID, userId); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(null != res && res.getResponseCode() == ResponseCode.OK); + } + + @Test + public void testSetProfileVisibilityFailure() { + final String userId = "USER-ID"; + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + Promise> promise = Futures.promise(); + promise.success(null); + when(esUtil.getDataByIdentifier(ProjectUtil.EsType.user.getTypeName(), userId)) + .thenReturn(promise.future()); + when(ElasticSearchHelper.getResponseFromFuture(Mockito.any())).thenReturn(null); + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.PROFILE_VISIBILITY.getValue()); + reqObj.put(JsonKey.USER_ID, userId); + subject.tell(reqObj, probe.getRef()); + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + Assert.assertTrue(res.getCode() == ResponseCode.userNotFound.getErrorCode()); + } + + private Map createGetResponse(boolean isSuccess) { + HashMap response = new HashMap<>(); + if (isSuccess) response.put(JsonKey.CONTENT, "Any-content"); + return response; + } + + private Response getSuccessResponse() { + Response response = new Response(); + List> resMapList = new ArrayList<>(); + Map map = new HashMap<>(); + resMapList.add(map); + response.put(JsonKey.RESPONSE, resMapList); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserProfileReadActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserProfileReadActorTest.java new file mode 100644 index 0000000000..57ab701f13 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserProfileReadActorTest.java @@ -0,0 +1,271 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actorutil.location.impl.LocationClientImpl; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.impl.DefaultDecryptionServiceImpl; +import org.sunbird.common.models.util.datasecurity.impl.DefaultEncryptionServivceImpl; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.services.sso.SSOServiceFactory; +import org.sunbird.services.sso.impl.KeyCloakServiceImpl; +import org.sunbird.user.actors.UserProfileReadActor; +import org.sunbird.user.service.impl.UserServiceImpl; +import org.sunbird.user.util.UserUtil; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class, + SSOServiceFactory.class, + ElasticSearchRestHighImpl.class, + EsClientFactory.class, + Util.class, + RequestRouter.class, + SystemSettingClientImpl.class, + UserServiceImpl.class, + UserUtil.class, + LocationClientImpl.class, + DataCacheHandler.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class UserProfileReadActorTest { + + private ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(UserProfileReadActor.class); + private static Map reqMap; + private static UserServiceImpl userService; + private static CassandraOperationImpl cassandraOperation; + private static DefaultEncryptionServivceImpl encService; + private static DefaultDecryptionServiceImpl decService; + private static KeyCloakServiceImpl ssoManager; + private static final String VALID_USER_ID = "VALID-USER-ID"; + private static final String INVALID_USER_ID = "INVALID-USER-ID"; + private static final String VALID_EMAIL = "someEmail@someDomain.com"; + private static final String INVALID_EMAIL = "someInvalidEmail"; + private static final String VALID_PHONE = "000000000"; + private static final String INVALID_PHONE = "000"; + private static final String VALID_USERNAME = "USERNAME"; + private static ElasticSearchService esService; + + @Before + public void beforeEachTest() { + + ActorRef actorRef = mock(ActorRef.class); + PowerMockito.mockStatic(RequestRouter.class); + when(RequestRouter.getActor(Mockito.anyString())).thenReturn(actorRef); + + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + PowerMockito.mockStatic(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory.class); + encService = mock(DefaultEncryptionServivceImpl.class); + when(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getEncryptionServiceInstance(null)) + .thenReturn(encService); + decService = mock(DefaultDecryptionServiceImpl.class); + when(org.sunbird.common.models.util.datasecurity.impl.ServiceFactory + .getDecryptionServiceInstance(null)) + .thenReturn(decService); + PowerMockito.mockStatic(SSOServiceFactory.class); + ssoManager = mock(KeyCloakServiceImpl.class); + when(SSOServiceFactory.getInstance()).thenReturn(ssoManager); + PowerMockito.mockStatic(SystemSettingClientImpl.class); + SystemSettingClientImpl systemSettingClient = mock(SystemSettingClientImpl.class); + when(SystemSettingClientImpl.getInstance()).thenReturn(systemSettingClient); + when(systemSettingClient.getSystemSettingByFieldAndKey( + Mockito.any(ActorRef.class), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyObject())) + .thenReturn(new HashMap<>()); + + PowerMockito.mockStatic(UserServiceImpl.class); + userService = mock(UserServiceImpl.class); + when(UserServiceImpl.getInstance()).thenReturn(userService); + when(userService.getRootOrgIdFromChannel(Mockito.anyString())).thenReturn("anyId"); + when(userService.getCustodianChannel(Mockito.anyMap(), Mockito.any(ActorRef.class))) + .thenReturn("anyChannel"); + when(userService.getRootOrgIdFromChannel(Mockito.anyString())).thenReturn("rootOrgId"); + + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(Util.class); + Util.getUserProfileConfig(Mockito.any(ActorRef.class)); + + PowerMockito.mockStatic(UserUtil.class); + UserUtil.setUserDefaultValue(Mockito.anyMap(), Mockito.anyString()); + + Map requestMap = new HashMap<>(); + requestMap.put(JsonKey.TNC_ACCEPTED_ON, 12345678L); + requestMap.put(JsonKey.ROOT_ORG_ID, "rootOrgId"); + when(UserUtil.encryptUserData(Mockito.anyMap())).thenReturn(requestMap); + PowerMockito.mockStatic(DataCacheHandler.class); + when(ssoManager.getUsernameById(Mockito.anyString())).thenReturn(VALID_USERNAME); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + } + + @Test + public void testGetUserProfileFailureWithInvalidUserId() { + reqMap = getUserProfileRequest(INVALID_USER_ID); + setEsResponse(null); + boolean result = + testScenario( + getRequest(reqMap, ActorOperations.GET_USER_PROFILE), ResponseCode.userNotFound); + assertTrue(result); + } + + @Test + public void testGetUserProfileSuccessWithValidUserId() { + reqMap = getUserProfileRequest(VALID_USER_ID); + setEsResponse(getUserResponseMap()); + boolean result = testScenario(getRequest(reqMap, ActorOperations.GET_USER_PROFILE), null); + assertTrue(result); + } + + @Test + @Ignore + public void testGetUserByEmailKeyFailureWithInvalidEmail() { + reqMap = getUserProfileByKeyRequest(JsonKey.EMAIL, INVALID_EMAIL); + setCassandraResponse(getCassandraResponse(false)); + boolean result = + testScenario( + getRequest(reqMap, ActorOperations.GET_USER_BY_KEY), ResponseCode.userNotFound); + assertTrue(result); + } + + @Test + @Ignore + public void testGetUserByEmailKeySuccessWithValidEmail() { + reqMap = getUserProfileByKeyRequest(JsonKey.EMAIL, VALID_EMAIL); + setCassandraResponse(getCassandraResponse(true)); + boolean result = testScenario(getRequest(reqMap, ActorOperations.GET_USER_BY_KEY), null); + assertTrue(result); + } + + @Test + @Ignore + public void testGetUserByPhoneKeyFailureWithInvalidPhone() { + reqMap = getUserProfileByKeyRequest(JsonKey.PHONE, INVALID_PHONE); + setCassandraResponse(getCassandraResponse(false)); + boolean result = + testScenario( + getRequest(reqMap, ActorOperations.GET_USER_BY_KEY), ResponseCode.userNotFound); + assertTrue(result); + } + + @Test + @Ignore + public void testGetUserByPhoneKeySuccessWithValidPhone() { + reqMap = getUserProfileByKeyRequest(JsonKey.PHONE, VALID_PHONE); + setCassandraResponse(getCassandraResponse(true)); + boolean result = testScenario(getRequest(reqMap, ActorOperations.GET_USER_BY_KEY), null); + assertTrue(result); + } + + private void setCassandraResponse(Response cassandraResponse) { + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(cassandraResponse); + } + + private Response getCassandraResponse(boolean success) { + Response response = new Response(); + if (success) { + List> userList = new ArrayList<>(); + userList.add(getUserResponseMap()); + response.put(JsonKey.RESPONSE, userList); + } + return response; + } + + private boolean testScenario(Request reqObj, ResponseCode errorCode) { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + private Map getUserProfileRequest(String userId) { + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, userId); + return reqMap; + } + + private Map getUserProfileByKeyRequest(String key, String value) { + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.KEY, key); + reqMap.put(JsonKey.VALUE, value); + return reqMap; + } + + private Request getRequest(Map reqMap, ActorOperations actorOperation) { + Request reqObj = new Request(); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.REQUESTED_BY, "requestedBy"); + innerMap.put(JsonKey.PRIVATE, false); + reqObj.setRequest(reqMap); + reqObj.setContext(innerMap); + reqObj.setOperation(actorOperation.getValue()); + return reqObj; + } + + private static Map getUserResponseMap() { + Map map = new HashMap<>(); + map.put(JsonKey.USER_ID, VALID_USER_ID); + map.put(JsonKey.CHANNEL, "anyChannel"); + return map; + } + + public void setEsResponse(Map esResponse) { + Promise> promise = Futures.promise(); + promise.success(esResponse); + when(esService.getDataByIdentifier(Mockito.anyString(), Mockito.anyString())) + .thenReturn(promise.future()); + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserRoleActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserRoleActorTest.java new file mode 100644 index 0000000000..5e84679525 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserRoleActorTest.java @@ -0,0 +1,263 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actor.service.BaseMWService; +import org.sunbird.actorutil.InterServiceCommunication; +import org.sunbird.actorutil.InterServiceCommunicationFactory; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.datasecurity.DecryptionService; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.dto.SearchDTO; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.actors.role.dao.impl.RoleDaoImpl; +import org.sunbird.learner.util.Util; +import org.sunbird.user.actors.UserRoleActor; +import org.sunbird.user.dao.UserOrgDao; +import org.sunbird.user.dao.impl.UserOrgDaoImpl; +import scala.concurrent.Promise; +import scala.concurrent.duration.Duration; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + RoleDaoImpl.class, + BaseMWService.class, + RequestRouter.class, + InterServiceCommunicationFactory.class, + EsClientFactory.class, + ElasticSearchRestHighImpl.class, + Util.class, + UserOrgDaoImpl.class, + DecryptionService.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class UserRoleActorTest { + + private ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(UserRoleActor.class); + private static final InterServiceCommunication interServiceCommunication = + Mockito.mock(InterServiceCommunication.class); + private static final Response response = Mockito.mock(Response.class); + private static CassandraOperationImpl cassandraOperation; + private static ElasticSearchRestHighImpl esService; + + @BeforeClass + public static void beforeClass() { + + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + } + + private static Response getRecordByPropertyResponse() { + + Response response = new Response(); + List> list = new ArrayList<>(); + Map orgMap = new HashMap<>(); + orgMap.put(JsonKey.ID, "ORGANISATION_ID"); + list.add(orgMap); + response.put(JsonKey.RESPONSE, list); + return response; + } + + @Before + public void beforeEachTest() { + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(BaseMWService.class); + PowerMockito.mockStatic(RequestRouter.class); + PowerMockito.mockStatic(InterServiceCommunicationFactory.class); + PowerMockito.mockStatic(RoleDaoImpl.class); + PowerMockito.mockStatic(Util.class); + PowerMockito.mockStatic(UserOrgDaoImpl.class); + PowerMockito.mockStatic(EsClientFactory.class); + + when(InterServiceCommunicationFactory.getInstance()).thenReturn(interServiceCommunication); + RoleDaoImpl roleDao = Mockito.mock(RoleDaoImpl.class); + when(RoleDaoImpl.getInstance()).thenReturn(roleDao); + UserOrgDao userOrgDao = Mockito.mock(UserOrgDaoImpl.class); + when(UserOrgDaoImpl.getInstance()).thenReturn(userOrgDao); + when(userOrgDao.updateUserOrg(Mockito.anyObject())).thenReturn(getSuccessResponse()); + CompletionStage completionStage = Mockito.mock(CompletionStage.class); + ActorSelection actorSelection = Mockito.mock(ActorSelection.class); + when(BaseMWService.getRemoteRouter(Mockito.anyString())).thenReturn(actorSelection); + when(actorSelection.resolveOneCS(Duration.create(Mockito.anyLong(), "seconds"))) + .thenReturn(completionStage); + ActorRef actorRef = Mockito.mock(ActorRef.class); + when(RequestRouter.getActor(Mockito.anyString())).thenReturn(actorRef); + SearchDTO searchDTO = Mockito.mock(SearchDTO.class); + when(Util.createSearchDto(Mockito.anyMap())).thenReturn(searchDTO); + + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + when(cassandraOperation.getAllRecords(Mockito.anyString(), Mockito.anyString())) + .thenReturn(getCassandraResponse()); + when(cassandraOperation.getRecordsByProperties( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getRecordByPropertyResponse()); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + } + + @Test + public void testGetUserRoleSuccess() { + assertTrue(testScenario(true, true, null)); + } + + @Test + public void testAssignRolesSuccessWithValidOrgId() { + assertTrue(testScenario(true, null)); + } + + @Test + public void testAssignRolesSuccessWithoutOrgId() { + assertTrue(testScenario(false, null)); + } + + @Test + public void testAssignRolesFailure() { + assertTrue(testScenario(false, ResponseCode.CLIENT_ERROR)); + } + + @Test + public void testAssignRolesFailureWithInvalidOrgId() { + assertTrue(testScenario(false, ResponseCode.invalidParameterValue)); + } + + private boolean testScenario(boolean isOrgIdReq, ResponseCode errorResponse) { + return testScenario(false, isOrgIdReq, errorResponse); + } + + private boolean testScenario( + boolean isGetUserRoles, boolean isOrgIdReq, ResponseCode errorResponse) { + + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + if (isGetUserRoles) { + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.GET_ROLES.getValue()); + subject.tell(reqObj, probe.getRef()); + } else { + DecryptionService decryptionService = Mockito.mock(DecryptionService.class); + when(decryptionService.decryptData(Mockito.anyMap())).thenReturn(getOrganisationsMap()); + when(interServiceCommunication.getResponse(Mockito.anyObject(), Mockito.anyObject())) + .thenReturn(response); + if (errorResponse == null) { + when(response.get(Mockito.anyString())).thenReturn(new HashMap<>()); + mockGetOrgResponse(true); + } else { + mockGetOrgResponse(false); + } + subject.tell(getRequestObj(isOrgIdReq), probe.getRef()); + } + if (errorResponse == null) { + Response res = probe.expectMsgClass(duration("100 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("100 second"), ProjectCommonException.class); + return res.getCode().equals(errorResponse.getErrorCode()) + || res.getResponseCode() == errorResponse.getResponseCode(); + } + } + + private Map getOrganisationsMap() { + + Map orgMap = new HashMap<>(); + List> list = new ArrayList<>(); + orgMap.put(JsonKey.ORGANISATION_ID, "ORGANISATION_ID"); + list.add(orgMap); + orgMap.put(JsonKey.ORGANISATIONS, list); + return orgMap; + } + + private Map createResponseGet(boolean isResponseRequired) { + HashMap response = new HashMap<>(); + List> content = new ArrayList<>(); + HashMap innerMap = new HashMap<>(); + innerMap.put(JsonKey.CONTACT_DETAILS, "CONTACT_DETAILS"); + innerMap.put(JsonKey.ID, "ORGANISATION_ID"); + innerMap.put(JsonKey.HASHTAGID, "HASHTAGID"); + HashMap orgMap = new HashMap<>(); + orgMap.put(JsonKey.ORGANISATION_ID, "ORGANISATION_ID"); + List> orgList = new ArrayList<>(); + orgList.add(orgMap); + innerMap.put(JsonKey.ORGANISATIONS, orgList); + if (isResponseRequired) { + content.add(innerMap); + } + response.put(JsonKey.CONTENT, content); + return response; + } + + private Object getRequestObj(boolean isOrgIdReq) { + Request reqObj = new Request(); + List roleLst = new ArrayList(); + roleLst.add("anyRole"); + reqObj.put(JsonKey.ROLES, roleLst); + reqObj.put(JsonKey.EXTERNAL_ID, "EXTERNAL_ID"); + reqObj.put(JsonKey.USER_ID, "USER_ID"); + reqObj.put(JsonKey.HASHTAGID, "HASHTAGID"); + reqObj.put(JsonKey.PROVIDER, "PROVIDER"); + if (isOrgIdReq) { + reqObj.put(JsonKey.ORGANISATION_ID, "ORGANISATION_ID"); + } + reqObj.setOperation(ActorOperations.ASSIGN_ROLES.getValue()); + return reqObj; + } + + private void mockGetOrgResponse(boolean isResponseRequired) { + Promise> promise = Futures.promise(); + promise.success(createResponseGet(isResponseRequired)); + when(esService.search(Mockito.any(SearchDTO.class), Mockito.anyVararg())) + .thenReturn(promise.future()); + } + + private static Response getCassandraResponse() { + Response response = new Response(); + List> list = new ArrayList<>(); + Map orgMap = new HashMap<>(); + orgMap.put(JsonKey.ID, "ORGANISATION_ID"); + list.add(orgMap); + response.put(JsonKey.RESPONSE, list); + return response; + } + + private Response getSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserServiceGenerateUsernameTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserServiceGenerateUsernameTest.java new file mode 100644 index 0000000000..c6b50d7f0b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserServiceGenerateUsernameTest.java @@ -0,0 +1,62 @@ +package org.sunbird.user; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.junit.Test; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; + +public class UserServiceGenerateUsernameTest { + + private static String englishName = "Some Random Name"; + private static String hindiName = "कोई अज्ञात नाम"; + private static String teluguName = "సుధీర్"; + private static String tamilName = "எந்த அறியப்படாத பெயர்"; + private static Pattern pattern; + private static String userNameValidatorRegex = "(^([a-z])+[0-9]{4})"; + private static UserService userService = new UserServiceImpl(); + + @Test + public void testGenerateUsernamesSuccessWithEnglishName() { + assertTrue(performTest(englishName)); + } + + @Test + public void testGenerateUsernamesFailureWithBlankName() { + List result = userService.generateUsernames("", new ArrayList()); + assertTrue(result == null); + } + + @Test + public void testGenerateUsernamesSuccessWithHindiName() { + assertTrue(performTest(hindiName)); + } + + @Test + public void testGenerateUsernamesSuccessWithTeluguName() { + assertTrue(performTest(teluguName)); + } + + @Test + public void testGenerateUsernamesSuccessWithTamilName() { + assertTrue(performTest(tamilName)); + } + + private boolean performTest(String name) { + List result = userService.generateUsernames(name, new ArrayList()); + pattern = Pattern.compile(userNameValidatorRegex); + boolean flag = true; + for (int i = 0; i < result.size(); i++) { + Matcher matcher = pattern.matcher(result.get(i)); + if (!matcher.matches()) { + flag = false; + break; + } + } + return flag; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserStatusActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserStatusActorTest.java new file mode 100644 index 0000000000..1c5f9452f8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserStatusActorTest.java @@ -0,0 +1,155 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.admin.client.resource.UsersResource; +import org.keycloak.representations.idm.UserRepresentation; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.KeyCloakConnectionProvider; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.models.user.User; +import org.sunbird.user.actors.UserStatusActor; +import org.sunbird.user.service.UserService; +import org.sunbird.user.service.impl.UserServiceImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({UserServiceImpl.class, KeyCloakConnectionProvider.class, ServiceFactory.class}) +@PowerMockIgnore("javax.management.*") +public class UserStatusActorTest { + + private static final Props props = Props.create(UserStatusActor.class); + private static final ActorSystem system = ActorSystem.create("system"); + private static final User user = mock(User.class); + private static final CassandraOperationImpl cassandraOperation = + mock(CassandraOperationImpl.class);; + + @BeforeClass + public static void beforeClass() { + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + Response response = createCassandraUpdateSuccessResponse(); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(response); + } + + @Before + public void init() { + + UserRepresentation userRepresentation = mock(UserRepresentation.class); + RealmResource realmResource = mock(RealmResource.class); + Keycloak keycloak = mock(Keycloak.class); + + PowerMockito.mockStatic(UserServiceImpl.class); + UserService userService = mock(UserService.class); + when(UserServiceImpl.getInstance()).thenReturn(userService); + + PowerMockito.mockStatic(KeyCloakConnectionProvider.class); + when(KeyCloakConnectionProvider.getConnection()).thenReturn(keycloak); + when(keycloak.realm(Mockito.anyString())).thenReturn(realmResource); + + UsersResource usersResource = mock(UsersResource.class); + when(realmResource.users()).thenReturn(usersResource); + + UserResource userResource = mock(UserResource.class); + when(usersResource.get(Mockito.any())).thenReturn(userResource); + when(userResource.toRepresentation()).thenReturn(userRepresentation); + when(userService.getUserById(Mockito.anyString())).thenReturn(user); + } + + @Test + public void testBlockUserSuccess() { + boolean result = testScenario(false, ActorOperations.BLOCK_USER, true, null); + assertTrue(result); + } + + @Test + public void testBlockUserFailureWithUserAlreadyInactive() { + boolean result = + testScenario( + true, + ActorOperations.BLOCK_USER, + false, + ResponseCode.userAlreadyInactive.getErrorCode()); + assertTrue(result); + } + + @Test + public void testUnblockUserSuccess() { + boolean result = testScenario(true, ActorOperations.UNBLOCK_USER, true, null); + assertTrue(result); + } + + @Test + public void testUnblockUserFailureWithUserAlreadyActive() { + boolean result = + testScenario( + false, + ActorOperations.UNBLOCK_USER, + false, + ResponseCode.userAlreadyActive.getErrorCode()); + assertTrue(result); + } + + private Request getRequestObject(String operation) { + + Request reqObj = new Request(); + String userId = "someUserId"; + reqObj.setOperation(operation); + reqObj.put(JsonKey.USER_ID, userId); + return reqObj; + } + + private static Response createCassandraUpdateSuccessResponse() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + return response; + } + + private boolean testScenario( + boolean isDeleted, + ActorOperations operation, + boolean isSuccess, + String expectedErrorResponse) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + when(user.getIsDeleted()).thenReturn(isDeleted); + subject.tell(getRequestObject(operation.getValue()), probe.getRef()); + + Response res; + if (isSuccess) { + res = probe.expectMsgClass(duration("10 second"), Response.class); + return (res != null && "SUCCESS".equals(res.getResult().get(JsonKey.RESPONSE))); + } else { + ProjectCommonException exception = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return (((ProjectCommonException) exception).getCode().equals(expectedErrorResponse)); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserTypeActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserTypeActorTest.java new file mode 100644 index 0000000000..20475d27f7 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/UserTypeActorTest.java @@ -0,0 +1,59 @@ +package org.sunbird.user; + +import static akka.testkit.JavaTestKit.duration; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.*; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.KeyCloakConnectionProvider; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.user.actors.UserTypeActor; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({KeyCloakConnectionProvider.class}) +@PowerMockIgnore("javax.management.*") +public class UserTypeActorTest { + + private static ActorSystem system = ActorSystem.create("system"); + private static final Props props = Props.create(UserTypeActor.class); + + @Test + public void testGetUserTypesSuccess() { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + + Request reqObj = new Request(); + reqObj.setOperation(ActorOperations.GET_USER_TYPES.getValue()); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + Assert.assertTrue(res.getResponseCode() == ResponseCode.OK && getResponse(res)); + } + + private boolean getResponse(Response res) { + + List> lst = + (List>) res.getResult().get(JsonKey.RESPONSE); + Set types = new HashSet<>(); + for (Map map : lst) { + Iterator> itr = map.entrySet().iterator(); + while (itr.hasNext()) { + Map.Entry entry = itr.next(); + types.add(entry.getValue()); + } + } + if (types.contains("OTHER") && types.contains("TEACHER") && types.size() == 2) return true; + return false; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/IdentifierFreeUpActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/IdentifierFreeUpActorTest.java new file mode 100644 index 0000000000..2c20bcf816 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/IdentifierFreeUpActorTest.java @@ -0,0 +1,186 @@ +package org.sunbird.user.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.dispatch.Futures; +import akka.testkit.javadsl.TestKit; +import java.util.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.CassandraUtil; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.Util; +import org.sunbird.user.service.impl.UserServiceImpl; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + UserServiceImpl.class, + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + ElasticSearchHelper.class, + EsClientFactory.class, + CassandraOperationImpl.class, + CassandraOperation.class, + CassandraUtil.class, +}) +@PowerMockIgnore({"javax.management.*"}) +public class IdentifierFreeUpActorTest { + private ElasticSearchService elasticSearchService; + public static CassandraOperation cassandraOperation; + private Util.DbInfo usrDbInfo = Util.dbInfoMap.get(JsonKey.USER_DB); + Props props = Props.create(IdentifierFreeUpActor.class); + ActorSystem system = ActorSystem.create("IdentifierFreeUpActor"); + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(ElasticSearchRestHighImpl.class); + elasticSearchService = PowerMockito.mock(ElasticSearchService.class); + PowerMockito.mockStatic(EsClientFactory.class); + when(EsClientFactory.getInstance(JsonKey.REST)).thenReturn(elasticSearchService); + PowerMockito.mockStatic(ElasticSearchHelper.class); + cassandraOperation = PowerMockito.mock(CassandraOperation.class); + PowerMockito.mockStatic(ServiceFactory.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + } + + @Test + public void testFreeUpWhenUserNotExists() { + String id = "wrongUserId"; + Response response = new Response(); + response.put(JsonKey.RESPONSE, new ArrayList<>()); + when(cassandraOperation.getRecordById(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), id)) + .thenReturn(response); + boolean result = + testScenario( + getFreeUpRequest(ActorOperations.FREEUP_USER_IDENTITY), ResponseCode.invalidUserId); + assertTrue(result); + } + + @Test + public void testFreeUpWhenOnlyFreeUpEmail() { + String id = "anyUserId"; + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.ID, "anyUserId"); + reqMap.put(JsonKey.IDENTIFIER, new ArrayList<>(Arrays.asList("email"))); + reqObj.setRequest(reqMap); + reqObj.setOperation(ActorOperations.FREEUP_USER_IDENTITY.getValue()); + Response response = new Response(); + List> responseList = new ArrayList<>(); + Map userDbMap = new HashMap<>(); + userDbMap.put(JsonKey.EMAIL, "userPrimaryEmail"); + userDbMap.put(JsonKey.PHONE, "9876543210"); + userDbMap.put(JsonKey.PREV_USED_EMAIL, null); + userDbMap.put(JsonKey.EMAIL_VERIFIED, true); + userDbMap.put(JsonKey.PHONE_VERIFIED, true); + userDbMap.put(JsonKey.PREV_USED_PHONE, null); + userDbMap.put(JsonKey.MASKED_EMAIL, "user*******"); + userDbMap.put(JsonKey.MASKED_PHONE, "98***08908"); + userDbMap.put(JsonKey.FLAGS_VALUE, 3); + userDbMap.put(JsonKey.ID, id); + responseList.add(userDbMap); + response.put(JsonKey.RESPONSE, responseList); + when(cassandraOperation.getRecordById(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), id)) + .thenReturn(response); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(new Response()); + Promise promise = Futures.promise(); + promise.success(true); + when(elasticSearchService.update(Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(promise.future()); + when(ElasticSearchHelper.getResponseFromFuture(promise.future())).thenReturn(true); + boolean result = testScenario(reqObj, null); + assertTrue(result); + } + + @Test + public void testFreeUpWhenOnlyFreeUpPhone() { + String id = "anyUserId"; + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.ID, "anyUserId"); + reqMap.put(JsonKey.IDENTIFIER, new ArrayList<>(Arrays.asList("phone"))); + reqObj.setRequest(reqMap); + reqObj.setOperation(ActorOperations.FREEUP_USER_IDENTITY.getValue()); + Response response = new Response(); + List> responseList = new ArrayList<>(); + Map userDbMap = new HashMap<>(); + userDbMap.put(JsonKey.EMAIL, "userPrimaryEmail"); + userDbMap.put(JsonKey.PHONE, "9876543210"); + userDbMap.put(JsonKey.PREV_USED_EMAIL, null); + userDbMap.put(JsonKey.EMAIL_VERIFIED, true); + userDbMap.put(JsonKey.PHONE_VERIFIED, true); + userDbMap.put(JsonKey.PREV_USED_PHONE, null); + userDbMap.put(JsonKey.MASKED_EMAIL, "user*******"); + userDbMap.put(JsonKey.MASKED_PHONE, "98***08908"); + userDbMap.put(JsonKey.FLAGS_VALUE, 3); + userDbMap.put(JsonKey.ID, id); + responseList.add(userDbMap); + response.put(JsonKey.RESPONSE, responseList); + when(cassandraOperation.getRecordById(usrDbInfo.getKeySpace(), usrDbInfo.getTableName(), id)) + .thenReturn(response); + when(cassandraOperation.updateRecord( + Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(new Response()); + Promise promise = Futures.promise(); + promise.success(true); + when(elasticSearchService.update(Mockito.anyString(), Mockito.anyString(), Mockito.anyMap())) + .thenReturn(promise.future()); + when(ElasticSearchHelper.getResponseFromFuture(promise.future())).thenReturn(true); + boolean result = testScenario(reqObj, null); + assertTrue(result); + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + System.out.println("the success response is" + res); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + System.out.println("the failure response is " + res); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + private Request getFreeUpRequest(ActorOperations actorOperation) { + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.ID, "wrongUserId"); + reqMap.put(JsonKey.IDENTIFIER, new ArrayList<>()); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation.getValue()); + return reqObj; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/JobProfileManagementActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/JobProfileManagementActorTest.java new file mode 100644 index 0000000000..57ca1329c3 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/JobProfileManagementActorTest.java @@ -0,0 +1,298 @@ +package org.sunbird.user.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.doNothing; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.user.dao.AddressDao; +import org.sunbird.user.dao.JobProfileDao; +import org.sunbird.user.dao.impl.AddressDaoImpl; +import org.sunbird.user.dao.impl.JobProfileDaoImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({AddressDaoImpl.class, ServiceFactory.class, JobProfileDaoImpl.class}) +@PowerMockIgnore({"javax.management.*"}) +public class JobProfileManagementActorTest { + private AddressDao addressDao; + private JobProfileDao jobProfileDao; + Props props = Props.create(JobProfileManagementActor.class); + ActorSystem system = ActorSystem.create("JobProfileManagementActor"); + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(AddressDaoImpl.class); + PowerMockito.mockStatic(JobProfileDaoImpl.class); + addressDao = PowerMockito.mock(AddressDao.class); + jobProfileDao = PowerMockito.mock(JobProfileDao.class); + when(AddressDaoImpl.getInstance()).thenReturn(addressDao); + when(JobProfileDaoImpl.getInstance()).thenReturn(jobProfileDao); + } + + @Test + public void testInsertUserJobProfileWithoutAddressSuccess() { + doNothing().when(jobProfileDao).createJobProfile(Mockito.anyMap()); + boolean result = testScenario(getJobProfileRequest("insertUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testInsertUserJobProfileWithAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = testScenario(getJobProfileRequestWithAddress("insertUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testInsertUserJobProfileWithAddressIdSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = testScenario(getJobProfileRequestWithAddressId("insertUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserJobProfileWithoutAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = testScenario(getJobProfileRequest("updateUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserJobProfileWithoutAddressAndIsDeletedSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = testScenario(getJobProfileRequestWithIsDeleted("updateUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserJobProfileWithAddressAndIsDeletedSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = testScenario(getJobProfileRequestWithAddress("updateUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserJobProfileWithAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = + testScenario(getJobProfileRequestWithAddressAndId("updateUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testUpdateUserJobProfileWithOutAddressSuccess() { + Response response = new Response(); + response.put(JsonKey.RESPONSE, JsonKey.SUCCESS); + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(response); + boolean result = testScenario(getJobProfileRequestWithIsDeleted("updateUserJobProfile"), null); + assertTrue(result); + } + + @Test + public void testInsertUserJobProfileWithAddressFailure() { + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(new Response()); + Response result = testScenario(getJobProfileRequestWithAddress("insertUserJobProfile")); + Assert.assertEquals( + "Error occurred while inserting job profile details.", + ((List) result.get(JsonKey.ERROR_MSG)).get(0)); + } + + @Test + public void testUpdateUserJobProfileWithAddressFailure() { + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(new Response()); + Response result = testScenario(getJobProfileRequestWithAddress("updateUserJobProfile")); + Assert.assertEquals( + "Error occurred while updating job profile details.", + ((List) result.get(JsonKey.ERROR_MSG)).get(0)); + } + + @Test + public void testInsertUserJobProfileWithInvalidOperation() { + when(addressDao.upsertAddress(Mockito.anyMap())).thenReturn(new Response()); + boolean result = + testScenario( + getJobProfileRequestWithAddress("invalidOperation"), ResponseCode.invalidRequestData); + Assert.assertTrue(result); + } + + private Request getJobProfileRequest(String actorOperation) { + Request reqObj = new Request(); + Map jobProfileMap = new HashMap<>(); + jobProfileMap.put(JsonKey.ID, "anyJobId"); + jobProfileMap.put(JsonKey.IS_DELETED, false); + jobProfileMap.put(JsonKey.JOB_NAME, "anyJobName"); + jobProfileMap.put(JsonKey.ROLE, "TEACHER"); + jobProfileMap.put(JsonKey.JOINING_DATE, null); + jobProfileMap.put(JsonKey.ORG_NAME, "anyOrgName"); + jobProfileMap.put(JsonKey.ORG_ID, "anyOrgId"); + List> jobProfileList = new ArrayList<>(); + jobProfileList.add(jobProfileMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.JOB_PROFILE, jobProfileList); + reqMap.put(JsonKey.CREATED_BY, "adminUser"); + + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation); + return reqObj; + } + + private Request getJobProfileRequestWithIsDeleted(String actorOperation) { + Request reqObj = new Request(); + Map jobProfileMap = new HashMap<>(); + jobProfileMap.put(JsonKey.ID, "anyJobId"); + jobProfileMap.put(JsonKey.IS_DELETED, true); + jobProfileMap.put(JsonKey.JOB_NAME, "anyJobName"); + jobProfileMap.put(JsonKey.ROLE, "TEACHER"); + jobProfileMap.put(JsonKey.JOINING_DATE, null); + jobProfileMap.put(JsonKey.ORG_NAME, "anyOrgName"); + jobProfileMap.put(JsonKey.ORG_ID, "anyOrgId"); + List> jobProfileList = new ArrayList<>(); + jobProfileList.add(jobProfileMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.JOB_PROFILE, jobProfileList); + reqMap.put(JsonKey.CREATED_BY, "adminUser"); + + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation); + return reqObj; + } + + private Request getJobProfileRequestWithAddress(String actorOperation) { + Request reqObj = new Request(); + Map jobProfileMap = new HashMap<>(); + Map addressMap = new HashMap<>(); + addressMap.put(JsonKey.ADD_TYPE, ProjectUtil.AddressType.home.getTypeName()); + addressMap.put(JsonKey.ADDRESS_LINE1, "any address"); + addressMap.put(JsonKey.CITY, "anyCity"); + addressMap.put(JsonKey.STATE, "KARANATAKA"); + addressMap.put(JsonKey.ZIPCODE, "anyZipCode"); + jobProfileMap.put(JsonKey.JOB_NAME, "anyJobName"); + jobProfileMap.put(JsonKey.ROLE, "TEACHER"); + jobProfileMap.put(JsonKey.IS_DELETED, true); + jobProfileMap.put(JsonKey.JOINING_DATE, null); + jobProfileMap.put(JsonKey.ORG_NAME, "anyOrgName"); + jobProfileMap.put(JsonKey.ORG_ID, "anyOrgId"); + jobProfileMap.put(JsonKey.ADDRESS, addressMap); + List> jobProfileList = new ArrayList<>(); + jobProfileList.add(jobProfileMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.JOB_PROFILE, jobProfileList); + reqMap.put(JsonKey.CREATED_BY, "adminUser"); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation); + return reqObj; + } + + private Request getJobProfileRequestWithAddressAndId(String actorOperation) { + Request reqObj = new Request(); + Map jobProfileMap = new HashMap<>(); + Map addressMap = new HashMap<>(); + addressMap.put(JsonKey.ADD_TYPE, ProjectUtil.AddressType.home.getTypeName()); + addressMap.put(JsonKey.ADDRESS_LINE1, "any address"); + addressMap.put(JsonKey.CITY, "anyCity"); + addressMap.put(JsonKey.STATE, "KARANATAKA"); + addressMap.put(JsonKey.ZIPCODE, "anyZipCode"); + jobProfileMap.put(JsonKey.JOB_NAME, "anyJobName"); + jobProfileMap.put(JsonKey.ROLE, "TEACHER"); + jobProfileMap.put(JsonKey.IS_DELETED, true); + jobProfileMap.put(JsonKey.ID, "anyJobId"); + jobProfileMap.put(JsonKey.JOINING_DATE, null); + jobProfileMap.put(JsonKey.ORG_NAME, "anyOrgName"); + jobProfileMap.put(JsonKey.ORG_ID, "anyOrgId"); + jobProfileMap.put(JsonKey.ADDRESS, addressMap); + List> jobProfileList = new ArrayList<>(); + jobProfileList.add(jobProfileMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.JOB_PROFILE, jobProfileList); + reqMap.put(JsonKey.CREATED_BY, "adminUser"); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation); + return reqObj; + } + + private Request getJobProfileRequestWithAddressId(String actorOperation) { + Request reqObj = new Request(); + Map jobProfileMap = new HashMap<>(); + Map addressMap = new HashMap<>(); + addressMap.put(JsonKey.ADD_TYPE, ProjectUtil.AddressType.home.getTypeName()); + addressMap.put(JsonKey.ADDRESS_LINE1, "any address"); + addressMap.put(JsonKey.CITY, "anyCity"); + addressMap.put(JsonKey.ID, "anyId"); + addressMap.put(JsonKey.STATE, "KARANATAKA"); + addressMap.put(JsonKey.ZIPCODE, "anyZipCode"); + jobProfileMap.put(JsonKey.JOB_NAME, "anyJobName"); + jobProfileMap.put(JsonKey.ROLE, "TEACHER"); + jobProfileMap.put(JsonKey.JOINING_DATE, null); + jobProfileMap.put(JsonKey.ORG_NAME, "anyOrgName"); + jobProfileMap.put(JsonKey.ORG_ID, "anyOrgId"); + jobProfileMap.put(JsonKey.ADDRESS, addressMap); + List> jobProfileList = new ArrayList<>(); + jobProfileList.add(jobProfileMap); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.JOB_PROFILE, jobProfileList); + reqMap.put(JsonKey.CREATED_BY, "adminUser"); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation); + return reqObj; + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } + + public Response testScenario(Request reqObj) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return res; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/ResetPasswordActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/ResetPasswordActorTest.java new file mode 100644 index 0000000000..c2abf6b82b --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/ResetPasswordActorTest.java @@ -0,0 +1,188 @@ +package org.sunbird.user.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.mockito.Mockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import org.sunbird.user.dao.UserDao; +import org.sunbird.user.dao.impl.UserDaoImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({UserDao.class, UserDaoImpl.class, Util.class, UserUtility.class}) +@PowerMockIgnore({"javax.management.*"}) +public class ResetPasswordActorTest { + + private UserDao userDao; + Props props = Props.create(ResetPasswordActor.class); + ActorSystem system = ActorSystem.create("ResetPasswordActor"); + + @Before + public void beforeEachTest() { + userDao = PowerMockito.mock(UserDao.class); + PowerMockito.mockStatic(UserDaoImpl.class); + when(UserDaoImpl.getInstance()).thenReturn(userDao); + PowerMockito.mockStatic(UserUtility.class); + PowerMockito.mockStatic(Util.class); + when(Util.getUserRequiredActionLink(Mockito.anyMap(), Mockito.anyBoolean())) + .thenReturn("/url/password"); + when(Util.getSunbirdLoginUrl()).thenReturn("/resource/url"); + when(UserUtility.decryptUserData(Mockito.anyMap())).thenReturn(getUserDbMap()); + when(userDao.getUserById("ValidUserId")).thenReturn(getValidUserResponse()); + } + + @Test + public void testResetPasswordWithInvalidUserIdFailure() { + when(userDao.getUserById("invalidUserId")).thenReturn(null); + boolean result = testScenario(getInvalidRequest(), ResponseCode.userNotFound); + Assert.assertTrue(result); + } + + @Test + public void testResetPasswordWithKeyPhoneSuccess() throws Exception { + when(UserUtility.decryptUserData(Mockito.anyMap())).thenReturn(getUserDbMap()); + boolean result = testScenario(getValidRequestWithKeyPhone(), null); + Assert.assertTrue(result); + } + + @Test + public void testResetPasswordWithKeyEmailSuccess() throws Exception { + when(UserUtility.decryptUserData(Mockito.anyMap())).thenReturn(getUserDbMap()); + boolean result = testScenario(getValidRequestWithKeyEmail(), null); + Assert.assertTrue(result); + } + + @Test + public void testResetPasswordWithKeyPrevUsedEmailSuccess() throws Exception { + when(UserUtility.decryptUserData(Mockito.anyMap())).thenReturn(getUserDbMap()); + boolean result = testScenario(getValidRequestWithKeyPrevUsedEmail(), null); + Assert.assertTrue(result); + } + + @Test + public void testResetPasswordWithKeyPrevUsedPhoneSuccess() throws Exception { + boolean result = testScenario(getValidRequestWithKeyPrevUsedPhone(), null); + Assert.assertTrue(result); + } + + private Request getInvalidRequest() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "invalidUserId"); + reqMap.put(JsonKey.TYPE, "phone"); + request.setRequest(reqMap); + request.setOperation("resetPassword"); + return request; + } + + private Request getValidRequestWithKeyPhone() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "ValidUserId"); + reqMap.put(JsonKey.TYPE, "phone"); + request.setRequest(reqMap); + request.setOperation("resetPassword"); + return request; + } + + private Request getValidRequestWithKeyPrevUsedPhone() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "ValidUserId"); + reqMap.put(JsonKey.TYPE, "prevUsedPhone"); + request.setRequest(reqMap); + request.setOperation("resetPassword"); + return request; + } + + private Request getValidRequestWithKeyEmail() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "ValidUserId"); + reqMap.put(JsonKey.TYPE, "email"); + request.setRequest(reqMap); + request.setOperation("resetPassword"); + return request; + } + + private Request getValidRequestWithKeyPrevUsedEmail() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "ValidUserId"); + reqMap.put(JsonKey.TYPE, "prevUsedEmail"); + request.setRequest(reqMap); + request.setOperation("resetPassword"); + return request; + } + + private User getValidUserResponse() { + User user = new User(); + user.setId("ValidUserId"); + user.setEmail("anyEmail@gmail.com"); + user.setChannel("TN"); + user.setPhone("9876543210"); + user.setMaskedEmail("any****@gmail.com"); + user.setMaskedPhone("987*****0"); + user.setIsDeleted(false); + user.setFlagsValue(3); + user.setUserType("TEACHER"); + user.setUserId("ValidUserId"); + user.setFirstName("Demo Name"); + user.setUserName("validUserName"); + return user; + } + + private Map getUserDbMap() { + Map userDbMap = new HashMap<>(); + userDbMap.put(JsonKey.SET_PASSWORD_LINK, "/password/link/url"); + userDbMap.put(JsonKey.USERNAME, "validUserName"); + userDbMap.put(JsonKey.CHANNEL, "TN"); + userDbMap.put(JsonKey.EMAIL, "anyEmail@gmail.com"); + userDbMap.put(JsonKey.PHONE, "9876543210"); + userDbMap.put(JsonKey.FLAGS_VALUE, 3); + userDbMap.put(JsonKey.USER_TYPE, "TEACHER"); + userDbMap.put(JsonKey.MASKED_PHONE, "987*****0"); + userDbMap.put(JsonKey.USER_ID, "ValidUserId"); + userDbMap.put(JsonKey.ID, "ValidUserId"); + userDbMap.put(JsonKey.FIRST_NAME, "Demo Name"); + userDbMap.put(JsonKey.REDIRECT_URI, "/resource/url"); + userDbMap.put(JsonKey.IS_DELETED, false); + return userDbMap; + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/TenantMigrationActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/TenantMigrationActorTest.java new file mode 100644 index 0000000000..d5a60371b8 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/TenantMigrationActorTest.java @@ -0,0 +1,277 @@ +package org.sunbird.user.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.*; +import org.apache.commons.lang3.StringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.actor.router.RequestRouter; +import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; +import org.sunbird.bean.ShadowUser; +import org.sunbird.cassandra.CassandraOperation; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.Constants; +import org.sunbird.common.ElasticSearchHelper; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.ActorOperations; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.feed.FeedUtil; +import org.sunbird.feed.IFeedService; +import org.sunbird.feed.impl.FeedFactory; +import org.sunbird.feed.impl.FeedServiceImpl; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.models.user.Feed; +import org.sunbird.user.UserManagementActorTestBase; +import org.sunbird.user.util.MigrationUtils; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + ServiceFactory.class, + ElasticSearchRestHighImpl.class, + ElasticSearchHelper.class, + EsClientFactory.class, + CassandraOperationImpl.class, + ElasticSearchService.class, + MigrationUtils.class, + SystemSettingClientImpl.class, + IFeedService.class, + FeedServiceImpl.class, + FeedFactory.class, + ShadowUser.class, + FeedUtil.class +}) +@PowerMockIgnore({"javax.management.*"}) +public class TenantMigrationActorTest extends UserManagementActorTestBase { + Props props = Props.create(TenantMigrationActor.class); + ActorSystem system = ActorSystem.create("system"); + + private ElasticSearchService esUtil; + private CassandraOperation cassandraOperation = null; + private static Response response; + private static IFeedService feedService; + + @Before + public void beforeEachTest() { + ActorRef actorRef = mock(ActorRef.class); + PowerMockito.mockStatic(RequestRouter.class); + PowerMockito.mockStatic(FeedUtil.class); + + PowerMockito.mockStatic(FeedServiceImpl.class); + PowerMockito.mockStatic(FeedFactory.class); + feedService = mock(FeedServiceImpl.class); + when(FeedFactory.getInstance()).thenReturn(feedService); + when(FeedServiceImpl.getCassandraInstance()).thenReturn(cassandraOperation); + when(FeedServiceImpl.getESInstance()).thenReturn(esUtil); + when(feedService.getRecordsByProperties(Mockito.anyMap())) + .thenReturn(getFeedList(true)) + .thenReturn(getFeedList(false)); + + PowerMockito.mockStatic(ServiceFactory.class); + PowerMockito.mockStatic(EsClientFactory.class); + PowerMockito.mockStatic(ElasticSearchHelper.class); + esUtil = mock(ElasticSearchService.class); + esUtil = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esUtil); + + cassandraOperation = mock(CassandraOperationImpl.class); + response = new Response(); + Map responseMap = new HashMap<>(); + responseMap.put(Constants.RESPONSE, Arrays.asList(getFeedMap())); + response.getResult().putAll(responseMap); + PowerMockito.when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + PowerMockito.when( + cassandraOperation.getRecordsByProperties(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(response); + + Response upsertResponse = new Response(); + Map responseMap2 = new HashMap<>(); + responseMap2.put(Constants.RESPONSE, Constants.SUCCESS); + upsertResponse.getResult().putAll(responseMap2); + PowerMockito.when(cassandraOperation.upsertRecord(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(upsertResponse); + + when(RequestRouter.getActor(Mockito.anyString())).thenReturn(actorRef); + PowerMockito.mockStatic(SystemSettingClientImpl.class); + SystemSettingClientImpl systemSettingClient = mock(SystemSettingClientImpl.class); + when(SystemSettingClientImpl.getInstance()).thenReturn(systemSettingClient); + when(systemSettingClient.getSystemSettingByFieldAndKey( + Mockito.any(ActorRef.class), + Mockito.anyString(), + Mockito.anyString(), + Mockito.anyObject())) + .thenReturn(new HashMap<>()); + PowerMockito.mockStatic(MigrationUtils.class); + when(MigrationUtils.markUserAsRejected(Mockito.any(ShadowUser.class))).thenReturn(true); + } + + @Test + public void testUserMigrateRejectWhenUserFound() { + when(MigrationUtils.getEligibleUsersById("anyUserId")) + .thenReturn(getShadowUserAsList(StringUtils.EMPTY, 1)); + boolean result = + testScenario( + getMigrateReq(ActorOperations.MIGRATE_USER, JsonKey.REJECT), null, ResponseCode.OK); + assertTrue(result); + } + + @Test + public void testUserMigrateRejectWhenUserNotFound() { + List shadowUserList = new ArrayList<>(); + when(MigrationUtils.getEligibleUsersById("WrongUserId")).thenReturn(shadowUserList); + boolean result = + testScenario( + getFailureMigrateReq(ActorOperations.MIGRATE_USER, JsonKey.REJECT), + ResponseCode.invalidUserId, + null); + assertTrue(result); + } + + @Test + public void testUserMigrationAcceptWhenUserNotFound() { + List shadowUserList = new ArrayList<>(); + when(MigrationUtils.getEligibleUsersById("WrongUserId")).thenReturn(shadowUserList); + boolean result = + testScenario( + getFailureMigrateReq(ActorOperations.MIGRATE_USER, JsonKey.ACCEPT), + ResponseCode.invalidUserId, + null); + assertTrue(result); + } + + public Request getFailureMigrateReq(ActorOperations actorOperation, String action) { + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "WrongUserId"); + reqMap.put(JsonKey.USER_EXT_ID, "WrongAnyUserExtId"); + reqMap.put(JsonKey.CHANNEL, "anyChannel"); + reqMap.put(JsonKey.ACTION, action); + reqMap.put(JsonKey.FEED_ID, "anyFeedId"); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation.getValue()); + System.out.println(reqMap); + return reqObj; + } + + /** AC->ATTEMPT COUNT, e.g AC1-> Attempt Count 1 */ + @Test + public void testUserMigrationAcceptWhenUserFoundWithInCorrectExtIdAC1() { + Map propsMap = new HashMap<>(); + propsMap.put(JsonKey.CHANNEL, "anyChannel"); + when(MigrationUtils.getEligibleUsersById("anyUserId", propsMap)) + .thenReturn(getShadowUserAsList("wrongUserExtId", 1)); + boolean result = + testScenario( + getMigrateReq(ActorOperations.MIGRATE_USER, JsonKey.ACCEPT), + null, + ResponseCode.invalidUserExternalId); + assertTrue(result); + } + + @Test + public void testUserMigrationAcceptWhenUserFoundWithInCorrectExtIdAC2() { + when(MigrationUtils.getEligibleUsersById(Mockito.anyString(), Mockito.anyMap())) + .thenReturn(getShadowUserAsList("wrongUserExtId", 2)); + boolean result = + testScenario( + getMigrateReq(ActorOperations.MIGRATE_USER, JsonKey.ACCEPT), + ResponseCode.userMigrationFiled, + null); + assertTrue(result); + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode, ResponseCode responseCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + + if (responseCode != null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == responseCode; + } + if (errorCode != null) { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + return true; + } + + public Request getMigrateReq(ActorOperations actorOperation, String action) { + Request reqObj = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.USER_ID, "anyUserId"); + reqMap.put(JsonKey.USER_EXT_ID, "anyUserExtId"); + reqMap.put(JsonKey.CHANNEL, "anyChannel"); + reqMap.put(JsonKey.ACTION, action); + reqMap.put(JsonKey.FEED_ID, "anyFeedId"); + reqObj.setRequest(reqMap); + reqObj.setOperation(actorOperation.getValue()); + System.out.println(reqMap); + return reqObj; + } + + private List getShadowUserAsList(String userExtId, int attemptCount) { + List shadowUserList = new ArrayList<>(); + shadowUserList.add(getShadowUser(userExtId, attemptCount)); + return shadowUserList; + } + + private ShadowUser getShadowUser(String userExtId, int attemptCount) { + ShadowUser shadowUser = + new ShadowUser.ShadowUserBuilder() + .setChannel("anyChannel") + .setUserExtId(StringUtils.isNotEmpty(userExtId) ? userExtId : "anyUserExtId") + .setUserId("anyUserId") + .setAttemptedCount(attemptCount - 1) + .setUserStatus(ProjectUtil.Status.ACTIVE.getValue()) + .build(); + return shadowUser; + } + + private Map getFeedMap() { + Map fMap = new HashMap<>(); + fMap.put(JsonKey.ID, "123-456-7890"); + fMap.put(JsonKey.USER_ID, "123-456-789"); + fMap.put(JsonKey.CATEGORY, "category"); + return fMap; + } + + private List getFeedList(boolean needId) { + Feed feed = new Feed(); + feed.setUserId("123-456-7890"); + feed.setCategory("category"); + if (needId) { + feed.setId("123-456-789"); + } + Map map = new HashMap<>(); + List channelList = new ArrayList<>(); + channelList.add("SI"); + map.put(JsonKey.PROSPECT_CHANNELS, channelList); + feed.setData(map); + List feedList = new ArrayList<>(); + feedList.add(feed); + return feedList; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/UserOrgManagementActorTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/UserOrgManagementActorTest.java new file mode 100644 index 0000000000..848cee6f19 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/actors/UserOrgManagementActorTest.java @@ -0,0 +1,118 @@ +package org.sunbird.user.actors; + +import static akka.testkit.JavaTestKit.duration; +import static org.mockito.Mockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.javadsl.TestKit; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.request.Request; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.learner.util.UserUtility; +import org.sunbird.learner.util.Util; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({Util.class, UserUtility.class}) +@PowerMockIgnore({"javax.management.*"}) +public class UserOrgManagementActorTest { + Props props = Props.create(UserOrgManagementActor.class); + ActorSystem system = ActorSystem.create("UserOrgManagementActor"); + + @Before + public void beforeEachTest() throws Exception { + PowerMockito.mockStatic(UserUtility.class); + PowerMockito.mockStatic(Util.class); + PowerMockito.doNothing().when(Util.class, "registerUserToOrg", Mockito.anyMap()); + when(Util.getHashTagIdFromOrgId(Mockito.anyString())).thenReturn("hashTagId"); + PowerMockito.doNothing().when(Util.class, "upsertUserOrgData", Mockito.anyMap()); + } + + @Test + public void testInsertUserOrgDetailsSuccess() { + boolean result = testScenario(getUserOrgInsertRequest(), null); + Assert.assertTrue(result); + } + + @Test + public void testInsertUserOrgDetailsWithInvalidOperations() { + boolean result = testScenario(getUserOrgInsertFailureRequest(), ResponseCode.CLIENT_ERROR); + Assert.assertTrue(result); + } + + @Test + public void testInsertUserOrgDetailsWithoutCallerIdSuccess() throws Exception { + Request request = getUserOrgInsertRequest(); + request.getRequest().remove(JsonKey.CALLER_ID); + boolean result = testScenario(request, null); + Assert.assertTrue(result); + } + + @Test + public void testUpdateUserOrgDetailsSuccess() throws Exception { + boolean result = testScenario(getUserOrgUpdateRequest(), null); + Assert.assertTrue(result); + } + + private Request getUserOrgInsertRequest() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.CALLER_ID, "anyCallerId"); + reqMap.put(JsonKey.ORGANISATION_ID, "anyOrgId"); + reqMap.put(JsonKey.ROOT_ORG_ID, "anyRootOrgId"); + request.setRequest(reqMap); + request.setOperation("insertUserOrgDetails"); + return request; + } + + private Request getUserOrgUpdateRequest() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.CALLER_ID, "anyCallerId"); + reqMap.put(JsonKey.ORGANISATION_ID, "anyOrgId"); + reqMap.put(JsonKey.ROOT_ORG_ID, "anyRootOrgId"); + request.setRequest(reqMap); + request.setOperation("updateUserOrgDetails"); + return request; + } + + private Request getUserOrgInsertFailureRequest() { + Request request = new Request(); + Map reqMap = new HashMap<>(); + reqMap.put(JsonKey.CALLER_ID, "anyCallerId"); + reqMap.put(JsonKey.ORGANISATION_ID, "anyOrgId"); + request.setRequest(reqMap); + request.setOperation("invalidOperation"); + return request; + } + + public boolean testScenario(Request reqObj, ResponseCode errorCode) { + TestKit probe = new TestKit(system); + ActorRef subject = system.actorOf(props); + subject.tell(reqObj, probe.getRef()); + if (errorCode == null) { + Response res = probe.expectMsgClass(duration("10 second"), Response.class); + return null != res && res.getResponseCode() == ResponseCode.OK; + } else { + ProjectCommonException res = + probe.expectMsgClass(duration("10 second"), ProjectCommonException.class); + System.out.println("the error" + res.getCode()); + return res.getCode().equals(errorCode.getErrorCode()) + || res.getResponseCode() == errorCode.getResponseCode(); + } + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/util/MigrationUtilsTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/util/MigrationUtilsTest.java new file mode 100644 index 0000000000..6648d8ba39 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/util/MigrationUtilsTest.java @@ -0,0 +1,147 @@ +package org.sunbird.user.util; + +import static org.powermock.api.mockito.PowerMockito.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.bean.ClaimStatus; +import org.sunbird.bean.ShadowUser; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.user.service.impl.UserServiceImpl; + +@RunWith(PowerMockRunner.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@PrepareForTest({UserServiceImpl.class, ServiceFactory.class, CassandraOperationImpl.class}) +@PowerMockIgnore({"javax.management.*"}) +public class MigrationUtilsTest { + + private static Response response; + public static CassandraOperationImpl cassandraOperationImpl; + + @Before + public void beforeEachTest() { + response = new Response(); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperationImpl = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperationImpl); + when(cassandraOperationImpl.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USER_IDs, "EFG")) + .thenReturn(getRecordsById(false)); + when(cassandraOperationImpl.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USER_IDs, "DEF")) + .thenReturn(getRecordsById(true)); + when(cassandraOperationImpl.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USER_IDs, "ABC", new HashMap<>())) + .thenReturn(getRecordsById(false)); + when(cassandraOperationImpl.searchValueInList( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, JsonKey.USER_IDs, "XYZ", new HashMap<>())) + .thenReturn(getRecordsById(true)); + } + + @Test + public void testGetRecordByUserIdSuccess() { + ShadowUser shadowUser = MigrationUtils.getRecordByUserId("EFG"); + Assert.assertEquals("TN", shadowUser.getChannel()); + } + + @Test + public void testGetRecordByUserIdFailure() { + ShadowUser shadowUser = MigrationUtils.getRecordByUserId("DEF"); + Assert.assertEquals(null, shadowUser); + } + + @Test + public void testUpdateRecord() { + Map compositeKeysMap = new HashMap<>(); + compositeKeysMap.put(JsonKey.USER_EXT_ID, "anyUserExtId"); + compositeKeysMap.put(JsonKey.CHANNEL, "anyChannel"); + when(cassandraOperationImpl.updateRecord( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, new HashMap<>(), compositeKeysMap)) + .thenReturn(response); + boolean isRecordUpdated = + MigrationUtils.updateRecord(new HashMap<>(), "anyChannel", "anyUserExtId"); + Assert.assertEquals(true, isRecordUpdated); + } + + @Test + public void testmarkUserAsRejected() { + ShadowUser shadowUser = + new ShadowUser.ShadowUserBuilder() + .setChannel("anyChannel") + .setUserExtId("anyUserExtId") + .build(); + Map compositeKeysMap = new HashMap<>(); + compositeKeysMap.put(JsonKey.USER_EXT_ID, "anyUserExtId"); + compositeKeysMap.put(JsonKey.CHANNEL, "anyChannel"); + when(cassandraOperationImpl.updateRecord( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, new HashMap<>(), compositeKeysMap)) + .thenReturn(response); + boolean isRecordUpdated = MigrationUtils.markUserAsRejected(shadowUser); + Assert.assertEquals(true, isRecordUpdated); + } + + @Test + public void testUpdateClaimStatus() { + ShadowUser shadowUser = + new ShadowUser.ShadowUserBuilder() + .setChannel("anyChannel") + .setUserExtId("anyUserExtId") + .build(); + Map compositeKeysMap = new HashMap<>(); + compositeKeysMap.put(JsonKey.USER_EXT_ID, "anyUserExtId"); + compositeKeysMap.put(JsonKey.CHANNEL, "anyChannel"); + when(cassandraOperationImpl.updateRecord( + JsonKey.SUNBIRD, JsonKey.SHADOW_USER, new HashMap<>(), compositeKeysMap)) + .thenReturn(response); + boolean isRecordUpdated = + MigrationUtils.updateClaimStatus(shadowUser, ClaimStatus.ELIGIBLE.getValue()); + Assert.assertEquals(true, isRecordUpdated); + } + + @Test + public void testGetEligibleUserByIdsSuccess() { + List shadowUserList = MigrationUtils.getEligibleUsersById("ABC", new HashMap<>()); + Assert.assertEquals(1, shadowUserList.size()); + } + + @Test + public void testGetEligibleUserByIdsFailure() { + List shadowUserList = MigrationUtils.getEligibleUsersById("XYZ", new HashMap<>()); + Assert.assertEquals(0, shadowUserList.size()); + } + + @Test + public void testGetEligibleUserByIdsWithoutProps() { + List shadowUserList = MigrationUtils.getEligibleUsersById("EFG"); + Assert.assertEquals(1, shadowUserList.size()); + } + + private Response getRecordsById(boolean empty) { + Response res = new Response(); + List> list = new ArrayList<>(); + if (!empty) { + Map map = new HashMap<>(); + map.put(JsonKey.CHANNEL, "TN"); + map.put(JsonKey.USER_ID, "ABC"); + map.put(JsonKey.CLAIM_STATUS, ClaimStatus.ELIGIBLE.getValue()); + list.add(map); + } + res.put(JsonKey.RESPONSE, list); + return res; + } +} diff --git a/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/util/UserUtilTest.java b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/util/UserUtilTest.java new file mode 100644 index 0000000000..cd19ec7ec2 --- /dev/null +++ b/actors/sunbird-lms-mw/actors/user/src/test/java/org/sunbird/user/util/UserUtilTest.java @@ -0,0 +1,174 @@ +package org.sunbird.user.util; + +import static akka.testkit.JavaTestKit.duration; +import static org.junit.Assert.*; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import akka.dispatch.Futures; +import org.apache.commons.lang3.math.NumberUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.common.ElasticSearchRestHighImpl; +import org.sunbird.common.exception.ProjectCommonException; +import org.sunbird.common.factory.EsClientFactory; +import org.sunbird.common.inf.ElasticSearchService; +import org.sunbird.common.models.response.Response; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.responsecode.ResponseCode; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.util.DataCacheHandler; +import org.sunbird.learner.util.Util; +import org.sunbird.models.user.User; +import scala.concurrent.Promise; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ServiceFactory.class, CassandraOperationImpl.class, DataCacheHandler.class, + EsClientFactory.class, + ElasticSearchRestHighImpl.class, + Util.class}) +@PowerMockIgnore({"javax.management.*"}) +public class UserUtilTest { + private static Response response; + public static CassandraOperationImpl cassandraOperationImpl; + private static ElasticSearchService esService; + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(DataCacheHandler.class); + response = new Response(); + List> userMapList = new ArrayList>(); + Map userMap = new HashMap(); + userMapList.add(userMap); + Response existResponse = new Response(); + existResponse.put(JsonKey.RESPONSE, userMapList); + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperationImpl = mock(CassandraOperationImpl.class); + Map settingMap = new HashMap(); + settingMap.put(JsonKey.PHONE_UNIQUE, "True"); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperationImpl); + when(cassandraOperationImpl.getRecordsByIndexedProperty( + JsonKey.SUNBIRD, "user", JsonKey.EMAIL, "test@test.com")) + .thenReturn(response); + when(cassandraOperationImpl.getRecordsByIndexedProperty( + JsonKey.SUNBIRD, "user", JsonKey.PHONE, "9663890400")) + .thenReturn(existResponse); + when(DataCacheHandler.getConfigSettings()).thenReturn(settingMap); + + PowerMockito.mockStatic(EsClientFactory.class); + esService = mock(ElasticSearchRestHighImpl.class); + when(EsClientFactory.getInstance(Mockito.anyString())).thenReturn(esService); + + PowerMockito.mockStatic(Util.class); + } + + @Test + public void generateUniqueStringSuccess() { + String val = UserUtil.generateUniqueString(4); + assertTrue(val.length() == 4); + } + + @Test + public void generateUniqueStringSecondCharCheck() { + String val = UserUtil.generateUniqueString(5); + assertTrue(val.length() == 5); + assertTrue( + NumberUtils.isNumber(val.substring(1, 2)) || NumberUtils.isNumber(val.substring(2, 3))); + } + + @Test + public void checkPhoneUniquenessExist() { + User user = new User(); + user.setPhone("9663890400"); + boolean response = false; + try { + UserUtil.checkPhoneUniqueness(user, "create"); + response = true; + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), 400); + } + assertFalse(response); + } + + @Test + public void checkPhoneExist() { + boolean response = false; + try { + UserUtil.checkPhoneUniqueness("9663890400"); + response = true; + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), 400); + } + assertFalse(response); + } + + @Test + public void checkEmailExist() { + boolean response = false; + try { + UserUtil.checkEmailUniqueness("test@test.com"); + response = true; + } catch (ProjectCommonException e) { + + } + assertTrue(response); + } + + @Test + public void copyAndConvertExternalIdsToLower() { + List> externalIds = new ArrayList>(); + Map userExternalIdMap = new HashMap(); + userExternalIdMap.put(JsonKey.ID, "test123"); + userExternalIdMap.put(JsonKey.PROVIDER, "State"); + userExternalIdMap.put(JsonKey.ID_TYPE, "UserExtId"); + externalIds.add(userExternalIdMap); + externalIds = UserUtil.copyAndConvertExternalIdsToLower(externalIds); + userExternalIdMap = externalIds.get(0); + assertNotNull(userExternalIdMap.get(JsonKey.ORIGINAL_EXTERNAL_ID)); + assertEquals(userExternalIdMap.get(JsonKey.PROVIDER), "state"); + } + + @Test + public void setUserDefaultValueForV3() { + Map userMap = new HashMap(); + userMap.put(JsonKey.FIRST_NAME, "Test User"); + UserUtil.setUserDefaultValueForV3(userMap); + assertNotNull(userMap.get(JsonKey.USERNAME)); + assertNotNull(userMap.get(JsonKey.STATUS)); + assertNotNull(userMap.get(JsonKey.ROLES)); + } + + @Test + public void testValidateManagedUserLimit() { + + Map req = new HashMap<>(); + req.put(JsonKey.MANAGED_BY, "ManagedBy"); + List managedUserList = new ArrayList(); + while(managedUserList.size()<=31){ + managedUserList.add(new User()); + } + when(Util.searchUser(req)).thenReturn(managedUserList); + try { + UserUtil.validateManagedUserLimit("ManagedBy"); + } catch (ProjectCommonException e) { + assertEquals(e.getResponseCode(), 400); + assertEquals(e.getMessage(), ResponseCode.managedUserLimitExceeded.getErrorMessage()); + } + + } +} diff --git a/actors/sunbird-lms-mw/pom.xml b/actors/sunbird-lms-mw/pom.xml new file mode 100644 index 0000000000..a6da03945d --- /dev/null +++ b/actors/sunbird-lms-mw/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + org.sunbird + sunbird-lms-mw + 1.0-SNAPSHOT + pom + Sunbird LMS MW + + actors/sunbird-utils + actors + service + + diff --git a/actors/sunbird-lms-mw/service/pom.xml b/actors/sunbird-lms-mw/service/pom.xml new file mode 100644 index 0000000000..c1e5252d82 --- /dev/null +++ b/actors/sunbird-lms-mw/service/pom.xml @@ -0,0 +1,154 @@ + + + 4.0.0 + + org.sunbird + sunbird-lms-mw + 1.0-SNAPSHOT + + mw-service + Middleware Service + + UTF-8 + + + + org.sunbird + actor-common + 1.0-SNAPSHOT + + + org.sunbird + auth-verifier + 1.0-SNAPSHOT + + + org.sunbird + organization + 1.0-SNAPSHOT + + + org.sunbird + user + 1.0-SNAPSHOT + + + org.sunbird + badge + 1.0-SNAPSHOT + + + org.sunbird + location + 1.0-SNAPSHOT + + + org.sunbird + systemsettings + 1.0-SNAPSHOT + + + + ${basedir}/src/main/java + ${basedir}/src/test/java + + + + org.apache.maven.plugins + maven-shade-plugin + 3.0.0 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + reference.conf + + + org.sunbird.middleware.Application + + + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + **/*Spec.java + **/*Test.java + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + org.sunbird.middleware.Application + + + + actor-service + + \ No newline at end of file diff --git a/actors/sunbird-lms-mw/service/src/main/java/org/sunbird/middleware/Application.java b/actors/sunbird-lms-mw/service/src/main/java/org/sunbird/middleware/Application.java new file mode 100644 index 0000000000..16f36e931b --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/main/java/org/sunbird/middleware/Application.java @@ -0,0 +1,12 @@ +package org.sunbird.middleware; + + +/** @author Mahesh Kumar Gangula */ +public class Application { + + public static void main(String[] args) { + init(); + } + + public static void init() {} +} diff --git a/actors/sunbird-lms-mw/service/src/main/resources/application.conf b/actors/sunbird-lms-mw/service/src/main/resources/application.conf new file mode 100644 index 0000000000..8c4c788778 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/main/resources/application.conf @@ -0,0 +1,592 @@ +SunbirdMWSystem { + default-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 8 + parallelism-factor = 32.0 + parallelism-max = 64 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + rr-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 8 + parallelism-factor = 32.0 + parallelism-max = 64 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + rr-usr-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 8 + parallelism-factor = 32.0 + parallelism-max = 64 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + brr-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 1 + parallelism-factor = 2.0 + parallelism-max = 4 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + brr-usr-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 1 + parallelism-factor = 2.0 + parallelism-max = 4 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + most-used-one-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 8 + parallelism-factor = 32.0 + parallelism-max = 64 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + + most-used-two-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 8 + parallelism-factor = 32.0 + parallelism-max = 64 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + akka { + stdout-loglevel = "OFF" + loglevel = "INFO" + log-config-on-start = off + actor { + provider = "akka.actor.LocalActorRefProvider" + serializers { + java = "akka.serialization.JavaSerializer" + } + serialization-bindings { + "org.sunbird.common.request.Request" = java + "org.sunbird.common.models.response.Response" = java + } + default-dispatcher { + type = "Dispatcher" + executor = "fork-join-executor" + fork-join-executor { + parallelism-min = 8 + parallelism-factor = 32.0 + parallelism-max = 64 + } + # Throughput for default Dispatcher, set to 1 for as fair as possible + throughput = 1 + } + deployment { + /RequestRouter + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = rr-dispatcher + } + /BackgroundRequestRouter + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = brr-dispatcher + } + "/BackgroundRequestRouter/*/BackgroundJobManager" + { + router = smallest-mailbox-pool + nr-of-instances = 15 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/EsSyncBackgroundActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/BackGroundServiceActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/ChannelRegistrationActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/EmailServiceActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = most-used-one-dispatcher + } + "/RequestRouter/*/EmailServiceActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = most-used-one-dispatcher + } + "/BackgroundRequestRouter/*/BulkUploadBackGroundJobActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/MetricsBackGroundJobActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/OrganisationMetricsBackgroundActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/BadgeNotifier" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = brr-usr-dispatcher + } + "/RequestRouter/*/UserManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 20 + dispatcher = most-used-two-dispatcher + } + "/RequestRouter/*/UserProfileReadActor" + { + router = smallest-mailbox-pool + nr-of-instances = 25 + dispatcher = most-used-one-dispatcher + } + "/RequestRouter/*/UserTypeActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/AddressManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/AddressManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserStatusActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/EducationManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/EducationManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserRoleActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/JobProfileManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/JobProfileManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/BackgroundUserDataEncryptionActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserDataEncryptionActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserExternalIdManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/UserExternalIdManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserOrgManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/UserOrgManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserOnboardingNotificationActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/UserOnboardingNotificationActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserBackgroundJobActor" + { + router = smallest-mailbox-pool + nr-of-instances = 15 + dispatcher = most-used-two-dispatcher + } + "/BackgroundRequestRouter/*/UserBackgroundJobActor" + { + router = smallest-mailbox-pool + nr-of-instances = 15 + dispatcher = most-used-one-dispatcher + } + "/RequestRouter/*/UserProfileUpdateActor" + { + router = smallest-mailbox-pool + nr-of-instances = 15 + dispatcher = most-used-two-dispatcher + } + "/BackgroundRequestRouter/*/UserProfileUpdateActor" + { + router = smallest-mailbox-pool + nr-of-instances = 15 + dispatcher = most-used-two-dispatcher + } + "/RequestRouter/*/UserLoginActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserProfileActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/OrganisationManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/SearchHandlerActor" + { + router = smallest-mailbox-pool + nr-of-instances = 25 + dispatcher = most-used-one-dispatcher + } + "/RequestRouter/*/BulkUploadManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/EsSyncActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/FileUploadServiceActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/NotesManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/SchedularActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/OnDemandSchedulerActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/OrganisationMetricsActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserSkillManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/TenantPreferenceManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/ClientManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/GeoLocationManagementActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/KeyCloakSyncActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/DbOperationActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/BadgeIssuerActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/BadgeClassActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/BadgeAssertionActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/UserBadgeAssertion" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = brr-usr-dispatcher + } + "/RequestRouter/*/HealthActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = most-used-one-dispatcher + } + "/RequestRouter/*/LocationActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/LocationBackgroundActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = brr-usr-dispatcher + } + "/RequestRouter/*/LocationBulkUploadActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/OrgBulkUploadActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserBulkUploadActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/SystemSettingsActor" + { + router = smallest-mailbox-pool + nr-of-instances = 15 + dispatcher = most-used-two-dispatcher + } + "/RequestRouter/*/UserTnCActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/LocationBulkUploadBackGroundJobActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/OrgBulkUploadBackgroundJobActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/UserBulkUploadBackgroundJobActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = brr-usr-dispatcher + } + "/BackgroundRequestRouter/*/ThreadDumpActor" + { + router = smallest-mailbox-pool + nr-of-instances = 1 + dispatcher = brr-usr-dispatcher + } + "/RequestRouter/*/OTPActor" + { + router = smallest-mailbox-pool + nr-of-instances = 10 + dispatcher = most-used-one-dispatcher + } + "/BackgroundRequestRouter/*/SendOTPActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = most-used-one-dispatcher + } + "/RequestRouter/*/TenantMigrationActor" + { + router = smallest-mailbox-pool + nr-of-instances = 3 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/IdentifierFreeUpActor" + { + router = smallest-mailbox-pool + nr-of-instances = 3 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/ResetPasswordActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserMergeActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/CertificateActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/CertificateActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserBulkMigrationActor" + { + router = smallest-mailbox-pool + nr-of-instances = 2 + dispatcher = rr-usr-dispatcher + } + "/RequestRouter/*/UserFeedActor" + { + router = smallest-mailbox-pool + nr-of-instances = 5 + dispatcher = rr-usr-dispatcher + } + "/BackgroundRequestRouter/*/SearchTelemetryGenerator" + { + router = smallest-mailbox-pool + nr-of-instances = 3 + dispatcher = brr-usr-dispatcher + } + } + } + remote { + maximum-payload-bytes = 30000000 bytes + netty.tcp { + port = 8088 + message-frame-size = 30000000b + send-buffer-size = 30000000b + receive-buffer-size = 30000000b + maximum-frame-size = 30000000b + } + } + } +} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/service/src/main/resources/cassandra.cql b/actors/sunbird-lms-mw/service/src/main/resources/cassandra.cql new file mode 100644 index 0000000000..6b5906d48f --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/main/resources/cassandra.cql @@ -0,0 +1,562 @@ +CREATE KEYSPACE IF NOT EXISTS sunbird WITH replication = {'class':'SimpleStrategy','replication_factor':1}; + +//to change cluster name +//UPDATE system.local SET cluster_name = 'sunbird' where key='local'; +//ALTER USER cassandra WITH PASSWORD 'password'; +USE sunbird; + +/* +creation of id= one way hash of (userId##courseId) here courseId is identifier of course mgmt table +toc url we have to generate through json of content id from ekStep +here status is (default(0),inProgress(1),completed(2)) +progress is no of content completed +*/ +CREATE TABLE IF NOT EXISTS sunbird.course_enrollment(id text, courseId text, courseName text,userId text,enrolledDate text, +description text,tocUrl text,status int,active boolean,delta text,grade text,progress int,lastReadContentId text, +lastReadContentStatus int,addedBy text,courseLogoUrl text,dateTime timestamp,contentId text,PRIMARY KEY (id)); + +CREATE INDEX inx_ce_userId ON sunbird.course_enrollment (userId); +CREATE INDEX inx_ce_courseId ON sunbird.course_enrollment (courseId); +CREATE INDEX inx_ce_course_name ON sunbird.course_enrollment (courseName); +CREATE INDEX inx_ce_status ON sunbird.course_enrollment (status); + +/* +creation of id = one way hash of (userId##contentId##courseId##batchId) +status is (default(0),inProgress(1),completed(2)) +*/ +CREATE TABLE IF NOT EXISTS sunbird.content_consumption(id text, contentId text, courseId text, userId text,viewPosition text,viewCount int,lastAccessTime text, +contentVersion text,completedCount int,status int,result text,score text,grade text,lastUpdatedTime text,lastCompletedTime text,dateTime timestamp,PRIMARY KEY (id)); + +CREATE INDEX inx_cc_userId ON sunbird.content_consumption (userId); +CREATE INDEX inx_cc_contentId ON sunbird.content_consumption (contentId); +CREATE INDEX inx_cc_status ON sunbird.content_consumption (status); +CREATE INDEX inx_cc_courseId ON sunbird.content_consumption (courseId); + +/* +creation of id = using timestamp and env + id and courseId both are same +content id is from ekstep +status DRAFT("draft"), LIVE("live"), RETIRED("retired") +contentType (pdf,video,word doc etc) +tutor map +*/ +CREATE TABLE IF NOT EXISTS sunbird.course_management(id text, courseId text, contentId text, courseName text,courseType text, +facultyId text,facultyName text,organisationId text,organisationName text,enrollementStartDate text,enrollementEndDate text, +courseDuration text,description text,status text,addedBy text,addedByName text,publishedBy text,publishedByName text,createdDate text, +publishedDate text,updatedDate text,updatedBy text,updatedByName text,contentType text,createdfor list,noOfLectures int,tocUrl text, +tutor map,courseLogoUrl text,courseRating text,userCount int,PRIMARY KEY (id)); + +CREATE INDEX inx_cm_facultyId ON sunbird.course_management (facultyId); +CREATE INDEX inx_cm_organisationId ON sunbird.course_management (organisationId); +CREATE INDEX inx_cm_courseId ON sunbird.course_management (courseId); +CREATE INDEX inx_cm_course_name ON sunbird.course_management (courseName); +CREATE INDEX inx_cm_status ON sunbird.course_management (status); +CREATE INDEX inx_cm_contentId ON sunbird.course_management (contentId); + +/* +creation of id = one way hash of userName +here id and userId both are same + currently username and email is same +email and username is unique +*/ +CREATE TABLE IF NOT EXISTS sunbird.user(id text,userId text,userName text, email text,phone text,aadhaarNo text,createdDate text,updatedDate text,updatedBy text, +lastLoginTime text,status int,firstName text,lastName text,password text,avatar text,gender text,language list,subject list,grade list,regOrgId text, +dob text,thumbnail text,PRIMARY KEY (id)); + +CREATE INDEX inx_u_email ON sunbird.user (email); +CREATE INDEX inx_u_phone ON sunbird.user (phone); +CREATE INDEX inx_u_status ON sunbird.user (status); +CREATE INDEX inx_u_userId ON sunbird.user (userId); +CREATE INDEX inx_u_userName ON sunbird.user (userName); + +//user_auth +//id is auth token +CREATE TABLE IF NOT EXISTS sunbird.user_auth(id text, userId text,createdDate text,updatedDate text,source text,PRIMARY KEY (id)); +CREATE INDEX inx_ua_userId ON sunbird.user_auth (userId); +CREATE INDEX inx_ua_source ON sunbird.user_auth (source); + +//organisation +CREATE TABLE IF NOT EXISTS sunbird.organisation(id text, orgName text, description text,communityId text,createdBy text,createdDate text, +updatedDate text,updatedBy text,status int,parentOrgId text,orgType text,orgCode text,dateTime timestamp,PRIMARY KEY (id)); + +CREATE INDEX inx_org_orgName ON sunbird.organisation (orgName); +CREATE INDEX inx_org_status ON sunbird.organisation (status); +//page_management +//id= using timestamp and env +CREATE TABLE IF NOT EXISTS sunbird.page_management(id text, name text, appMap text,portalMap text,createdDate text,createdBy text, +updatedDate text,updatedBy text,organisationId text,PRIMARY KEY (id)); + +CREATE INDEX inx_pm_pageName ON sunbird.page_management (name); +CREATE INDEX inx_vm_organisationId ON sunbird.page_management (organisationId); + +//page_section +//id= using timestamp and env +CREATE TABLE IF NOT EXISTS sunbird.page_section(id text, name text, sectionDataType text,description text,display text, +searchQuery text,createdDate text,createdBy text,updatedDate text,updatedBy text,imgUrl text,alt text,status int,PRIMARY KEY (id)); +CREATE INDEX inx_ps_sectionDataType ON sunbird.page_section (sectionDataType); +CREATE INDEX inx_ps_sectionName ON sunbird.page_section (name); + +//Assessment Eval +//id= using timestamp and env +CREATE TABLE IF NOT EXISTS sunbird.assessment_eval(id text, contentId text, courseId text, userId text, +createdDate text,result text,score text,attemptId text,attemptedCount int,PRIMARY KEY (id)); + +CREATE INDEX inx_ae_userId ON sunbird.assessment_eval (userId); +CREATE INDEX inx_ae_contentId ON sunbird.assessment_eval (contentId); +CREATE INDEX inx_ae_courseId ON sunbird.assessment_eval (courseId); + +//Assessment item +//id= using timestamp and userId +CREATE TABLE IF NOT EXISTS sunbird.assessment_item(id text, contentId text, courseId text, userId text,assessmentItemId text, +assessmentType text,attemptedDate text,createdDate text,timeTaken int,result text,score text,maxScore text,answers text, +evaluationStatus boolean,processingStatus boolean,attemptId text,PRIMARY KEY (id)); + +CREATE INDEX inx_ai_userId ON sunbird.assessment_item (userId); +CREATE INDEX inx_ai_contentId ON sunbird.assessment_item (contentId); +CREATE INDEX inx_ai_assessmentItemId ON sunbird.assessment_item (assessmentItemId); +CREATE INDEX inx_ai_courseId ON sunbird.assessment_item (courseId); +CREATE INDEX inx_ai_processingStatus ON sunbird.assessment_item (processingStatus); + +DROP INDEX IF EXISTS sunbird.inx_ai_processingStatus; +DROP INDEX IF EXISTS sunbird.inx_ae_assessmentitemid; + + +CREATE TABLE IF NOT EXISTS sunbird.user_external_identity(id text, userId text, externalId text,source text,isVerified boolean,PRIMARY KEY (id)); +CREATE INDEX inx_uei_userid ON sunbird.user_external_identity (userId); +CREATE INDEX inx_uei_externalId ON sunbird.user_external_identity (externalId); +CREATE INDEX inx_uei_source ON sunbird.user_external_identity (source); + +//Address Type values(permanent, current, office, home) +CREATE TABLE IF NOT EXISTS sunbird.address(id text, userId text, country text,state text,city text,zipCode text,addType text,createdDate text,createdBy text,updatedDate text,updatedBy text, PRIMARY KEY (id)); +CREATE INDEX inx_add_userid ON sunbird.address (userId); +CREATE INDEX inx_add_addType ON sunbird.address (addType); + +CREATE TABLE IF NOT EXISTS sunbird.user_education(id text, userId text, courseName text,duration int,yearOfPassing int,percentage double,grade text,name text,boardOrUniversity text,addressId text,createdDate text,createdBy text,updatedDate text,updatedBy text, PRIMARY KEY (id)); +CREATE INDEX inx_ueu_userid ON sunbird.user_education (userId); + +CREATE TABLE IF NOT EXISTS sunbird.user_job_profile(id text, userId text, jobName text,role text,joiningDate text,endDate text,orgName text,orgId text,subject list,addressId text,boardName text,isVerified boolean,isRejected boolean,verifiedDate text,verifiedBy text,createdDate text,createdBy text,updatedDate text,updatedBy text, PRIMARY KEY (id)); +CREATE INDEX inx_ujp_userid ON sunbird.user_job_profile (userId); + +CREATE TABLE IF NOT EXISTS sunbird.user_org(id text, userId text, role text,orgId text,orgJoinDate text,orgLeftDate text,isApproved boolean, +isRejected boolean,approvedBy text,approvalDate text,updatedDate text,updatedBy text, PRIMARY KEY (id)); +CREATE INDEX inx_uorg_userid ON sunbird.user_org(userId); +CREATE INDEX inx_uorg_orgId ON sunbird.user_org(orgId); + +CREATE TABLE IF NOT EXISTS sunbird.subject(id text, name text, PRIMARY KEY (id)); +CREATE INDEX inx_sb_name ON sunbird.subject(name); + + +ALTER TABLE sunbird.organisation ADD imgUrl text; +ALTER TABLE sunbird.organisation ADD thumbnail text; +ALTER TABLE sunbird.organisation ADD channel text; +ALTER TABLE sunbird.organisation ADD preferredLanguage text; +ALTER TABLE sunbird.organisation ADD homeUrl text; +ALTER TABLE sunbird.organisation ADD isRootOrg boolean; +ALTER TABLE sunbird.organisation ADD addId text; +ALTER TABLE sunbird.organisation ADD noOfmembers int; +ALTER TABLE sunbird.organisation ADD isApproved boolean; +ALTER TABLE sunbird.organisation ADD approvedBy text; +ALTER TABLE sunbird.organisation ADD approvedDate text; + + +CREATE INDEX inx_org_channel ON sunbird.organisation(channel); +CREATE INDEX inx_org_orgType ON sunbird.organisation(orgType); +CREATE INDEX inx_org_orgCode ON sunbird.organisation(orgCode); + +CREATE TABLE IF NOT EXISTS sunbird.org_type(id text, name text, PRIMARY KEY (id)); +CREATE INDEX inx_ot_name ON sunbird.org_type(name); + +CREATE TABLE IF NOT EXISTS sunbird.org_mapping(id text, orgIdOne text,relation text,orgIdTwo text, PRIMARY KEY (id)); +CREATE INDEX inx_om_orgIdOne ON sunbird.org_mapping(orgIdOne); +CREATE INDEX inx_om_orgIdTwo ON sunbird.org_mapping(orgIdTwo); + +ALTER TABLE sunbird.user ADD rootOrgId text; +ALTER TABLE sunbird.address ADD addressLine1 text; +ALTER TABLE sunbird.address ADD addressLine2 text; +ALTER TABLE sunbird.user_education ADD degree text; + +CREATE TABLE IF NOT EXISTS sunbird.master_action(id text, name text, PRIMARY KEY (id)); +CREATE INDEX inx_ma_name ON sunbird.master_action(name); + +CREATE TABLE IF NOT EXISTS sunbird.action_group(id text, actionId list,groupName text, PRIMARY KEY (id)); +CREATE INDEX inx_uacg_groupName ON sunbird.action_group(groupName); + +CREATE TABLE IF NOT EXISTS sunbird.user_action_role(id text, actionGroupId list,roleId text, PRIMARY KEY (id)); +CREATE INDEX inx_uactr_roleId ON sunbird.user_action_role(roleId); + + +insert into sunbird.action_group(id,actionId,groupName) values ('ag_12',['1','2'],'SYSTEM_ADMINISTRATION'); +insert into sunbird.action_group(id,actionId,groupName) values ('ag_13',['3','4','7','8','5'],'ORG_MANAGEMENT'); +insert into sunbird.action_group(id,actionId,groupName) values ('ag_14',['6','9','10'],'MEMBERSHIP_MANAGEMENT'); + +insert into sunbird.action_group(id,actionId,groupName) values ('ag_15',['11','12','13','14'],'CONTENT_CREATION'); +insert into sunbird.action_group(id,actionId,groupName) values ('ag_16',['15','16'],'CONTENT_REVIEW'); +insert into sunbird.action_group(id,actionId,groupName) values ('ag_17',['17','18','10'],'CONTENT_CURATION'); +insert into sunbird.action_group(id,actionId,groupName) values ('ag_17',['19','20','21','22','23','24','25','26'],'PUBLIC'); + +ALTER TABLE sunbird.user ADD loginId text; +ALTER TABLE sunbird.user ADD provider text; +ALTER TABLE sunbird.user_external_identity ADD idType text; + +insert into sunbird.user_action_role(id,actiongroupid,roleid) values ('uar_1',['ag_17'],'r_107'); +insert into sunbird.user_action_role(id,actiongroupid,roleid) values ('uar_2',['ag_13'],'r_102'); +insert into sunbird.user_action_role(id,actiongroupid,roleid) values ('uar_3',['ag_14'],'r_103'); + insert into sunbird.user_action_role(id,actiongroupid,roleid) values ('uar_3',['ag_15'],'r_104'); + insert into sunbird.user_action_role(id,actiongroupid,roleid) values ('uar_3',['ag_16'],'r_105'); + insert into sunbird.user_action_role(id,actiongroupid,roleid) values ('uar_3',['ag_12'],'r_101'); + +ALTER TABLE sunbird.organisation DROP addId; +ALTER TABLE sunbird.organisation ADD addressId text; +ALTER TABLE sunbird.user ADD roles List; + + + CREATE TABLE IF NOT EXISTS sunbird.role_group(id text, name text, PRIMARY KEY (id)); + insert into sunbird.role_group (id,name) values ('SYSTEM_ADMINISTRATION','System Administration'); + insert into sunbird.role_group (id,name) values ('ORG_MANAGEMENT','Org Management'); + insert into sunbird.role_group (id,name) values ('MEMBERSHIP_MANAGEMENT','Membership Management'); + insert into sunbird.role_group (id,name) values ('CONTENT_CREATION','Content Creation'); + insert into sunbird.role_group (id,name) values ('CONTENT_CURATION','Content Curation'); + insert into sunbird.role_group (id,name) values ('CONTENT_REVIEW','Content Review'); + +CREATE TABLE IF NOT EXISTS sunbird.role(id text, name text,roleGroupId List,status int, PRIMARY KEY (id)); +CREATE INDEX inx_ro_master_name ON sunbird.role(name); + insert into sunbird.role (id,name,rolegroupid,status) values ('ADMIN','Admin',['SYSTEM_ADMINISTRATION','ORG_MANAGEMENT'],1); + insert into sunbird.role (id,name,rolegroupid,status) values ('ORG_ADMIN','Org Admin',['ORG_MANAGEMENT','MEMBERSHIP_MANAGEMENT'],1); + insert into sunbird.role (id,name,rolegroupid,status) values ('ORG_MODERATOR','Org Moderator',['MEMBERSHIP_MANAGEMENT'],1); + insert into sunbird.role (id,name,rolegroupid,status) values ('CONTENT_CREATOR','Content Creator',['CONTENT_CREATION'],1); + insert into sunbird.role (id,name,rolegroupid,status) values ('CONTENT_REVIEWER','Content Reviewer',['CONTENT_CREATION','CONTENT_CURATION','CONTENT_REVIEW'],1); + + CREATE TABLE IF NOT EXISTS sunbird.url_action(id text, url list,name text, PRIMARY KEY (id)); + CREATE INDEX inx_ua_name ON sunbird.url_action(name); +CREATE INDEX inx_ua_url ON sunbird.url_action(url); + +insert into sunbird.url_action (id,name) values ('suspendOrg','suspendOrg'); + insert into sunbird.url_action (id,name) values ('suspendUser','suspendUser'); + insert into sunbird.url_action (id,name) values ('createOrg','createOrg'); + insert into sunbird.url_action (id,name) values ('updateOrg','updateOrg'); + insert into sunbird.url_action (id,name) values ('removeOrg','removeOrg'); + insert into sunbird.url_action (id,name) values ('createUser','createUser'); + insert into sunbird.url_action (id,name) values ('updateUser','updateUser'); + insert into sunbird.url_action (id,name) values ('ORG_MANAGEMENT','Org Management'); + insert into sunbird.url_action (id,name) values ('createOrg','createOrg'); + insert into sunbird.url_action (id,name) values ('addMember','addMember'); + insert into sunbird.url_action (id,name) values ('removeMember','removeMember'); + insert into sunbird.url_action (id,name) values ('suspendMember','suspendMember'); + insert into sunbird.url_action (id,name) values ('createCourse','createCourse'); + insert into sunbird.url_action (id,name) values ('updateCourse','updateCourse'); + insert into sunbird.url_action (id,name) values ('createContent','createContent'); + insert into sunbird.url_action (id,name) values ('updateContent','updateContent'); + insert into sunbird.url_action (id,name) values ('flagCourse','flagCourse'); + insert into sunbird.url_action (id,name) values ('flagContent','flagContent'); + insert into sunbird.url_action (id,name) values ('publishCourse','publishCourse'); + insert into sunbird.url_action (id,name) values ('publishContent','publishContent'); + ALTER table sunbird.role_group add url_action_ids list; + + update sunbird.role_group set url_action_ids=['addMember','removeMember','suspendMember'] where id='MEMBERSHIP_MANAGEMENT'; + update sunbird.role_group set url_action_ids=['createCourse','updateCourse','createContent','updateContent'] where id='CONTENT_CREATION'; + update sunbird.role_group set url_action_ids=['suspendOrg','suspendUser'] where id='SYSTEM_ADMINISTRATION'; + update sunbird.role_group set url_action_ids=['publishCourse','publishContent'] where id='CONTENT_REVIEW'; + update sunbird.role_group set url_action_ids=['createOrg','updateOrg','removeOrg','createUser','updateUser'] where id='ORG_MANAGEMENT'; + update sunbird.role_group set url_action_ids=['flagCourse','flagContent'] where id='CONTENT_CURATION'; + + update sunbird.url_action set url=['/v1/course/publish'] where id='publishContent'; +update sunbird.url_action set url=['/v1/user/create'] where id='addMember'; + update sunbird.url_action set url=['v1/course/create'] where id='createCourse'; +update sunbird.url_action set url=['/v1/user/create'] where id='createUser'; + update sunbird.url_action set url=['/v1/course/publish'] where id='publishCourse'; +update sunbird.url_action set url=['/v1/organisation/update'] where id='updateOrg'; + +drop index inx_uorg_orgid; +ALTER TABLE sunbird.user_org DROP orgid; +ALTER TABLE sunbird.user_org ADD organisationid text; +ALTER TABLE sunbird.user_org ADD addedby text; +ALTER TABLE sunbird.user_org ADD addedbyname text; +CREATE INDEX inx_uorg_orgid ON sunbird.user_org (organisationid); + + +/* +creation of id= one way hash of (userId##courseId##batchId) here courseId is identifier of EkStep course +toc url is generated from ekStep +here status is (default(0),inProgress(1),completed(2)) +progress is no of content completed +*/ +CREATE TABLE IF NOT EXISTS sunbird.user_courses(id text, courseId text, courseName text, userId text, batchId text, enrolledDate text, +description text,tocUrl text,status int,active boolean,delta text,grade text,progress int,lastReadContentId text, +lastReadContentStatus int,addedBy text,courseLogoUrl text, dateTime timestamp, contentId text, PRIMARY KEY (id)); + +CREATE INDEX inx_ucs_userId ON sunbird.user_courses (userId); +CREATE INDEX inx_ucs_courseId ON sunbird.user_courses (courseId); +CREATE INDEX inx_ucs_batchId ON sunbird.user_courses (batchId); +CREATE INDEX inx_ucs_course_name ON sunbird.user_courses (courseName); +CREATE INDEX inx_ucs_status ON sunbird.user_courses (status); + +DROP INDEX IF EXISTS inx_uei_source; +ALTER TABLE sunbird.user_external_identity DROP source; +ALTER TABLE sunbird.user_external_identity ADD provider text; +ALTER TABLE sunbird.user_external_identity ADD externalIdValue text; +CREATE INDEX inx_uei_provider ON sunbird.user_external_identity (provider); + +//changes 7 July 2017 updated organization table +ALTER TABLE sunbird.organisation ADD rootOrgID text; +ALTER TABLE sunbird.org_mapping ADD rootOrgID text; +CREATE TABLE IF NOT EXISTS sunbird.org_type(id text, name text, PRIMARY KEY (id)); +DROP INDEX sunbird.inx_org_status; +ALTER TABLE sunbird.organisation DROP status ; +ALTER TABLE sunbird.organisation ADD status text; + +CREATE INDEX inx_org_status ON sunbird.organisation (status); + +CREATE INDEX inx_u_loginId ON sunbird.user(loginId); + +ALTER TABLE sunbird.user_job_profile ADD isCurrentJob boolean; +ALTER TABLE sunbird.content_consumption ADD progress int; +ALTER TABLE sunbird.content_consumption DROP viewPosition; + +//changes on 12th july 2017 +ALTER TABLE sunbird.user_job_profile ADD isDeleted boolean; +ALTER TABLE sunbird.user_education ADD isDeleted boolean; +ALTER TABLE sunbird.address ADD isDeleted boolean; +ALTER TABLE sunbird.user_org ADD isDeleted boolean; +ALTER TABLE sunbird.user ADD profileSummary text; + +ALTER TABLE sunbird.organisation ADD source text; +ALTER TABLE sunbird.organisation ADD externalId text; + +ALTER TABLE sunbird.user_org drop role; +ALTER TABLE sunbird.user_org ADD roles list; + +//to export data from csv to cassandra table run below command(for page_section and page_management table) +// change the path of csv file +//COPY sunbird.page_management(id, appmap,createdby ,createddate ,name ,organisationid ,portalmap ,updatedby ,updateddate ) FROM '/tmp/cql/pageMgmt.csv'; + +//COPY sunbird.page_section(id, alt,createdby ,createddate ,description ,display ,imgurl ,name,searchquery , sectiondatatype ,status , updatedby ,updateddate) FROM '/tmp/cql/pageSection.csv'; + +// insert default root organisation -- July 15,2017 +ALTER TABLE sunbird.organisation ADD isDefault boolean; + +ALTER TABLE sunbird.user_courses ADD leafNodesCount int; +// change organisation status field from text to int -- July 19,2017 +drop index inx_org_status; +ALTER TABLE sunbird.organisation DROP status ; +ALTER TABLE sunbird.organisation ADD status int; +CREATE INDEX inx_org_status ON sunbird.organisation (status); + + +// add isdeleted field to user table -- July 31,2017 +ALTER TABLE sunbird.user ADD isDeleted boolean; + +//added for course batch +CREATE TABLE IF NOT EXISTS sunbird.course_batch(id text, courseId text,courseCreator text,createdBy text,createdOn text,enrollmentType text,startDate text,endDate text,name text,description text,status int,lastUpdatedOn text,mentors List,participants List,createdFor List,PRIMARY KEY (id)); +CREATE INDEX inx_cou_bat_status ON sunbird.course_batch (status); +CREATE INDEX inx_cou_bat_courseId ON sunbird.course_batch (courseId); +CREATE INDEX inx_cou_bat_courseCreator ON sunbird.course_batch (courseCreator); +CREATE INDEX inx_cou_bat_createdBy ON sunbird.course_batch (createdBy); +CREATE INDEX inx_cou_bat_enrolmentType ON sunbird.course_batch (enrollmentType); +ALTER TABLE sunbird.course_batch DROP createdon; +ALTER TABLE sunbird.course_batch ADD createdDate text; +ALTER TABLE sunbird.course_batch DROP lastupdatedon; +ALTER TABLE sunbird.course_batch ADD updatedDate text; + +ALTER TABLE sunbird.organisation add provider text; +ALTER TABLE sunbird.organisation DROP source; +//Id is courseId +CREATE TABLE IF NOT EXISTS sunbird.course_publish_status(id text,submitDate text,status int,PRIMARY KEY (id)); + +// convert data type of participants from List to map -- Aug 7,2017 +ALTER TABLE sunbird.course_batch DROP participants; +ALTER TABLE sunbird.course_batch ADD participant map; + +ALTER TABLE sunbird.course_batch ADD courseAdditionalInfo map; + +// adding the batchId column to content consumption table -- Aug 8,2017 +ALTER TABLE sunbird.content_consumption ADD batchId text; + +CREATE TABLE IF NOT EXISTS sunbird.bulk_upload_process(id text, status int,data text,successResult text,failureResult text,uploadedBy text,uploadedDate text,processStartTime text,processEndTime text,ObjectType text,organisationId text, PRIMARY KEY (id)); +CREATE INDEX inx_status ON sunbird.bulk_upload_process(status); +insert into sunbird.role_group (id,name) values ('COURSE_MENTOR','Course Mentor'); +update sunbird.role_group set url_action_ids=['courseMentor'] where id='COURSE_MENTOR'; + +ALTER TABLE sunbird.course_batch ADD countIncrementStatus boolean; +ALTER TABLE sunbird.course_batch ADD countIncrementDate text; +ALTER TABLE sunbird.course_batch ADD countDecrementStatus boolean; +ALTER TABLE sunbird.course_batch ADD countDecrementDate text; + +CREATE INDEX inx_org_provider ON sunbird.organisation (provider); +CREATE INDEX inx_org_externalId ON sunbird.organisation (externalId); + +insert into sunbird.url_action (id,name) values ('orgupload','orgupload'); +update sunbird.role_group set url_action_ids=['suspendOrg','suspendUser','orgupload'] where id='SYSTEM_ADMINISTRATION'; +update sunbird.url_action set url=['/v1/org/suspend'] where id='suspendOrg'; +update sunbird.url_action set url=['/v1/user/block'] where id='suspendUser'; +update sunbird.url_action set url=['/v1/org/upload'] where id='orgupload'; +insert into sunbird.role (id,name,rolegroupid,status) values ('COURSE_MENTOR','Course Mentor',['COURSE_MENTOR'],1); + +// changes on Aug 16,2017 +ALTER TABLE sunbird.organisation ADD slug text; +ALTER TABLE sunbird.organisation ADD hashTagId text; +ALTER TABLE sunbird.organisation ADD theme text; +ALTER TABLE sunbird.user_org ADD position text; +ALTER TABLE sunbird.course_batch ADD hashTagId text; +CREATE INDEX inx_cps_status ON sunbird.course_publish_status (status); +ALTER TABLE sunbird.user ADD location text; +ALTER TABLE sunbird.organisation ADD contactDetails map; +insert into sunbird.role_group (id,name) values ('FLAG_REVIEWER ','Flag Reviewer'); +insert into sunbird.url_action (id,name) values ('FLAG_REVIEWER','flag Review'); +insert into sunbird.role (id,name,rolegroupid,status) values ('FLAG_REVIEWER','Flag Reviewer',['FLAG_REVIEWER'],1); +update sunbird.role_group set url_action_ids=['flagReview'] where id='FLAG_REVIEWER'; +ALTER TABLE sunbird.organisation DROP contactdetails; +ALTER TABLE sunbird.organisation ADD contactdetail text; + +//update course_batch set countdecrementstatus=false ,countincrementstatus=false where id in ('01231295903433523233', '01231300152093900880', '01231362610791219226', '012311485318971392184', '012311507396763648187', '01231446621414195215', '012311399697334272167', '012310182931898368117', '01231437156529766411', '0123143731552501769', '012315729890295808125', '01231515693522124824', '012315105801404416176', '012315113121030144181', '0123156336446914560', '0123152537517178880', '012311452395159552176', '012310182079651840116', '01231365904918118428', '012315115229880320201', '01231297804052070441', '01231295967369625632', '01231437649992908813', '01231298538289561658', '01231290682958643227', '012310176900218880115', '012311394333097984166', '012311400451145728168', '01231513667683942421', '012315115088601088183', '0123153123053158404', '01231363201368064027', '01231290412171264026', '0123151248760258560', '01231514986607411223', '012311580166266880203', '01231217800957952058', '01231304911540224098', '0123152769465384961', '012310190924496896119', '01231569596413542494', '01231299360593510461', '01231437480674099212', '012310195742662656126', '012311489586135040185', '01231298390404300857', '012311415973486592169', '01231298670022656060', '01231569429976678493', '01231294824787148831', '012310173385113600114', '01231385960518451255', '012315785629794304137', '01231296418316288037', '012310193544601600118', '012311447751262208177', '012311507213688832188', '01231437595463680010', '0123156778024960005', '012311505273479168186', '01231300602153369682', '01231298422152396859', '0123152820520222722', '012311511755972608189', '012315179912159232103', '012315751464787968136', '012315736241045504130', '01231288911727001615', '01231514371529113622', '01231366031184691229', '01231383864920473645', '012315107363119104182', '012311574182944768202', '01231516784369664088', '01231443633637785614', '01231300661683814481' ); +insert into sunbird.role_group (id,name) values ('COURSE_ADMIN','Course Admin'); +update sunbird.role_group set url_action_ids=['courseAdmin'] where id='COURSE_ADMIN'; +insert into sunbird.role (id,name,rolegroupid,status) values ('COURSE_ADMIN','Course Admin',['COURSE_ADMIN'],1); +insert into sunbird.role_group (id,name) values ('COURSE_CREATOR','Course Creator'); +update sunbird.role_group set url_action_ids=['courseCreator'] where id='COURSE_CREATOR'; +insert into sunbird.role (id,name,rolegroupid,status) values ('COURSE_CREATOR','Course Creator',['COURSE_CREATOR'],1); +update sunbird.role_group set name='Flag Reviewer' where id='FLAG_REVIEWER'; +//changes on Aug 29,2017 +CREATE TABLE IF NOT EXISTS sunbird.badge(id text, name text, description text, isActive boolean, PRIMARY KEY (id)); +CREATE TABLE IF NOT EXISTS sunbird.user_badge(id text, createdDate text, createdBy text, updatedDate text,updatedBy text,badgeTypeId text,receivedDate text,receiverId text,providerId text,providerName text,providerEmail text,providerPhone text,description text,validityDate int,expiryDate text,image text,isVerified boolean,isExpired boolean,isRevoked boolean,revocationReason text,revocationDate text,revokedBy text,verifiedBy text,verifiedDate text ,PRIMARY KEY (id)); + CREATE INDEX inx_usr_badg ON sunbird.user_badge (badgeTypeId); + insert into sunbird.badge (id,name,description,isactive) values ('0123206539020943360','President''s Gold Medal','Gold medal provided by President',true); + CREATE INDEX inx_usr_badg_receiverid ON sunbird.user_badge (receiverid); +CREATE INDEX inx_uei_externalIdValue ON sunbird.user_external_identity (externalIdValue); + +//adding for report tracking +CREATE TABLE IF NOT EXISTS sunbird.report_tracking(id text, status int,type text,createdDate text,userId text,uploadedDate text,email text,fileUrl text,emailTryCount int, PRIMARY KEY (id)); +CREATE INDEX inx_report_tracking_status ON sunbird.report_tracking(status); +CREATE INDEX inx_report_tracking_userId ON sunbird.report_tracking(userId); +ALTER TABLE sunbird.report_tracking ADD firstName text; +ALTER TABLE sunbird.report_tracking ADD batchId text; +ALTER TABLE sunbird.report_tracking ADD period text; +ALTER TABLE sunbird.report_tracking ADD data text; +insert into sunbird.role_group (id,name) values ('PUBLIC','Public'); +update sunbird.role_group set url_action_ids=['public'] where id='PUBLIC'; +insert into sunbird.role (id,name,rolegroupid,status) values ('PUBLIC','Public',['PUBLIC'],1); +ALTER TABLE sunbird.report_tracking ADD tryCount int; +ALTER TABLE sunbird.report_tracking DROP emailTryCount; +ALTER TABLE sunbird.report_tracking ADD updatedDate text; + +//Changes on Aug 31st 2017 +ALTER TABLE sunbird.report_tracking DROP batchId; +ALTER TABLE sunbird.report_tracking ADD resourceId text; + +// adding fileFormat for dashboard metrics report tracking -- Sep 1,2017 +ALTER TABLE sunbird.report_tracking ADD format text; + +ALTER TABLE sunbird.user DROP aadhaarno; +update organisation set channel='ROOT_ORG' where id='ORG_001'; + +// Sept 18th 2017 +ALTER TABLE sunbird.org_type ADD createdDate text; +ALTER TABLE sunbird.org_type ADD createdBy text; +ALTER TABLE sunbird.org_type ADD updatedDate text; +ALTER TABLE sunbird.org_type ADD updatedBy text; +//Adding table user_notes --Sep 13th 2017 +CREATE TABLE IF NOT EXISTS sunbird.user_notes(id text, userId text, courseId text, +contentId text, title text, note text, tags list, createdDate text, createdBy text, +updatedDate text, updatedBy text, isDeleted boolean, PRIMARY KEY (id)); +CREATE INDEX inx_un_userId ON sunbird.user_notes(userId); +CREATE INDEX inx_un_courseId ON sunbird.user_notes(courseId); +CREATE INDEX inx_un_contentId ON sunbird.user_notes(contentId); +ALTER TABLE sunbird.user ADD createdBy text; + +//Adding changes related to social media in user table +ALTER TABLE sunbird.user ADD webpages list>>; +CREATE TABLE IF NOT EXISTS sunbird.media_type(id text, name text, PRIMARY KEY (id)); + +insert into media_type(id,name) values('fb', 'facebook'); +insert into media_type(id,name) values('twitter','twitter'); +insert into media_type(id,name) values('in','linkedin'); +insert into media_type(id,name) values('blog','blog'); +//Oct 12th +ALTER TABLE sunbird.user ADD tempPassword text; +ALTER TABLE sunbird.user ADD currentLoginTime text; +//Oct 18th +UPDATE sunbird.media_type SET name = 'Facebook' where id = 'fb'; +UPDATE sunbird.media_type SET name = 'Twitter' where id = 'twitter'; +UPDATE sunbird.media_type SET name = 'LinkedIn' where id = 'in'; +UPDATE sunbird.media_type SET name = 'Blog' where id = 'blog'; + +ALTER TABLE sunbird.bulk_upload_process ADD retryCount int; + +// userSkill table to store the user skills - Oct 18, 2017 --- +/* +creation of id = one way hash of (userId##skillnametolowercase) +*/ +CREATE TABLE IF NOT EXISTS sunbird.user_skills(id text, userId text, skillname text,skillnametolowercase text, addedby text, addedat text, endorsementcount int ,endorsers Map, PRIMARY KEY (id)); +CREATE INDEX inx_us_userId ON sunbird.user_skills(userId); + +// skills table - Oct 18, 2017 --- +/* +creation of id = one way hash of (userId##skillnametolowercase) +*/ +CREATE TABLE IF NOT EXISTS sunbird.skills(id text,skills list, PRIMARY KEY (id)); + +//25th Oct +ALTER TABLE sunbird.organisation ADD orgTypeId text; + +//Announcement apis -27th Oct +CREATE KEYSPACE IF NOT EXISTS sunbirdplugin WITH replication = {'class':'SimpleStrategy','replication_factor':1}; +//CREATE TYPE IF NOT EXISTS sunbirdplugin.attachment (id text,filename text,mimetype text); +CREATE TABLE sunbirdplugin.announcement (id text,userid text,sourceid text,details map,links list,attachments list,target text,sentcount int,priority text,expiry text,status text,createddate text,updateddate text, PRIMARY KEY (id)); +CREATE TABLE sunbirdplugin.attachment (id text,file text,filename text,mimetype text,createdby text,status text,createddate text, PRIMARY KEY (id)); +CREATE TABLE sunbirdplugin.metrics (id text,userid text,announcementid text,activity text,channel text,createddate text, PRIMARY KEY (id)); +CREATE TABLE sunbirdplugin.announcementtype (id text,rootorgid text,name text,status text,createddate text, PRIMARY KEY (id)); +CREATE TABLE sunbirdplugin.announcementauth (id text,userid text,rootorgid text,permissions map,status text,createddate text, PRIMARY KEY (id)); + +insert into sunbird.role_group (id,name) values ('ANNOUNCEMENT_SENDER','Announcement Sender'); +update sunbird.role_group set url_action_ids=['Announcement Sender'] where id='ANNOUNCEMENT_SENDER'; +insert into sunbird.role (id,name,rolegroupid,status) values ('ANNOUNCEMENT_SENDER','Announcement Sender',['ANNOUNCEMENT_SENDER'],1); + +//mongodb import , env var is taken from group_vars +//COPY sunbird.user_notes(id, userid,courseid,contentid,title,note,tags,createddate,updateddate,isdeleted) FROM '/tmp/notes-{{env}}.csv'; +//2nd Nov +CREATE TABLE IF NOT EXISTS sunbird.tenant_preference(id text,tenantName text,orgId text,role text, data text, PRIMARY KEY (id)); +CREATE INDEX inx_tp_userId ON sunbird.tenant_preference(orgId); +ALTER TABLE sunbird.user ADD tcstatus text; +//CLIENT_INFO table for master key +CREATE TABLE IF NOT EXISTS sunbird.client_info(id text, clientname text, masterkey text, createddate text, updateddate text, PRIMARY KEY (id)); +CREATE INDEX inx_ci_clientname ON sunbird.client_info(clientname); +// Geo Location - Oct 31,2017 + +ALTER TABLE sunbird.user ADD tcupdateddate text; + +CREATE TABLE IF NOT EXISTS sunbird.geo_location(id text,locationName text,rootOrgId text,type text, createdDate text,createdBy text,updatedDate text,updatedBy text,topicName text,topicId text, PRIMARY KEY (id)); +CREATE INDEX inx_gl_rootOrgId ON sunbird.geo_location(rootOrgId); +ALTER TABLE sunbird.geo_location DROP topicId ; +ALTER TABLE sunbird.geo_location DROP topicName ; +ALTER TABLE sunbird.geo_location ADD topic text; +ALTER TABLE sunbird.geo_location DROP locationName ; +ALTER TABLE sunbird.geo_location ADD location text; +// 3rd Nov 2017 +ALTER TABLE sunbird.organisation ADD locationId text; + +ALTER TABLE sunbird.user ADD profileVisibility map; + +// 9th Nov 2017 +ALTER TABLE sunbirdplugin.announcement DROP target ; +ALTER TABLE sunbirdplugin.announcement ADD target map>>>>; +//adding default one Skills. +insert into skills (id,skills) values ('001',['java']); +ALTER TABLE sunbird.user_skills drop endorsers; +ALTER TABLE sunbird.user_skills ADD endorsersList frozen>>; +// 16th Nov 2017 +ALTER TABLE sunbird.user ADD emailVerified boolean; + +// 23rd Nov 2017 +ALTER TABLE sunbird.user ADD countryCode text; +CREATE TABLE IF NOT EXISTS sunbird.system_settings (id text ,field text ,value text ,PRIMARY KEY (id)); + +// Dec 5th 2017 + +ALTER TABLE sunbird.geo_location ADD userCount int; + +insert into sunbird.system_settings (id,field,value) values ('phoneUnique','phoneUnique','false'); +insert into sunbird.system_settings (id,field,value) values ('emailUnique','emailUnique','false'); +// Dec 6th 2017 +ALTER TABLE sunbird.geo_location ADD userCountTTL text; +// adding new column in client-info to save the channel +ALTER TABLE sunbird.client_info ADD channel text; +CREATE INDEX inx_ci_clientchannel ON sunbird.client_info(channel); diff --git a/actors/sunbird-lms-mw/service/src/main/resources/quartz.properties b/actors/sunbird-lms-mw/service/src/main/resources/quartz.properties new file mode 100644 index 0000000000..3ad176a1ae --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/main/resources/quartz.properties @@ -0,0 +1,35 @@ +#============================================================================ +# Configure Main Scheduler Properties +#============================================================================ + +org.quartz.scheduler.instanceName = MyScheduler +org.quartz.scheduler.instanceId = AUTO + +#============================================================================ +# Configure ThreadPool +#============================================================================ + +org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool +org.quartz.threadPool.threadCount = 1 + +#============================================================================ +# Configure JobStore +#============================================================================ + +org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX +org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate +org.quartz.jobStore.tablePrefix = QRTZ_ +org.quartz.jobStore.useProperties = false +org.quartz.jobStore.dataSource=MySqlDS +org.quartz.jobStore.isClustered = true +org.quartz.jobStore.clusterCheckinInterval = 5000 + +#============================================================================ +# Configure Datasources +#============================================================================ +org.quartz.dataSource.MySqlDS.driver = org.postgresql.Driver +org.quartz.dataSource.MySqlDS.URL = jdbc:postgresql://localhost/postgres +org.quartz.dataSource.MySqlDS.user = postgres +org.quartz.dataSource.MySqlDS.password = root +org.quartz.dataSource.MySqlDS.maxConnections = 2 +org.quartz.dataSource.MySqlDS.validationQuery=select 0 from qrtz_triggers \ No newline at end of file diff --git a/actors/sunbird-lms-mw/service/src/main/resources/tables_postgres.sql b/actors/sunbird-lms-mw/service/src/main/resources/tables_postgres.sql new file mode 100644 index 0000000000..512a9b1ed4 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/main/resources/tables_postgres.sql @@ -0,0 +1,187 @@ +-- Thanks to Patrick Lightbody for submitting this... +-- +-- In your Quartz properties file, you'll need to set +-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate + +drop table qrtz_fired_triggers; +DROP TABLE QRTZ_PAUSED_TRIGGER_GRPS; +DROP TABLE QRTZ_SCHEDULER_STATE; +DROP TABLE QRTZ_LOCKS; +drop table qrtz_simple_triggers; +drop table qrtz_cron_triggers; +drop table qrtz_simprop_triggers; +DROP TABLE QRTZ_BLOB_TRIGGERS; +drop table qrtz_triggers; +drop table qrtz_job_details; +drop table qrtz_calendars; + +CREATE TABLE qrtz_job_details + ( + SCHED_NAME VARCHAR(120) NOT NULL, + JOB_NAME VARCHAR(200) NOT NULL, + JOB_GROUP VARCHAR(200) NOT NULL, + DESCRIPTION VARCHAR(250) NULL, + JOB_CLASS_NAME VARCHAR(250) NOT NULL, + IS_DURABLE BOOL NOT NULL, + IS_NONCONCURRENT BOOL NOT NULL, + IS_UPDATE_DATA BOOL NOT NULL, + REQUESTS_RECOVERY BOOL NOT NULL, + JOB_DATA BYTEA NULL, + PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) +); + +CREATE TABLE qrtz_triggers + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + JOB_NAME VARCHAR(200) NOT NULL, + JOB_GROUP VARCHAR(200) NOT NULL, + DESCRIPTION VARCHAR(250) NULL, + NEXT_FIRE_TIME BIGINT NULL, + PREV_FIRE_TIME BIGINT NULL, + PRIORITY INTEGER NULL, + TRIGGER_STATE VARCHAR(16) NOT NULL, + TRIGGER_TYPE VARCHAR(8) NOT NULL, + START_TIME BIGINT NOT NULL, + END_TIME BIGINT NULL, + CALENDAR_NAME VARCHAR(200) NULL, + MISFIRE_INSTR SMALLINT NULL, + JOB_DATA BYTEA NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) + REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) +); + +CREATE TABLE qrtz_simple_triggers + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + REPEAT_COUNT BIGINT NOT NULL, + REPEAT_INTERVAL BIGINT NOT NULL, + TIMES_TRIGGERED BIGINT NOT NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_cron_triggers + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + CRON_EXPRESSION VARCHAR(120) NOT NULL, + TIME_ZONE_ID VARCHAR(80), + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_simprop_triggers + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + STR_PROP_1 VARCHAR(512) NULL, + STR_PROP_2 VARCHAR(512) NULL, + STR_PROP_3 VARCHAR(512) NULL, + INT_PROP_1 INT NULL, + INT_PROP_2 INT NULL, + LONG_PROP_1 BIGINT NULL, + LONG_PROP_2 BIGINT NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 BOOL NULL, + BOOL_PROP_2 BOOL NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_blob_triggers + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + BLOB_DATA BYTEA NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_calendars + ( + SCHED_NAME VARCHAR(120) NOT NULL, + CALENDAR_NAME VARCHAR(200) NOT NULL, + CALENDAR BYTEA NOT NULL, + PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) +); + + +CREATE TABLE qrtz_paused_trigger_grps + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_fired_triggers + ( + SCHED_NAME VARCHAR(120) NOT NULL, + ENTRY_ID VARCHAR(95) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + INSTANCE_NAME VARCHAR(200) NOT NULL, + FIRED_TIME BIGINT NOT NULL, + SCHED_TIME BIGINT NOT NULL, + PRIORITY INTEGER NOT NULL, + STATE VARCHAR(16) NOT NULL, + JOB_NAME VARCHAR(200) NULL, + JOB_GROUP VARCHAR(200) NULL, + IS_NONCONCURRENT BOOL NULL, + REQUESTS_RECOVERY BOOL NULL, + PRIMARY KEY (SCHED_NAME,ENTRY_ID) +); + +CREATE TABLE qrtz_scheduler_state + ( + SCHED_NAME VARCHAR(120) NOT NULL, + INSTANCE_NAME VARCHAR(200) NOT NULL, + LAST_CHECKIN_TIME BIGINT NOT NULL, + CHECKIN_INTERVAL BIGINT NOT NULL, + PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) +); + +CREATE TABLE qrtz_locks + ( + SCHED_NAME VARCHAR(120) NOT NULL, + LOCK_NAME VARCHAR(40) NOT NULL, + PRIMARY KEY (SCHED_NAME,LOCK_NAME) +); + +create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY); +create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP); + +create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); +create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP); +create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME); +create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP); +create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE); +create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); +create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); +create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); +create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); + +create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME); +create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); +create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); +create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP); +create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); +create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP); + + +commit; diff --git a/actors/sunbird-lms-mw/service/src/test/java/org/sunbird/learner/actors/OrgExternalServiceTest.java b/actors/sunbird-lms-mw/service/src/test/java/org/sunbird/learner/actors/OrgExternalServiceTest.java new file mode 100644 index 0000000000..7d99d4f93f --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/java/org/sunbird/learner/actors/OrgExternalServiceTest.java @@ -0,0 +1,37 @@ +package org.sunbird.learner.actors; + +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.sunbird.cassandraimpl.CassandraOperationImpl; +import org.sunbird.helper.ServiceFactory; +import org.sunbird.learner.organisation.external.identity.service.OrgExternalService; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ServiceFactory.class}) +@PowerMockIgnore({"javax.management.*", "javax.crypto.*", "javax.net.ssl.*", "javax.security.*"}) +public class OrgExternalServiceTest { + private static CassandraOperationImpl cassandraOperation; + private OrgExternalService orgExternalService = new OrgExternalService(); + + @Before + public void beforeEachTest() { + PowerMockito.mockStatic(ServiceFactory.class); + cassandraOperation = mock(CassandraOperationImpl.class); + when(ServiceFactory.getInstance()).thenReturn(cassandraOperation); + } + + @Test + public void testCreateNoteSuccess() { + + assertTrue(true); + } +} diff --git a/actors/sunbird-lms-mw/service/src/test/resources/BulkOrgUploadSample.csv b/actors/sunbird-lms-mw/service/src/test/resources/BulkOrgUploadSample.csv new file mode 100644 index 0000000000..2318f624bd --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/resources/BulkOrgUploadSample.csv @@ -0,0 +1,201 @@ +orgName,isRootOrg,channel,externalId,provider,description,homeUrl,orgCode,orgType,preferredLanguage,theme,contactDetail,hashTagId +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 +hello001,false,,1119,ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7ct4 \ No newline at end of file diff --git a/actors/sunbird-lms-mw/service/src/test/resources/BulkOrgUploadSampleWithRootOrgTrue.csv b/actors/sunbird-lms-mw/service/src/test/resources/BulkOrgUploadSampleWithRootOrgTrue.csv new file mode 100644 index 0000000000..1816b8c766 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/resources/BulkOrgUploadSampleWithRootOrgTrue.csv @@ -0,0 +1,2 @@ +orgName,isRootOrg,channel,externalId,provider,description,homeUrl,orgCode,orgType,preferredLanguage,theme,contactDetail,hashTagId +hello002,true,himanchalboardk9899543c,1119gxf47,hbx3r8ugc,technical,googlehome,122,,hindi,sunbied,"[{'name':'abcd','age':110},{'fax':123456}]",ggy6dnuyy7c54 diff --git a/actors/sunbird-lms-mw/service/src/test/resources/BulkUploadBatchSample.csv b/actors/sunbird-lms-mw/service/src/test/resources/BulkUploadBatchSample.csv new file mode 100644 index 0000000000..2889d83562 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/resources/BulkUploadBatchSample.csv @@ -0,0 +1,2 @@ +batchId,userIds +batch78575ir8478,"bcic783gfu239,nhhuc37i5t8,h7884f7t8" \ No newline at end of file diff --git a/actors/sunbird-lms-mw/service/src/test/resources/BulkUploadUserSample.csv b/actors/sunbird-lms-mw/service/src/test/resources/BulkUploadUserSample.csv new file mode 100644 index 0000000000..8599767242 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/resources/BulkUploadUserSample.csv @@ -0,0 +1,2 @@ +firstName,lastName,phone,email,userName,countryCode,phoneVerified,emailVerified,roles,position,location,dob,gender,language,profileSummary,subject,webPages +xyz1234516,Kumar15,9453500000,bk3@yahoo.com,bk3hoo,countryCode,true,true,,pos,loc,1992-10-12,MALE,"ENGLISH,KANADA",summary,"HINDI,MATH,PHYSICS", diff --git a/actors/sunbird-lms-mw/service/src/test/resources/FrameworkForTextbookTocActorTest.json b/actors/sunbird-lms-mw/service/src/test/resources/FrameworkForTextbookTocActorTest.json new file mode 100644 index 0000000000..ce216c1eb6 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/resources/FrameworkForTextbookTocActorTest.json @@ -0,0 +1 @@ +{ "identifier":"Identifier","frameworkCategories":{"medium":"Medium","gradeLevel":"Grade","subject":"Subject"},"hierarchy":{"Textbook":"Textbook Name","L:1":"Level 1 Textbook Unit","L:2":"Level 2 Textbook Unit","L:3":"Level 3 Textbook Unit","L:4":"Level 4 Textbook Unit"},"metadata":{"description":"Description","dialcodeRequired":"QR Code Required?","dialcodes":"QR Code","purpose":"Purpose of Content to be linked","topic":"Mapped Topics","keywords":"Keywords"}} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/service/src/test/resources/MandatoryValueForTextbookTocActorTest.json b/actors/sunbird-lms-mw/service/src/test/resources/MandatoryValueForTextbookTocActorTest.json new file mode 100644 index 0000000000..bd644ecf05 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/resources/MandatoryValueForTextbookTocActorTest.json @@ -0,0 +1 @@ +{"Textbook":"Textbook Name","L:1":"Level 1 Textbook Unit"} \ No newline at end of file diff --git a/actors/sunbird-lms-mw/service/src/test/resources/dbconfig.properties b/actors/sunbird-lms-mw/service/src/test/resources/dbconfig.properties new file mode 100644 index 0000000000..e998963688 --- /dev/null +++ b/actors/sunbird-lms-mw/service/src/test/resources/dbconfig.properties @@ -0,0 +1,5 @@ +db.ip=127.0.0.1 +db.port=9042 +db.username=cassandra +db.password=password +db.keyspace=sunbird diff --git a/scripts/setup.sh b/scripts/setup.sh index e0966cf58c..bebf28643a 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -3,3 +3,4 @@ REPO_ROOT_DIR="$(git rev-parse --show-toplevel)" cp "${REPO_ROOT_DIR}/git-hooks/pre-commit" "${REPO_ROOT_DIR}/.git/hooks/" +echo "format hooks registered" diff --git a/service/app/controllers/BaseController.java b/service/app/controllers/BaseController.java index 02dda98045..132075edf0 100644 --- a/service/app/controllers/BaseController.java +++ b/service/app/controllers/BaseController.java @@ -4,15 +4,12 @@ import akka.actor.ActorSelection; import akka.pattern.PatternsCS; import akka.util.Timeout; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; @@ -30,18 +27,16 @@ import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; import org.sunbird.common.models.util.ProjectUtil; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.HeaderParam; import org.sunbird.common.responsecode.ResponseCode; import org.sunbird.telemetry.util.TelemetryEvents; -import org.sunbird.telemetry.util.TelemetryLmaxWriter; +import org.sunbird.telemetry.util.TelemetryWriter; import play.libs.Json; import play.mvc.Controller; import play.mvc.Http; import play.mvc.Http.Request; import play.mvc.Result; import play.mvc.Results; -import util.AuthenticationHelper; /** * This controller we can use for writing some common method. @@ -50,10 +45,10 @@ */ public class BaseController extends Controller { + private static ObjectMapper objectMapper = new ObjectMapper(); public static final int AKKA_WAIT_TIME = 30; private static final String version = "v1"; private static Object actorRef = null; - private TelemetryLmaxWriter lmaxWriter = TelemetryLmaxWriter.getInstance(); protected Timeout timeout = new Timeout(AKKA_WAIT_TIME, TimeUnit.SECONDS); static { @@ -71,6 +66,12 @@ private org.sunbird.common.request.Request initRequest( request.getParams().setMsgid(httpRequest.flash().get(JsonKey.REQUEST_ID)); request.setEnv(getEnvironment()); request.getContext().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); + String muid = httpRequest.flash().get(JsonKey.MANAGED_FOR); + request.getContext().put(JsonKey.MANAGED_FOR, muid); + Optional manageToken = httpRequest.header(HeaderParam.X_Authenticated_For.getName()); + String managedToken = manageToken.isPresent() ? manageToken.get() : ""; + request.getContext().put(JsonKey.MANAGED_TOKEN, managedToken); + request = transformUserId(request); return request; } @@ -300,32 +301,23 @@ public static Response createFailureResponse( response.setId(getApiResponseId(request)); response.setTs(ProjectUtil.getFormattedDate()); response.setResponseCode(headerCode); - response.setParams(createResponseParamObj(code)); + response.setParams(createResponseParamObj(code, null, request.flash().get(JsonKey.REQUEST_ID))); return response; } - public static ResponseParams createResponseParamObj(ResponseCode code, String customMessage) { + public static ResponseParams createResponseParamObj( + ResponseCode code, String customMessage, String requestId) { ResponseParams params = new ResponseParams(); if (code.getResponseCode() != 200) { params.setErr(code.getErrorCode()); params.setErrmsg( StringUtils.isNotBlank(customMessage) ? customMessage : code.getErrorMessage()); } - params.setMsgid(ExecutionContext.getRequestId()); + params.setMsgid(requestId); params.setStatus(ResponseCode.getHeaderResponseCode(code.getResponseCode()).name()); return params; } - /** - * This method will create response parameter - * - * @param code ResponseCode - * @return ResponseParams - */ - public static ResponseParams createResponseParamObj(ResponseCode code) { - return createResponseParamObj(code, null); - } - /** * This method will create data for success response. * @@ -344,7 +336,7 @@ public static Result createSuccessResponse(Request request, Response response) { response.setTs(ProjectUtil.getFormattedDate()); ResponseCode code = ResponseCode.getResponse(ResponseCode.success.getErrorCode()); code.setResponseCode(ResponseCode.OK.getResponseCode()); - response.setParams(createResponseParamObj(code)); + response.setParams(createResponseParamObj(code, null, request.flash().get(JsonKey.REQUEST_ID))); String value = null; try { if (response.getResult() != null) { @@ -382,7 +374,7 @@ public static Response createResponseOnException( ProjectLogger.log( exception != null ? exception.getMessage() : "Message is not coming", exception, - genarateTelemetryInfoForError(request)); + generateTelemetryInfoForError(request)); Response response = new Response(); response.setVer(""); if (request != null) { @@ -395,7 +387,9 @@ public static Response createResponseOnException( if (code == null) { code = ResponseCode.SERVER_ERROR; } - response.setParams(createResponseParamObj(code, exception.getMessage())); + response.setParams( + createResponseParamObj( + code, exception.getMessage(), request.flash().get(JsonKey.REQUEST_ID))); if (response.getParams() != null) { response.getParams().setStatus(response.getParams().getStatus()); if (exception.getCode() != null) { @@ -406,7 +400,6 @@ public static Response createResponseOnException( response.getParams().setErrmsg(exception.getMessage()); } } - OnRequestHandler.requestInfo.remove(request.flash().get(JsonKey.REQUEST_ID)); return response; } @@ -424,7 +417,7 @@ public static Response createResponseOnException( response.setTs(ProjectUtil.getFormattedDate()); response.setResponseCode(ResponseCode.getHeaderResponseCode(exception.getResponseCode())); ResponseCode code = ResponseCode.getResponse(exception.getCode()); - response.setParams(createResponseParamObj(code, exception.getMessage())); + response.setParams(createResponseParamObj(code, exception.getMessage(), null)); return response; } @@ -437,49 +430,6 @@ public static Response createResponseOnException( * @return Result */ public Result createCommonResponse(Object response, String key, Request request) { - String requestId = request.flash().getOptional(JsonKey.REQUEST_ID).orElse(null); - if (requestId != null && OnRequestHandler.requestInfo.containsKey(requestId)) { - Map requestInfo = OnRequestHandler.requestInfo.get(requestId); - org.sunbird.common.request.Request req = new org.sunbird.common.request.Request(); - try { - Map params = (Map) requestInfo.get(JsonKey.ADDITIONAL_INFO); - - params.put(JsonKey.LOG_TYPE, JsonKey.API_ACCESS); - params.put(JsonKey.MESSAGE, ""); - params.put(JsonKey.METHOD, request.method()); - // calculate the total time consume - long startTime = (Long) params.get(JsonKey.START_TIME); - params.put(JsonKey.DURATION, calculateApiTimeTaken(startTime)); - removeFields(params, JsonKey.START_TIME); - params.put( - JsonKey.STATUS, - String.valueOf(((Response) response).getResponseCode().getResponseCode())); - params.put(JsonKey.LOG_LEVEL, JsonKey.INFO); - req.setRequest( - generateTelemetryRequestForController( - TelemetryEvents.LOG.getName(), - params, - (Map) requestInfo.get(JsonKey.CONTEXT))); - // if any request is coming form /v1/telemetry/save then don't generate the telemetry log - // for it. - lmaxWriter.submitMessage(req); - } catch (Exception ex) { - ProjectLogger.log( - "BaseController:createCommonResponse Exception in writing telemetry for request " - + requestId, - ex); - } finally { - // remove request info from map - OnRequestHandler.requestInfo.remove(requestId); - ProjectLogger.log( - "BaseController:createCommonResponse removed details for messageId=" + requestId, - LoggerEnum.INFO); - } - } else { - ProjectLogger.log( - "BaseController:createCommonResponse request details not found requestId=" + requestId, - LoggerEnum.ERROR); - } Response courseResponse = (Response) response; if (!StringUtils.isBlank(key)) { Object value = courseResponse.getResult().get(JsonKey.RESPONSE); @@ -534,7 +484,6 @@ private Map generateTelemetryRequestForController( */ public Result createCommonExceptionResponse(Exception e, Request request) { Request req = request; - ProjectLogger.log(e.getMessage(), e, genarateTelemetryInfoForError(request)); ProjectCommonException exception = null; if (e instanceof ProjectCommonException) { exception = (ProjectCommonException) e; @@ -548,20 +497,21 @@ public Result createCommonExceptionResponse(Exception e, Request request) { generateExceptionTelemetry(request, exception); // cleaning request info ... return Results.status( - exception.getResponseCode(), - Json.toJson(BaseController.createResponseOnException(req, exception))); + exception.getResponseCode(), Json.toJson(createResponseOnException(req, exception))); } private void generateExceptionTelemetry(Request request, ProjectCommonException exception) { try { + String reqContext = request.flash().get(JsonKey.CONTEXT); Map requestInfo = - OnRequestHandler.requestInfo.get(request.flash().get(JsonKey.REQUEST_ID)); + objectMapper.readValue(reqContext, new TypeReference>() {}); org.sunbird.common.request.Request reqForTelemetry = new org.sunbird.common.request.Request(); Map params = (Map) requestInfo.get(JsonKey.ADDITIONAL_INFO); params.put(JsonKey.LOG_TYPE, JsonKey.API_ACCESS); params.put(JsonKey.MESSAGE, ""); params.put(JsonKey.METHOD, request.method()); - // calculate the total time consume + params.put("err", exception.getResponseCode() + ""); + params.put("errtype", exception.getCode()); long startTime = (Long) params.get(JsonKey.START_TIME); params.put(JsonKey.DURATION, calculateApiTimeTaken(startTime)); removeFields(params, JsonKey.START_TIME); @@ -573,14 +523,13 @@ private void generateExceptionTelemetry(Request request, ProjectCommonException TelemetryEvents.ERROR.getName(), params, (Map) requestInfo.get(JsonKey.CONTEXT))); - lmaxWriter.submitMessage(reqForTelemetry); + TelemetryWriter.write(reqForTelemetry); } catch (Exception ex) { ex.printStackTrace(); } } private long calculateApiTimeTaken(Long startTime) { - Long timeConsumed = null; if (null != startTime) { timeConsumed = System.currentTimeMillis() - startTime; @@ -604,7 +553,7 @@ public CompletionStage actorResponseHandler( Timeout timeout, String responseKey, Request httpReq) { - setChannelAndActorInfo(httpReq, request); + setContextData(httpReq, request); Function function = result -> { if (ActorOperations.HEALTH_CHECK.getValue().equals(request.getOperation())) { @@ -624,7 +573,12 @@ public CompletionStage actorResponseHandler( } else if (result instanceof File) { return createFileDownloadResponse((File) result); } else { - return createCommonExceptionResponse(new Exception(), httpReq); + if (StringUtils.isNotEmpty((String) response.getResult().get(JsonKey.MESSAGE)) + && response.getResponseCode().getResponseCode() == 0) { + return createCommonResponse(response, responseKey, httpReq); + } else { + return createCommonExceptionResponse((Exception) result, httpReq); + } } } else if (result instanceof ProjectCommonException) { return createCommonExceptionResponse((ProjectCommonException) result, httpReq); @@ -645,8 +599,7 @@ public CompletionStage actorResponseHandler( private Result createClientErrorResponse(Request httpReq, ClientErrorResponse response) { ClientErrorResponse errorResponse = response; generateExceptionTelemetry(httpReq, errorResponse.getException()); - Response responseObj = - BaseController.createResponseOnException(httpReq, errorResponse.getException()); + Response responseObj = createResponseOnException(httpReq, errorResponse.getException()); responseObj.getResult().putAll(errorResponse.getResult()); return Results.status(errorResponse.getException().getResponseCode(), Json.toJson(responseObj)); } @@ -663,17 +616,6 @@ public int getEnvironment() { return ProjectUtil.Environment.dev.getValue(); } - /** - * Method to get UserId by AuthToken - * - * @param token - * @return String - */ - public String getUserIdByAuthToken(String token) { - - return AuthenticationHelper.verifyUserAccesToken(token); - } - /** * Method to get API response Id * @@ -719,6 +661,7 @@ public static String getResponseId(String requestPath) { final String ver = "/" + version; final String ver2 = "/" + JsonKey.VERSION_2; final String ver3 = "/" + JsonKey.VERSION_3; + final String ver4 = "/" + JsonKey.VERSION_4; path = path.trim(); StringBuilder builder = new StringBuilder(""); if (path.startsWith(ver) || path.startsWith(ver2) || path.startsWith(ver3)) { @@ -729,6 +672,8 @@ public static String getResponseId(String requestPath) { requestUrl = requestUrl.replaceFirst(ver2, "api"); } else if (requestUrl.contains(ver3)) { requestUrl = requestUrl.replaceFirst(ver3, "api"); + } else if (requestUrl.contains(ver4)) { + requestUrl = requestUrl.replaceFirst(ver4, "api"); } String[] list = requestUrl.split("/"); for (String str : list) { @@ -788,40 +733,37 @@ public static void setActorRef(Object obj) { actorRef = obj; } - private static Map genarateTelemetryInfoForError(Request request) { - - Map map = new HashMap<>(); - Map requestInfo = - OnRequestHandler.requestInfo.get(request.flash().get(JsonKey.REQUEST_ID)); - if (requestInfo != null) { - Map contextInfo = (Map) requestInfo.get(JsonKey.CONTEXT); - map.put(JsonKey.CONTEXT, contextInfo); + private static Map generateTelemetryInfoForError(Request request) { + try { + Map map = new HashMap<>(); + String reqContext = request.flash().get(JsonKey.CONTEXT); + Map requestInfo = + objectMapper.readValue(reqContext, new TypeReference>() {}); + if (requestInfo != null) { + Map contextInfo = (Map) requestInfo.get(JsonKey.CONTEXT); + map.put(JsonKey.CONTEXT, contextInfo); + } + Map params = new HashMap<>(); + params.put(JsonKey.ERR_TYPE, JsonKey.API_ACCESS); + map.put(JsonKey.PARAMS, params); + return map; + } catch (Exception ex) { + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); } - Map params = new HashMap<>(); - params.put(JsonKey.ERR_TYPE, JsonKey.API_ACCESS); - map.put(JsonKey.PARAMS, params); - return map; + return Collections.emptyMap(); } - public void setChannelAndActorInfo( - Http.Request httpReq, org.sunbird.common.request.Request reqObj) { - - reqObj.getContext().put(JsonKey.CHANNEL, httpReq.flash().get(JsonKey.CHANNEL)); - reqObj.getContext().put(JsonKey.ACTOR_ID, httpReq.flash().get(JsonKey.ACTOR_ID)); - reqObj.getContext().put(JsonKey.ACTOR_TYPE, httpReq.flash().get(JsonKey.ACTOR_TYPE)); - reqObj.getContext().put(JsonKey.APP_ID, httpReq.flash().get(JsonKey.APP_ID)); - reqObj.getContext().put(JsonKey.DEVICE_ID, httpReq.flash().get(JsonKey.DEVICE_ID)); - reqObj - .getContext() - .put( - JsonKey.SIGNUP_TYPE, - httpReq.flash().get(JsonKey.SIGNUP_TYPE)); // adding signup type in request context - reqObj - .getContext() - .put( - JsonKey.REQUEST_SOURCE, - httpReq.flash().get(JsonKey.REQUEST_SOURCE)); // ADDING Source under params in context - httpReq.flash().remove(JsonKey.APP_ID); + public void setContextData(Http.Request httpReq, org.sunbird.common.request.Request reqObj) { + try { + String reqContext = httpReq.flash().get(JsonKey.CONTEXT); + Map requestInfo = + objectMapper.readValue(reqContext, new TypeReference>() {}); + reqObj.setRequestId(httpReq.flash().get(JsonKey.REQUEST_ID)); + reqObj.getContext().putAll((Map) requestInfo.get(JsonKey.CONTEXT)); + reqObj.getContext().putAll((Map) requestInfo.get(JsonKey.ADDITIONAL_INFO)); + } catch (Exception ex) { + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); + } } /** @@ -879,16 +821,6 @@ private void setGlobalHealthFlag(Object result) { LoggerEnum.INFO.name()); } - protected String getQueryString(Map queryStringMap) { - return queryStringMap - .entrySet() - .stream() - .map(p -> p.getKey() + "=" + String.join(",", p.getValue())) - .reduce((p1, p2) -> p1 + "&" + p2) - .map(s -> "?" + s) - .orElse(""); - } - public static String getResponseSize(String response) throws UnsupportedEncodingException { if (StringUtils.isNotBlank(response)) { return response.getBytes("UTF-8").length + ""; diff --git a/service/app/controllers/badging/BadgeAssertionController.java b/service/app/controllers/badging/BadgeAssertionController.java index e7a9c02b69..39c1cc56ee 100644 --- a/service/app/controllers/badging/BadgeAssertionController.java +++ b/service/app/controllers/badging/BadgeAssertionController.java @@ -4,20 +4,18 @@ import com.fasterxml.jackson.databind.JsonNode; import controllers.BaseController; import controllers.badging.validator.BadgeAssertionValidator; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import org.sunbird.common.models.util.BadgingActorOperations; import org.sunbird.common.models.util.BadgingJsonKey; import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import play.mvc.BodyParser; import play.mvc.Http; import play.mvc.Result; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; - /** * This controller will handle all api related to badge assertions. issue badge, revoke badge,get * badge instance etc. @@ -43,7 +41,7 @@ public CompletionStage issueBadge(Http.Request httpRequest) { reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgingActorOperations.CREATE_BADGE_ASSERTION.getValue(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); @@ -69,7 +67,7 @@ public CompletionStage getAssertionDetails(String assertionId, Http.Requ reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgingActorOperations.GET_BADGE_ASSERTION.getValue(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); @@ -93,7 +91,7 @@ public CompletionStage getAssertionList(Http.Request httpRequest) { reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgingActorOperations.GET_BADGE_ASSERTION_LIST.getValue(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); @@ -118,7 +116,7 @@ public CompletionStage revokeAssertion(Http.Request httpRequest) { reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgingActorOperations.REVOKE_BADGE.getValue(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); diff --git a/service/app/controllers/badging/BadgeIssuerController.java b/service/app/controllers/badging/BadgeIssuerController.java index 2d6cc1fd92..284b6926b5 100644 --- a/service/app/controllers/badging/BadgeIssuerController.java +++ b/service/app/controllers/badging/BadgeIssuerController.java @@ -19,7 +19,6 @@ import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import org.sunbird.common.responsecode.ResponseCode; import play.libs.Files; @@ -62,7 +61,7 @@ public CompletionStage createBadgeIssuer(Http.Request httpRequest) { reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgeOperations.createBadgeIssuer.name(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); @@ -83,7 +82,7 @@ public CompletionStage getBadgeIssuer(String issuerId, Http.Request http reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgeOperations.getBadgeIssuer.name(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); @@ -106,7 +105,7 @@ public CompletionStage getAllIssuer(Http.Request httpRequest) { reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgeOperations.getAllIssuer.name(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); @@ -127,7 +126,7 @@ public CompletionStage deleteBadgeIssuer(String issuerId, Http.Request h reqObj = setExtraParam( reqObj, - ExecutionContext.getRequestId(), + httpRequest.flash().get(JsonKey.REQUEST_ID), BadgeOperations.deleteIssuer.name(), httpRequest.flash().get(JsonKey.USER_ID), getEnvironment()); diff --git a/service/app/controllers/bulkapimanagement/BaseBulkUploadController.java b/service/app/controllers/bulkapimanagement/BaseBulkUploadController.java index 112c586adf..34c0332680 100644 --- a/service/app/controllers/bulkapimanagement/BaseBulkUploadController.java +++ b/service/app/controllers/bulkapimanagement/BaseBulkUploadController.java @@ -17,14 +17,12 @@ import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.ProjectLogger; import org.sunbird.common.models.util.ProjectUtil; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.responsecode.ResponseCode; import play.libs.Files; import play.mvc.Http; import play.mvc.Http.MultipartFormData; import play.mvc.Http.MultipartFormData.FilePart; - /** * Class to provide common functionality to ulk upload controllers. * @@ -45,7 +43,8 @@ public class BaseBulkUploadController extends BaseController { * instance. */ protected org.sunbird.common.request.Request createAndInitBulkRequest( - String operation, String objectType, Boolean validateFileZize, Http.Request httpRequest) throws IOException { + String operation, String objectType, Boolean validateFileZize, Http.Request httpRequest) + throws IOException { ProjectLogger.log("API call for operation : " + operation); org.sunbird.common.request.Request reqObj = new org.sunbird.common.request.Request(); Map map = new HashMap<>(); @@ -93,7 +92,7 @@ protected org.sunbird.common.request.Request createAndInitBulkRequest( checkFileSize(byteArray, objectType); } reqObj.setOperation(operation); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); map.put(JsonKey.OBJECT_TYPE, objectType); map.put(JsonKey.CREATED_BY, httpRequest.flash().get(JsonKey.USER_ID)); diff --git a/service/app/controllers/clientmanagement/ClientController.java b/service/app/controllers/clientmanagement/ClientController.java index f50fd16c21..978cd51758 100644 --- a/service/app/controllers/clientmanagement/ClientController.java +++ b/service/app/controllers/clientmanagement/ClientController.java @@ -10,7 +10,6 @@ import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.HeaderParam; import org.sunbird.common.request.Request; import org.sunbird.common.request.RequestValidator; @@ -35,7 +34,7 @@ public CompletionStage registerClient(Http.Request httpRequest) { Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); RequestValidator.validateRegisterClient(reqObj); reqObj.setOperation(ActorOperations.REGISTER_CLIENT.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); } catch (Exception e) { @@ -53,12 +52,14 @@ public CompletionStage updateClientKey(Http.Request httpRequest) { try { JsonNode requestData = httpRequest.body().asJson(); ProjectLogger.log("Update client key: " + requestData, LoggerEnum.INFO.name()); - Optional masterKey = httpRequest.getHeaders().get(HeaderParam.X_Authenticated_Client_Token.getName()); - Optional clientId = httpRequest.getHeaders().get(HeaderParam.X_Authenticated_Client_Id.getName()); + Optional masterKey = + httpRequest.getHeaders().get(HeaderParam.X_Authenticated_Client_Token.getName()); + Optional clientId = + httpRequest.getHeaders().get(HeaderParam.X_Authenticated_Client_Id.getName()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); RequestValidator.validateUpdateClientKey(clientId.get(), masterKey.get()); reqObj.setOperation(ActorOperations.UPDATE_CLIENT_KEY.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); HashMap innerMap = (HashMap) reqObj.getRequest(); innerMap.put(JsonKey.CLIENT_ID, clientId); @@ -84,7 +85,7 @@ public CompletionStage getClientKey(String clientId, Http.Request httpRe RequestValidator.validateGetClientKey(clientId, type); Request reqObj = new Request(); reqObj.setOperation(ActorOperations.GET_CLIENT_KEY.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); HashMap innerMap = new HashMap<>(); innerMap.put(JsonKey.CLIENT_ID, clientId); diff --git a/service/app/controllers/datapersistence/DbOperationController.java b/service/app/controllers/datapersistence/DbOperationController.java index a1348785ae..963af3a678 100644 --- a/service/app/controllers/datapersistence/DbOperationController.java +++ b/service/app/controllers/datapersistence/DbOperationController.java @@ -2,18 +2,16 @@ import com.fasterxml.jackson.databind.JsonNode; import controllers.BaseController; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import org.sunbird.common.models.util.ActorOperations; import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import play.mvc.Http; import play.mvc.Result; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; - public class DbOperationController extends BaseController { /** @@ -27,7 +25,7 @@ public CompletionStage create(Http.Request httpRequest) { ProjectLogger.log("DbOperationController: create called", LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.CREATE_DATA.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -47,7 +45,7 @@ public CompletionStage update(Http.Request httpRequest) { ProjectLogger.log("DbOperationController: update called", LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.UPDATE_DATA.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -67,7 +65,7 @@ public CompletionStage delete(Http.Request httpRequest) { ProjectLogger.log("DbOperationController: delete called", LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.DELETE_DATA.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -87,7 +85,7 @@ public CompletionStage read(Http.Request httpRequest) { ProjectLogger.log("DbOperationController: read called", LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.READ_DATA.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -107,7 +105,7 @@ public CompletionStage readAll(Http.Request httpRequest) { ProjectLogger.log("DbOperationController: readAll called", LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.READ_ALL_DATA.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -127,7 +125,7 @@ public CompletionStage search(Http.Request httpRequest) { ProjectLogger.log("DbOperationController: search called", LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.SEARCH_DATA.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -147,7 +145,7 @@ public CompletionStage getMetrics(Http.Request httpRequest) { ProjectLogger.log("DbOperationController: getMetrics called", LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.GET_METRICS.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); diff --git a/service/app/controllers/geolocation/GeoLocationController.java b/service/app/controllers/geolocation/GeoLocationController.java index 78664bf5f9..1f75d2ad9d 100644 --- a/service/app/controllers/geolocation/GeoLocationController.java +++ b/service/app/controllers/geolocation/GeoLocationController.java @@ -10,7 +10,6 @@ import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import org.sunbird.common.request.RequestValidator; import play.mvc.Http; @@ -25,7 +24,7 @@ public CompletionStage createGeoLocation(Http.Request httpRequest) { ProjectLogger.log("create geo location" + requestData, LoggerEnum.DEBUG.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.CREATE_GEO_LOCATION.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); @@ -42,7 +41,7 @@ public CompletionStage getGeoLocation(String id, Http.Request httpReques String type = httpRequest.getQueryString(JsonKey.TYPE); Request reqObj = new Request(); reqObj.setOperation(ActorOperations.GET_GEO_LOCATION.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); @@ -61,7 +60,7 @@ public CompletionStage updateGeoLocation(String locationId, Http.Request ProjectLogger.log("update geo location" + requestData, LoggerEnum.INFO.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.UPDATE_GEO_LOCATION.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); @@ -78,7 +77,7 @@ public CompletionStage deleteGeoLocation(String locationId, Http.Request ProjectLogger.log("delete geo location"); Request reqObj = new Request(); reqObj.setOperation(ActorOperations.DELETE_GEO_LOCATION.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = new HashMap<>(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); @@ -97,7 +96,7 @@ public CompletionStage sendNotification(Http.Request httpRequest) { Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); RequestValidator.validateSendNotification(reqObj); reqObj.setOperation(ActorOperations.SEND_NOTIFICATION.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); @@ -115,7 +114,7 @@ public CompletionStage getUserCount(Http.Request httpRequest) { Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); RequestValidator.validateGetUserCount(reqObj); reqObj.setOperation(ActorOperations.GET_USER_COUNT.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); diff --git a/service/app/controllers/healthmanager/HealthController.java b/service/app/controllers/healthmanager/HealthController.java index 836b1eab6e..a854b4d7af 100644 --- a/service/app/controllers/healthmanager/HealthController.java +++ b/service/app/controllers/healthmanager/HealthController.java @@ -13,14 +13,7 @@ import org.apache.commons.lang3.StringUtils; import org.sunbird.common.exception.ProjectCommonException; import org.sunbird.common.models.response.Response; -import org.sunbird.common.models.util.ActorOperations; -import org.sunbird.common.models.util.HttpUtil; -import org.sunbird.common.models.util.JsonKey; -import org.sunbird.common.models.util.LoggerEnum; -import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.models.util.ProjectUtil; -import org.sunbird.common.models.util.PropertiesCache; -import org.sunbird.common.request.ExecutionContext; +import org.sunbird.common.models.util.*; import org.sunbird.common.request.Request; import org.sunbird.common.responsecode.ResponseCode; import play.mvc.Http; @@ -49,7 +42,7 @@ public CompletionStage getHealth(Http.Request httpRequest) { handleSigTerm(); Request reqObj = new Request(); reqObj.setOperation(ActorOperations.HEALTH_CHECK.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.CREATED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -75,7 +68,7 @@ public CompletionStage getLearnerServiceHealth(String val, Http.Request handleSigTerm(); Request reqObj = new Request(); reqObj.setOperation(val); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.CREATED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -94,7 +87,7 @@ public CompletionStage getLearnerServiceHealth(String val, Http.Request response.getResult().put(JsonKey.RESPONSE, finalResponseMap); response.setId("learner.service.health.api"); response.setVer(getApiVersion(httpRequest.path())); - response.setTs(ExecutionContext.getRequestId()); + response.setTs(httpRequest.flash().get(JsonKey.REQUEST_ID)); return CompletableFuture.completedFuture(ok(play.libs.Json.toJson(response))); } catch (Exception e) { return CompletableFuture.completedFuture(createCommonExceptionResponse(e, httpRequest)); @@ -154,8 +147,7 @@ public CompletionStage getEkStepHealtCheck(play.mvc.Http.Request request response.getResult().put(JsonKey.RESPONSE, finalResponseMap); response.setId("Ekstep.service.health.api"); response.setVer(getApiVersion(request.path())); - response.setTs(ExecutionContext.getRequestId()); + response.setTs(request.flash().get(JsonKey.REQUEST_ID)); return CompletableFuture.completedFuture(ok(play.libs.Json.toJson(response))); } - } diff --git a/service/app/controllers/metrics/OrganisationMetricsController.java b/service/app/controllers/metrics/OrganisationMetricsController.java index 903f63b137..60bb751166 100644 --- a/service/app/controllers/metrics/OrganisationMetricsController.java +++ b/service/app/controllers/metrics/OrganisationMetricsController.java @@ -8,7 +8,6 @@ import org.sunbird.common.models.util.ActorOperations; import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import play.mvc.Http; import play.mvc.Result; @@ -27,7 +26,7 @@ public CompletionStage orgCreation(String orgId, Http.Request httpReques request.setRequest(map); request.setOperation(ActorOperations.ORG_CREATION_METRICS.getValue()); request.setRequest(map); - request.setRequestId(ExecutionContext.getRequestId()); + request.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); ProjectLogger.log("Return from Org Metrics Creation Contoller"); return actorResponseHandler(getActorRef(), request, timeout, null, httpRequest); } catch (Exception e) { @@ -47,7 +46,7 @@ public CompletionStage orgConsumption(String orgId, Http.Request httpReq request.setRequest(map); request.setOperation(ActorOperations.ORG_CONSUMPTION_METRICS.getValue()); request.setRequest(map); - request.setRequestId(ExecutionContext.getRequestId()); + request.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); ProjectLogger.log("Return from Org Metrics Consumption Contoller"); return actorResponseHandler(getActorRef(), request, timeout, null, httpRequest); } catch (Exception e) { @@ -69,7 +68,7 @@ public CompletionStage orgCreationReport(String orgId, Http.Request http request.setEnv(getEnvironment()); request.setOperation(ActorOperations.ORG_CREATION_METRICS_REPORT.getValue()); request.setRequest(map); - request.setRequestId(ExecutionContext.getRequestId()); + request.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); ProjectLogger.log("Return from Org Creation Report Contoller"); return actorResponseHandler(getActorRef(), request, timeout, null, httpRequest); } catch (Exception e) { @@ -91,7 +90,7 @@ public CompletionStage orgConsumptionReport(String orgId, Http.Request h request.setEnv(getEnvironment()); request.setOperation(ActorOperations.ORG_CONSUMPTION_METRICS_REPORT.getValue()); request.setRequest(map); - request.setRequestId(ExecutionContext.getRequestId()); + request.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); ProjectLogger.log("Return from Org Consumption Report Contoller"); return actorResponseHandler(getActorRef(), request, timeout, null, httpRequest); } catch (Exception e) { diff --git a/service/app/controllers/metrics/UserMetricsController.java b/service/app/controllers/metrics/UserMetricsController.java index a5cc9608b1..b5d0b86538 100644 --- a/service/app/controllers/metrics/UserMetricsController.java +++ b/service/app/controllers/metrics/UserMetricsController.java @@ -6,7 +6,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import org.sunbird.common.models.util.ActorOperations; -import org.sunbird.common.request.ExecutionContext; +import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.request.Request; import play.mvc.Http; import play.mvc.Result; @@ -21,7 +21,7 @@ public CompletionStage userCreation(String userId, Http.Request httpRequ request.setRequest(map); request.setOperation(ActorOperations.USER_CREATION_METRICS.getValue()); request.setRequest(map); - request.setRequestId(ExecutionContext.getRequestId()); + request.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); return actorResponseHandler(getActorRef(), request, timeout, null, httpRequest); } catch (Exception e) { return CompletableFuture.completedFuture(createCommonExceptionResponse(e, httpRequest)); @@ -36,7 +36,7 @@ public CompletionStage userConsumption(String userId, Http.Request httpR request.setRequest(map); request.setOperation(ActorOperations.USER_CONSUMPTION_METRICS.getValue()); request.setRequest(map); - request.setRequestId(ExecutionContext.getRequestId()); + request.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); return actorResponseHandler(getActorRef(), request, timeout, null, httpRequest); } catch (Exception e) { return CompletableFuture.completedFuture(createCommonExceptionResponse(e, httpRequest)); diff --git a/service/app/controllers/notificationservice/EmailServiceController.java b/service/app/controllers/notificationservice/EmailServiceController.java index 53a1b6efea..241a580f55 100644 --- a/service/app/controllers/notificationservice/EmailServiceController.java +++ b/service/app/controllers/notificationservice/EmailServiceController.java @@ -1,6 +1,7 @@ package controllers.notificationservice; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import controllers.BaseController; import java.util.HashMap; import java.util.concurrent.CompletableFuture; @@ -9,7 +10,6 @@ import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import org.sunbird.common.request.RequestValidator; import play.mvc.Http; @@ -17,6 +17,8 @@ public class EmailServiceController extends BaseController { + private ObjectMapper omapper = new ObjectMapper(); + /** * This method will add a new course entry into cassandra DB. * @@ -30,14 +32,25 @@ public CompletionStage sendMail(Http.Request httpRequest) { Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); RequestValidator.validateSendMail(reqObj); reqObj.setOperation(ActorOperations.EMAIL_SERVICE.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); HashMap innerMap = new HashMap<>(); innerMap.put(JsonKey.EMAIL_REQUEST, reqObj.getRequest()); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setRequest(innerMap); - return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); + JsonNode reqObjJson = omapper.convertValue(reqObj, JsonNode.class); + return handleRequest( + ActorOperations.EMAIL_SERVICE.getValue(), + reqObjJson, + req -> { + // We have validated earlier. + return null; + }, + null, + null, + true, + httpRequest); } catch (Exception e) { return CompletableFuture.completedFuture(createCommonExceptionResponse(e, httpRequest)); } diff --git a/service/app/controllers/otp/validator/OtpRequestValidator.java b/service/app/controllers/otp/validator/OtpRequestValidator.java index 66b6b9fd0e..3a2475d156 100644 --- a/service/app/controllers/otp/validator/OtpRequestValidator.java +++ b/service/app/controllers/otp/validator/OtpRequestValidator.java @@ -24,7 +24,7 @@ public void validateGenerateOtpRequest(Request otpRequest) { private void validateTemplateId(Request otpRequest) { String templateId = (String) otpRequest.getRequest().get(JsonKey.TEMPLATE_ID); - if(StringUtils.isNotBlank(templateId) && !templateId.equalsIgnoreCase(JsonKey.TEMPLATE_ID_VALUE)) { + if(StringUtils.isNotBlank(templateId) && !templateId.equalsIgnoreCase(JsonKey.TEMPLATE_ID_VALUE) && !templateId.equalsIgnoreCase(JsonKey.WARD_LOGIN_OTP_TEMPLATE_ID)) { throw new ProjectCommonException( ResponseCode.invalidIdentifier.getErrorCode(), ProjectUtil.formatMessage( diff --git a/service/app/controllers/search/SearchController.java b/service/app/controllers/search/SearchController.java index 2f5da9effc..1d8302e7f8 100644 --- a/service/app/controllers/search/SearchController.java +++ b/service/app/controllers/search/SearchController.java @@ -10,13 +10,11 @@ import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import org.sunbird.common.request.RequestValidator; import play.mvc.Http; import play.mvc.Result; - /** * This controller will handle all the request related user and organization search. * @@ -37,7 +35,7 @@ public CompletionStage compositeSearch(Http.Request httpRequest) { ProjectLogger.log("getting search request data = " + requestData, LoggerEnum.INFO.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.COMPOSITE_SEARCH.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.CREATED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); @@ -60,7 +58,7 @@ public CompletionStage sync(Http.Request httpRequest) { String operation = (String) reqObj.getRequest().get(JsonKey.OPERATION_FOR); if ("keycloak".equalsIgnoreCase(operation)) { reqObj.setOperation(ActorOperations.SYNC_KEYCLOAK.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.CREATED_BY, httpRequest.flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); HashMap map = new HashMap<>(); @@ -69,7 +67,7 @@ public CompletionStage sync(Http.Request httpRequest) { return actorResponseHandler(getActorRef(), reqObj, timeout, null, httpRequest); } else { reqObj.setOperation(ActorOperations.SYNC.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.getRequest().put(JsonKey.CREATED_BY, ctx().flash().get(JsonKey.USER_ID)); reqObj.setEnv(getEnvironment()); HashMap map = new HashMap<>(); diff --git a/service/app/controllers/storage/FileStorageController.java b/service/app/controllers/storage/FileStorageController.java index db80becce4..1fda78bf63 100644 --- a/service/app/controllers/storage/FileStorageController.java +++ b/service/app/controllers/storage/FileStorageController.java @@ -17,7 +17,6 @@ import org.sunbird.common.exception.ProjectCommonException; import org.sunbird.common.models.util.ActorOperations; import org.sunbird.common.models.util.JsonKey; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import org.sunbird.common.responsecode.ResponseCode; import play.libs.Files; @@ -84,7 +83,7 @@ public CompletionStage uploadFileService(Http.Request httpRequest) { return CompletableFuture.completedFuture(createCommonExceptionResponse(e, httpRequest)); } reqObj.setOperation(ActorOperations.FILE_STORAGE_SERVICE.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); HashMap innerMap = new HashMap<>(); innerMap.put(JsonKey.DATA, map); diff --git a/service/app/controllers/tac/validator/UserTnCRequestValidator.java b/service/app/controllers/tac/validator/UserTnCRequestValidator.java index 649cfc5b07..164097b21e 100644 --- a/service/app/controllers/tac/validator/UserTnCRequestValidator.java +++ b/service/app/controllers/tac/validator/UserTnCRequestValidator.java @@ -1,10 +1,15 @@ package controllers.tac.validator; +import org.apache.commons.lang3.StringUtils; +import org.sunbird.common.exception.ProjectCommonException; import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectUtil; import org.sunbird.common.request.BaseRequestValidator; import org.sunbird.common.request.Request; import org.sunbird.common.responsecode.ResponseCode; +import java.text.MessageFormat; + public class UserTnCRequestValidator extends BaseRequestValidator { public void validateTnCRequest(Request request) { @@ -12,5 +17,14 @@ public void validateTnCRequest(Request request) { (String) request.get(JsonKey.VERSION), ResponseCode.mandatoryParamsMissing, JsonKey.VERSION); + + //if managedUserId's terms and conditions are accepted, validate userId from request + String managedUserId = (String) request.getRequest().get(JsonKey.USER_ID); + if (StringUtils.isNotBlank(managedUserId) && !ProjectUtil.validateUUID(managedUserId)){ + throw new ProjectCommonException( + ResponseCode.invalidPropertyError.getErrorCode(), + MessageFormat.format(ResponseCode.invalidPropertyError.getErrorMessage(), JsonKey.USER_ID), + ResponseCode.CLIENT_ERROR.getResponseCode()); + } } } diff --git a/service/app/controllers/tenantpreference/TenantPreferenceController.java b/service/app/controllers/tenantpreference/TenantPreferenceController.java index 98add91d3d..452a17fc4b 100644 --- a/service/app/controllers/tenantpreference/TenantPreferenceController.java +++ b/service/app/controllers/tenantpreference/TenantPreferenceController.java @@ -9,12 +9,10 @@ import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.Request; import play.mvc.Http; import play.mvc.Result; - /** Created by arvind on 27/10/17. */ public class TenantPreferenceController extends BaseController { @@ -24,7 +22,7 @@ public CompletionStage createTenantPreference(Http.Request httpRequest) ProjectLogger.log("Create tenant preferences: " + requestData, LoggerEnum.INFO.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.CREATE_TENANT_PREFERENCE.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); @@ -41,7 +39,7 @@ public CompletionStage updateTenantPreference(Http.Request httpRequest) ProjectLogger.log("Update tenant preferences: " + requestData, LoggerEnum.INFO.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.UPDATE_TENANT_PREFERENCE.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); @@ -58,7 +56,7 @@ public CompletionStage getTenantPreference(Http.Request httpRequest) { ProjectLogger.log("Get tenant preferences: " + requestData, LoggerEnum.INFO.name()); Request reqObj = (Request) mapper.RequestMapper.mapRequest(requestData, Request.class); reqObj.setOperation(ActorOperations.GET_TENANT_PREFERENCE.getValue()); - reqObj.setRequestId(ExecutionContext.getRequestId()); + reqObj.setRequestId(httpRequest.flash().get(JsonKey.REQUEST_ID)); reqObj.setEnv(getEnvironment()); Map innerMap = reqObj.getRequest(); innerMap.put(JsonKey.REQUESTED_BY, httpRequest.flash().get(JsonKey.USER_ID)); diff --git a/service/app/controllers/usermanagement/UserController.java b/service/app/controllers/usermanagement/UserController.java index 4004b97075..42df0294f3 100644 --- a/service/app/controllers/usermanagement/UserController.java +++ b/service/app/controllers/usermanagement/UserController.java @@ -77,6 +77,21 @@ public CompletionStage createUserV3(Http.Request httpRequest) { httpRequest); } + public CompletionStage createUserV4(Http.Request httpRequest) { + return handleRequest( + ActorOperations.CREATE_USER_V4.getValue(), + httpRequest.body().asJson(), + req -> { + Request request = (Request) req; + new UserRequestValidator().validateUserCreateV4(request); + request.getContext().put(JsonKey.VERSION, JsonKey.VERSION_4); + return null; + }, + null, + null, + true, + httpRequest); + } public CompletionStage updateUser(Http.Request httpRequest) { final boolean isPrivate; @@ -175,6 +190,7 @@ private CompletionStage handleGetUserProfile(String operation, String us final String requestedFields = httpRequest.getQueryString(JsonKey.FIELDS); final String provider = httpRequest.getQueryString(JsonKey.PROVIDER); final String idType = httpRequest.getQueryString(JsonKey.ID_TYPE); + final String withTokens = httpRequest.getQueryString(JsonKey.WITH_TOKENS); userId = ProjectUtil.getLmsUserId(userId); return handleRequest( operation, @@ -185,6 +201,7 @@ private CompletionStage handleGetUserProfile(String operation, String us request.getContext().put(JsonKey.PROVIDER, provider); request.getContext().put(JsonKey.ID_TYPE, idType); request.getContext().put(JsonKey.PRIVATE, isPrivate); + request.getContext().put(JsonKey.WITH_TOKENS, withTokens); return null; }, userId, @@ -214,4 +231,26 @@ public CompletionStage isUserValid(String key, String value, Http.Reques false, httpRequest); } + + public CompletionStage getManagedUsers(String luaUuid, Http.Request httpRequest) { + HashMap map = new HashMap<>(); + map.put(JsonKey.ID, luaUuid); + String withTokens = httpRequest.getQueryString(JsonKey.WITH_TOKENS); + map.put(JsonKey.WITH_TOKENS, withTokens); + map.put(JsonKey.SORTBY, httpRequest.getQueryString(JsonKey.SORTBY)); //createdDate + map.put(JsonKey.ORDER, httpRequest.getQueryString(JsonKey.ORDER)); //desc + return handleRequest( + ActorOperations.GET_MANAGED_USERS.getValue(), + null, + req -> { + Request request = (Request) req; + request.setRequest(map); + new UserRequestValidator().validateUserId(luaUuid); + return null; + }, + null, + null, + false, + httpRequest); + } } diff --git a/service/app/filters/AccessLogFilter.java b/service/app/filters/AccessLogFilter.java new file mode 100644 index 0000000000..40c101eace --- /dev/null +++ b/service/app/filters/AccessLogFilter.java @@ -0,0 +1,80 @@ +package filters; + +import akka.util.ByteString; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.Executor; +import javax.inject.Inject; +import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.telemetry.util.TelemetryEvents; +import org.sunbird.telemetry.util.TelemetryWriter; +import play.libs.streams.Accumulator; +import play.mvc.EssentialAction; +import play.mvc.EssentialFilter; +import play.mvc.Result; + +public class AccessLogFilter extends EssentialFilter { + + private final Executor executor; + private ObjectMapper objectMapper = new ObjectMapper(); + + @Inject + public AccessLogFilter(Executor executor) { + super(); + this.executor = executor; + } + + @Override + public EssentialAction apply(EssentialAction next) { + return EssentialAction.of( + request -> { + long startTime = System.currentTimeMillis(); + Accumulator accumulator = next.apply(request); + return accumulator.map( + result -> { + long endTime = System.currentTimeMillis(); + long requestTime = endTime - startTime; + try { + org.sunbird.common.request.Request req = new org.sunbird.common.request.Request(); + Map params = new WeakHashMap<>(); + params.put(JsonKey.URL, request.uri()); + params.put(JsonKey.METHOD, request.method()); + params.put(JsonKey.LOG_TYPE, JsonKey.API_ACCESS); + params.put(JsonKey.MESSAGE, ""); + params.put(JsonKey.METHOD, request.method()); + params.put(JsonKey.DURATION, requestTime); + params.put(JsonKey.STATUS, result.status()); + params.put(JsonKey.LOG_LEVEL, JsonKey.INFO); + String contextDetails = request.flash().get(JsonKey.CONTEXT); + Map context = + objectMapper.readValue( + contextDetails, new TypeReference>() {}); + req.setRequest( + generateTelemetryRequestForController( + TelemetryEvents.LOG.getName(), + params, + (Map) context.get(JsonKey.CONTEXT))); + TelemetryWriter.write(req); + } catch (Exception ex) { + ProjectLogger.log("AccessLogFilter:apply Exception in writing telemetry", ex); + } + return result; + }, + executor); + }); + } + + private Map generateTelemetryRequestForController( + String eventType, Map params, Map context) { + + Map map = new HashMap<>(); + map.put(JsonKey.TELEMETRY_EVENT_TYPE, eventType); + map.put(JsonKey.CONTEXT, context); + map.put(JsonKey.PARAMS, params); + return map; + } +} diff --git a/service/app/filters/LoggingFilter.java b/service/app/filters/LoggingFilter.java deleted file mode 100644 index 554087fdcb..0000000000 --- a/service/app/filters/LoggingFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -package filters; - -import akka.stream.Materializer; -import play.Logger; -import play.mvc.Filter; -import play.mvc.Http; -import play.mvc.Result; - -import javax.inject.Inject; -import java.util.concurrent.CompletionStage; -import java.util.function.Function; - -public class LoggingFilter extends Filter { - - @Inject - public LoggingFilter(Materializer mat) { - super(mat); - } - - @Override - public CompletionStage apply( - Function> nextFilter, - Http.RequestHeader requestHeader) { - long startTime = System.currentTimeMillis(); - return nextFilter - .apply(requestHeader) - .thenApply( - result -> { - long endTime = System.currentTimeMillis(); - long requestTime = endTime - startTime; - - Logger.info( - "{} {} took {}ms and returned {}", - requestHeader.method(), - requestHeader.uri(), - requestTime, - result.status()); - - return result.withHeader("Request-Time", "" + requestTime); - }); - } -} \ No newline at end of file diff --git a/service/app/modules/ApplicationStart.java b/service/app/modules/ApplicationStart.java index 439bd72cbf..e22472efc0 100644 --- a/service/app/modules/ApplicationStart.java +++ b/service/app/modules/ApplicationStart.java @@ -1,7 +1,10 @@ package modules; - +import java.util.concurrent.CompletableFuture; +import javax.inject.Inject; +import javax.inject.Singleton; import org.sunbird.actor.service.SunbirdMWService; +import org.sunbird.auth.verifier.KeyManager; import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; @@ -11,10 +14,6 @@ import play.api.Environment; import play.api.inject.ApplicationLifecycle; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.concurrent.CompletableFuture; - @Singleton public class ApplicationStart { public static ProjectUtil.Environment env; @@ -28,30 +27,27 @@ public ApplicationStart(ApplicationLifecycle applicationLifecycle, Environment e ProjectLogger.log("Server started.. with environment: " + env.name(), LoggerEnum.INFO.name()); SunbirdMWService.init(); checkCassandraConnections(); - applicationLifecycle.addStopHook( - () -> { - return CompletableFuture.completedFuture(null); } - ); + applicationLifecycle.addStopHook( + () -> { + return CompletableFuture.completedFuture(null); + }); + KeyManager.init(); ProjectLogger.log("ApplicationStart:ApplicationStart: End", LoggerEnum.DEBUG.name()); } private void setEnvironment(Environment environment) { - if(environment.asJava().isDev()) { + if (environment.asJava().isDev()) { env = ProjectUtil.Environment.dev; - } else if(environment.asJava().isTest()) { + } else if (environment.asJava().isTest()) { env = ProjectUtil.Environment.qa; } else { env = ProjectUtil.Environment.prod; } - } private static void checkCassandraConnections() { - - Util.checkCassandraDbConnections(JsonKey.SUNBIRD); - Util.checkCassandraDbConnections(JsonKey.SUNBIRD_PLUGIN); + Util.checkCassandraDbConnections(); SchedulerManager.schedule(); - // Run quartz scheduler in a separate thread as it waits for 4 minutes // before scheduling various jobs. new Thread(() -> org.sunbird.common.quartz.scheduler.SchedulerManager.getInstance()).start(); diff --git a/service/app/modules/OnRequestHandler.java b/service/app/modules/OnRequestHandler.java index 4dffb08605..dc5d4c6d97 100644 --- a/service/app/modules/OnRequestHandler.java +++ b/service/app/modules/OnRequestHandler.java @@ -1,24 +1,24 @@ package modules; - import akka.actor.ActorRef; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import controllers.BaseController; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.sunbird.actor.router.RequestRouter; import org.sunbird.actorutil.org.OrganisationClient; import org.sunbird.actorutil.org.impl.OrganisationClientImpl; -import org.sunbird.actorutil.systemsettings.SystemSettingClient; -import org.sunbird.actorutil.systemsettings.impl.SystemSettingClientImpl; import org.sunbird.common.exception.ProjectCommonException; import org.sunbird.common.models.response.Response; import org.sunbird.common.models.util.*; -import org.sunbird.common.request.ExecutionContext; import org.sunbird.common.request.HeaderParam; import org.sunbird.common.responsecode.ResponseCode; -import org.sunbird.models.systemsetting.SystemSetting; -import org.sunbird.telemetry.util.TelemetryUtil; +import org.sunbird.learner.util.DataCacheHandler; import play.http.ActionCreator; import play.libs.Json; import play.mvc.Action; @@ -27,44 +27,33 @@ import play.mvc.Results; import util.RequestInterceptor; -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ConcurrentHashMap; - public class OnRequestHandler implements ActionCreator { + private ObjectMapper mapper = new ObjectMapper(); private static String custodianOrgHashTagId; public static boolean isServiceHealthy = true; - private final List USER_UNAUTH_STATES = - Arrays.asList(JsonKey.UNAUTHORIZED, JsonKey.ANONYMOUS); - public static Map> requestInfo = new ConcurrentHashMap<>(); @Override public Action createAction(Http.Request request, Method method) { Optional optionalMessageId = request.header(JsonKey.MESSAGE_ID); - String messageId; - if(optionalMessageId.isPresent()) { - messageId = optionalMessageId.get(); + String requestId; + if (optionalMessageId.isPresent()) { + requestId = optionalMessageId.get(); } else { UUID uuid = UUID.randomUUID(); - messageId = uuid.toString(); + requestId = uuid.toString(); } - ExecutionContext.setRequestId(messageId); return new Action.Simple() { @Override public CompletionStage call(Http.Request request) { request.getHeaders(); CompletionStage result = checkForServiceHealth(request); if (result != null) return result; - //ctx.response().setHeader("Access-Control-Allow-Origin", "*"); - - // Unauthorized, Anonymous, UserID + //From 3.0.0 checking user access-token and managed-by from the request header String message = RequestInterceptor.verifyRequestData(request); // call method to set all the required params for the telemetry event(log)... - intializeRequestInfo(request, message); - if (!USER_UNAUTH_STATES.contains(message)) { + initializeRequestInfo(request, message, requestId); + if (!JsonKey.USER_UNAUTH_STATES.contains(message)) { request.flash().put(JsonKey.USER_ID, message); request.flash().put(JsonKey.IS_AUTH_REQ, "false"); for (String uri : RequestInterceptor.restrictedUriList) { @@ -73,10 +62,10 @@ public CompletionStage call(Http.Request request) { break; } } - result = delegate.call(request); + result = delegate.call(request); } else if (JsonKey.UNAUTHORIZED.equals(message)) { result = - onDataValidationError(request, message, ResponseCode.UNAUTHORIZED.getResponseCode()); + onDataValidationError(request, message, ResponseCode.UNAUTHORIZED.getResponseCode()); } else { result = delegate.call(request); } @@ -87,12 +76,12 @@ public CompletionStage call(Http.Request request) { public CompletionStage checkForServiceHealth(Http.Request request) { if (Boolean.parseBoolean((ProjectUtil.getConfigValue(JsonKey.SUNBIRD_HEALTH_CHECK_ENABLE))) - && !request.path().endsWith(JsonKey.HEALTH)) { + && !request.path().endsWith(JsonKey.HEALTH)) { if (!isServiceHealthy) { ResponseCode headerCode = ResponseCode.SERVICE_UNAVAILABLE; Response resp = BaseController.createFailureResponse(request, headerCode, headerCode); return CompletableFuture.completedFuture( - Results.status(ResponseCode.SERVICE_UNAVAILABLE.getResponseCode(), Json.toJson(resp))); + Results.status(ResponseCode.SERVICE_UNAVAILABLE.getResponseCode(), Json.toJson(resp))); } } return null; @@ -107,7 +96,7 @@ public CompletionStage checkForServiceHealth(Http.Request request) { * @return CompletionStage */ public CompletionStage onDataValidationError( - Http.Request request, String errorMessage, int responseCode) { + Http.Request request, String errorMessage, int responseCode) { ProjectLogger.log("Data error found--" + errorMessage); ResponseCode code = ResponseCode.getResponse(errorMessage); ResponseCode headerCode = ResponseCode.CLIENT_ERROR; @@ -115,115 +104,93 @@ public CompletionStage onDataValidationError( return CompletableFuture.completedFuture(Results.status(responseCode, Json.toJson(resp))); } - public void intializeRequestInfo(Http.Request request, String userId) { - - String actionMethod = request.method(); - String messageId = ExecutionContext.getRequestId(); // request.getHeader(JsonKey.MESSAGE_ID); - String url = request.uri(); - String methodName = actionMethod; - long startTime = System.currentTimeMillis(); - String signType = ""; - String source = ""; - if (request.body() != null && request.body().asJson() != null) { - JsonNode requestNode = - request.body().asJson().get("params"); // extracting signup type from request - if (requestNode != null && requestNode.get(JsonKey.SIGNUP_TYPE) != null) { - signType = requestNode.get(JsonKey.SIGNUP_TYPE).asText(); + public void initializeRequestInfo(Http.Request request, String userId, String requestId) { + try { + String actionMethod = request.method(); + String url = request.uri(); + String methodName = actionMethod; + long startTime = System.currentTimeMillis(); + String signType = ""; + String source = ""; + if (request.body() != null && request.body().asJson() != null) { + JsonNode requestNode = + request.body().asJson().get("params"); // extracting signup type from request + if (requestNode != null && requestNode.get(JsonKey.SIGNUP_TYPE) != null) { + signType = requestNode.get(JsonKey.SIGNUP_TYPE).asText(); + } + if (requestNode != null && requestNode.get(JsonKey.REQUEST_SOURCE) != null) { + source = requestNode.get(JsonKey.REQUEST_SOURCE).asText(); + } } - if (requestNode != null && requestNode.get(JsonKey.REQUEST_SOURCE) != null) { - source = requestNode.get(JsonKey.REQUEST_SOURCE).asText(); + Map reqContext = new WeakHashMap<>(); + reqContext.put(JsonKey.SIGNUP_TYPE, signType); + reqContext.put(JsonKey.REQUEST_SOURCE, source); + Optional optionalChannel = request.header(HeaderParam.CHANNEL_ID.getName()); + String channel; + if (optionalChannel.isPresent()) { + channel = optionalChannel.get(); + } else { + String custodianOrgHashTagid = getCustodianOrgHashTagId(); + channel = + (StringUtils.isNotEmpty(custodianOrgHashTagid)) + ? custodianOrgHashTagid + : JsonKey.DEFAULT_ROOT_ORG_ID; } - } - request.flash().put(JsonKey.SIGNUP_TYPE, signType); - request.flash().put(JsonKey.REQUEST_SOURCE, source); - ExecutionContext context = ExecutionContext.getCurrent(); - Map reqContext = new HashMap<>(); - // set env and channel to the - Optional optionalChannel = request.header(HeaderParam.CHANNEL_ID.getName()); - String channel; - if (optionalChannel.isPresent()) { - channel = optionalChannel.get(); - } else { - String custodianOrgHashTagid = getCustodianOrgHashTagId(); - channel = - (StringUtils.isNotEmpty(custodianOrgHashTagid)) - ? custodianOrgHashTagid - : JsonKey.DEFAULT_ROOT_ORG_ID; - } - reqContext.put(JsonKey.CHANNEL, channel); - request.flash().put(JsonKey.CHANNEL, channel); - reqContext.put(JsonKey.ENV, getEnv(request)); - reqContext.put(JsonKey.REQUEST_ID, ExecutionContext.getRequestId()); - Optional optionalAppId = request.header(HeaderParam.X_APP_ID.getName()); - // check if in request header X-app-id is coming then that need to - // be pass in search telemetry. - if (optionalAppId.isPresent()) { - request.flash().put(JsonKey.APP_ID, optionalAppId.get()); - reqContext.put(JsonKey.APP_ID, optionalAppId.get()); - } - // checking device id in headers - Optional optionalDeviceId = request.header(HeaderParam.X_Device_ID.getName()); - if (optionalDeviceId.isPresent()) { - request.flash().put(JsonKey.DEVICE_ID, optionalDeviceId.get()); - reqContext.put(JsonKey.DEVICE_ID, optionalDeviceId.get()); - } - if (!USER_UNAUTH_STATES.contains(userId)) { - reqContext.put(JsonKey.ACTOR_ID, userId); - reqContext.put(JsonKey.ACTOR_TYPE, StringUtils.capitalize(JsonKey.USER)); - request.flash().put(JsonKey.ACTOR_ID, userId); - request.flash().put(JsonKey.ACTOR_TYPE, JsonKey.USER); - } else { - Optional optionalConsumerId = request.header(HeaderParam.X_Consumer_ID.getName()); - String consumerId; - if (optionalConsumerId.isPresent()) { - consumerId = optionalConsumerId.get(); + reqContext.put(JsonKey.CHANNEL, channel); + reqContext.put(JsonKey.ENV, getEnv(request)); + reqContext.put(JsonKey.REQUEST_ID, requestId); + reqContext.putAll(DataCacheHandler.getTelemetryPdata()); + Optional optionalAppId = request.header(HeaderParam.X_APP_ID.getName()); + if (optionalAppId.isPresent()) { + reqContext.put(JsonKey.APP_ID, optionalAppId.get()); + } + Optional optionalDeviceId = request.header(HeaderParam.X_Device_ID.getName()); + if (optionalDeviceId.isPresent()) { + reqContext.put(JsonKey.DEVICE_ID, optionalDeviceId.get()); + } + if (!JsonKey.USER_UNAUTH_STATES.contains(userId)) { + reqContext.put(JsonKey.ACTOR_ID, userId); + reqContext.put(JsonKey.ACTOR_TYPE, StringUtils.capitalize(JsonKey.USER)); } else { - consumerId = JsonKey.DEFAULT_CONSUMER_ID; + Optional optionalConsumerId = request.header(HeaderParam.X_Consumer_ID.getName()); + String consumerId; + if (optionalConsumerId.isPresent()) { + consumerId = optionalConsumerId.get(); + } else { + consumerId = JsonKey.DEFAULT_CONSUMER_ID; + } + reqContext.put(JsonKey.ACTOR_ID, consumerId); + reqContext.put(JsonKey.ACTOR_TYPE, StringUtils.capitalize(JsonKey.CONSUMER)); } - reqContext.put(JsonKey.ACTOR_ID, consumerId); - reqContext.put(JsonKey.ACTOR_TYPE, StringUtils.capitalize(JsonKey.CONSUMER)); - request.flash().put(JsonKey.ACTOR_ID, consumerId); - request.flash().put(JsonKey.ACTOR_TYPE, JsonKey.CONSUMER); - } - context.setRequestContext(reqContext); - Map map = new ConcurrentHashMap<>(); - map.put(JsonKey.CONTEXT, TelemetryUtil.getTelemetryContext()); - Map additionalInfo = new HashMap<>(); - additionalInfo.put(JsonKey.URL, url); - additionalInfo.put(JsonKey.METHOD, methodName); - additionalInfo.put(JsonKey.START_TIME, startTime); - - // additional info contains info other than context info ... - map.put(JsonKey.ADDITIONAL_INFO, additionalInfo); - if (StringUtils.isBlank(messageId)) { - messageId = JsonKey.DEFAULT_CONSUMER_ID; + Map map = new WeakHashMap<>(); + map.put(JsonKey.CONTEXT, reqContext); + Map additionalInfo = new WeakHashMap<>(); + additionalInfo.put(JsonKey.URL, url); + additionalInfo.put(JsonKey.METHOD, methodName); + map.put(JsonKey.ADDITIONAL_INFO, additionalInfo); + request.flash().put(JsonKey.REQUEST_ID, requestId); + request.flash().put(JsonKey.CONTEXT, mapper.writeValueAsString(map)); + } catch (Exception ex) { + ProjectCommonException.throwServerErrorException(ResponseCode.SERVER_ERROR); } - request.flash().put(JsonKey.REQUEST_ID, messageId); - if (requestInfo == null) { - requestInfo = new ConcurrentHashMap<>(); - } - requestInfo.put(messageId, map); - ProjectLogger.log( - "OnRequestHandler:intializeRequestInfo added details for messageId=" + messageId, - LoggerEnum.INFO); } private static String getCustodianOrgHashTagId() { + if (custodianOrgHashTagId != null) { + return custodianOrgHashTagId; + } synchronized (OnRequestHandler.class) { if (custodianOrgHashTagId == null) { try { - // Get custodian org ID - SystemSettingClient sysSettingClient = SystemSettingClientImpl.getInstance(); - ActorRef sysSettingActorRef = - RequestRouter.getActor(ActorOperations.GET_SYSTEM_SETTING.getValue()); - SystemSetting systemSetting = - sysSettingClient.getSystemSettingByField( - sysSettingActorRef, JsonKey.CUSTODIAN_ORG_ID); // Get hash tag ID of custodian org OrganisationClient orgClient = new OrganisationClientImpl(); ActorRef orgActorRef = RequestRouter.getActor(ActorOperations.GET_ORG_DETAILS.getValue()); custodianOrgHashTagId = - orgClient.getOrgById(orgActorRef, systemSetting.getValue()).getHashTagId(); + orgClient + .getOrgById( + orgActorRef, + DataCacheHandler.getConfigSettings().get(JsonKey.CUSTODIAN_ORG_ID)) + .getHashTagId(); } catch (ProjectCommonException e) { if (e.getResponseCode() == HttpStatus.SC_NOT_FOUND) custodianOrgHashTagId = ""; else throw e; @@ -253,7 +220,7 @@ private String getEnv(Http.Request request) { env = JsonKey.BADGES; } else if (uri.startsWith("/v1/issuer")) { env = BadgingJsonKey.BADGES; - } else if (uri.startsWith("/v1/role")) { + } else if (uri.startsWith("/v1/role")) { env = JsonKey.ROLE; } else if (uri.startsWith("/v1/note")) { env = JsonKey.NOTE; @@ -268,5 +235,4 @@ private String getEnv(Http.Request request) { } return env; } - -} \ No newline at end of file +} diff --git a/service/app/util/AuthenticationHelper.java b/service/app/util/AuthenticationHelper.java index 76acc3a23b..fd78b106ba 100644 --- a/service/app/util/AuthenticationHelper.java +++ b/service/app/util/AuthenticationHelper.java @@ -3,18 +3,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + +import org.sunbird.auth.verifier.ManagedTokenValidator; import org.sunbird.cassandra.CassandraOperation; -import org.sunbird.common.exception.ProjectCommonException; import org.sunbird.common.models.response.Response; import org.sunbird.common.models.util.JsonKey; import org.sunbird.common.models.util.ProjectLogger; import org.sunbird.common.models.util.PropertiesCache; import org.sunbird.common.models.util.datasecurity.EncryptionService; -import org.sunbird.common.responsecode.ResponseCode; import org.sunbird.helper.ServiceFactory; import org.sunbird.learner.util.Util; import org.sunbird.learner.util.Util.DbInfo; -import org.sunbird.middleware.Application; import org.sunbird.services.sso.SSOManager; import org.sunbird.services.sso.SSOServiceFactory; @@ -25,9 +24,6 @@ * @author Manzarul */ public class AuthenticationHelper { - static { - Application.checkCassandraConnection(); - } private static boolean ssoEnabled = ((PropertiesCache.getInstance().getProperty(JsonKey.SSO_PUBLIC_KEY) != null) @@ -95,38 +91,5 @@ public static String verifyClientAccessToken(String clientId, String clientToken } return validClientId; } - - /** - * This method will save the user access token in side data base. - * - * @param token String - * @param userId String - * @return boolean - */ - public static boolean saveUserAccessToken(String token, String userId) { - - return false; - } - - /** - * This method will invalidate the user access token. - * - * @param token String - * @return boolean - */ - public static boolean invalidateToken(String token) { - - return false; - } - - public static String getEncryptedData(String value) { - try { - return encryptionService.encryptData(value); - } catch (Exception e) { - throw new ProjectCommonException( - ResponseCode.userDataEncryptionError.getErrorCode(), - ResponseCode.userDataEncryptionError.getErrorMessage(), - ResponseCode.SERVER_ERROR.getResponseCode()); - } - } + } diff --git a/service/app/util/RequestInterceptor.java b/service/app/util/RequestInterceptor.java index 87d2d88c06..a071ba8d89 100644 --- a/service/app/util/RequestInterceptor.java +++ b/service/app/util/RequestInterceptor.java @@ -1,11 +1,17 @@ package util; +import com.fasterxml.jackson.databind.JsonNode; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.StringUtils; +import org.sunbird.auth.verifier.ManagedTokenValidator; import org.sunbird.common.models.util.JsonKey; +import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; import org.sunbird.common.request.HeaderParam; import play.mvc.Http; @@ -100,10 +106,34 @@ private RequestInterceptor() {} apiHeaderIgnoreMap.put("/private/user/v1/identifier/freeup", var); apiHeaderIgnoreMap.put("/private/user/v1/password/reset", var); apiHeaderIgnoreMap.put("/private/user/v1/certs/add", var); - apiHeaderIgnoreMap.put("/v1/user/exists/email",var); - apiHeaderIgnoreMap.put("/v1/user/exists/phone",var); - apiHeaderIgnoreMap.put("/v1/role/read",var); + apiHeaderIgnoreMap.put("/v1/user/exists/email", var); + apiHeaderIgnoreMap.put("/v1/user/exists/phone", var); + apiHeaderIgnoreMap.put("/v1/role/read", var); + } + private static String getUserRequestedFor(Http.Request request) { + String requestedForUserID = null; + JsonNode jsonBody = request.body().asJson(); + if (!(jsonBody == null)) { // for search and update and create_mui api's + if (!(jsonBody.get(JsonKey.REQUEST).get(JsonKey.USER_ID) == null)) { + requestedForUserID = jsonBody.get(JsonKey.REQUEST).get(JsonKey.USER_ID).asText(); + } + } else { // for read-api + String uuidSegment = null; + Path path = Paths.get(request.uri()); + if (request.queryString().isEmpty()) { + uuidSegment = path.getFileName().toString(); + } else { + String[] queryPath = path.getFileName().toString().split("\\?"); + uuidSegment = queryPath[0]; + } + try { + requestedForUserID = UUID.fromString(uuidSegment).toString(); + } catch (IllegalArgumentException iae) { + ProjectLogger.log("Perhaps this is another API, like search that doesn't carry user id."); + } + } + return requestedForUserID; } /** @@ -111,18 +141,42 @@ private RequestInterceptor() {} * * @param request HTTP play request * @return User or Client ID for authenticated request. For unauthenticated requests, UNAUTHORIZED - * is returned + * is returned release-3.0.0 on-wards validating managedBy token. */ public static String verifyRequestData(Http.Request request) { String clientId = JsonKey.UNAUTHORIZED; + request.flash().put(JsonKey.MANAGED_FOR, null); Optional accessToken = request.header(HeaderParam.X_Authenticated_User_Token.getName()); Optional authClientToken = request.header(HeaderParam.X_Authenticated_Client_Token.getName()); Optional authClientId = request.header(HeaderParam.X_Authenticated_Client_Id.getName()); if (!isRequestInExcludeList(request.path()) && !isRequestPrivate(request.path())) { + // The API must be invoked with either access token or client token. if (accessToken.isPresent()) { clientId = AuthenticationHelper.verifyUserAccesToken(accessToken.get()); + if (!JsonKey.USER_UNAUTH_STATES.contains(clientId)) { + // Now we have some valid token, next verify if the token is matching the request. + String requestedForUserID = getUserRequestedFor(request); + if (StringUtils.isNotEmpty(requestedForUserID) && !requestedForUserID.equals(clientId)) { + // LUA - MUA user combo, check the 'for' token and its parent, child identifiers + Optional forTokenHeader = + request.header(HeaderParam.X_Authenticated_For.getName()); + String managedAccessToken = forTokenHeader.isPresent() ? forTokenHeader.get() : ""; + if (StringUtils.isNotEmpty(managedAccessToken)) { + String managedFor = + ManagedTokenValidator.verify(managedAccessToken, clientId, requestedForUserID); + if (!JsonKey.USER_UNAUTH_STATES.contains(managedFor)) { + request.flash().put(JsonKey.MANAGED_FOR, managedFor); + } else { + clientId = JsonKey.UNAUTHORIZED; + } + } + } else { + ProjectLogger.log("Ignoring x-authenticated-for token...", LoggerEnum.INFO.name()); + } + } } else if (authClientToken.isPresent() && authClientId.isPresent()) { + // Client token is present clientId = AuthenticationHelper.verifyClientAccessToken(authClientId.get(), authClientToken.get()); if (!JsonKey.UNAUTHORIZED.equals(clientId)) { diff --git a/service/conf/application.conf b/service/conf/application.conf index a16de109f6..8e5cffe754 100644 --- a/service/conf/application.conf +++ b/service/conf/application.conf @@ -149,7 +149,7 @@ play.filters { # Allow requests to example.com, its subdomains, and localhost:9000. allowed = ["localhost:9000","."] } - enabled += filters.LoggingFilter + enabled += filters.AccessLogFilter enabled += filters.CustomGzipFilter disabled += play.filters.csrf.CSRFFilter } diff --git a/service/conf/logback.xml b/service/conf/logback.xml new file mode 100644 index 0000000000..6859422812 --- /dev/null +++ b/service/conf/logback.xml @@ -0,0 +1,60 @@ + + + + + + + + + + %d %msg%n + + + + + + + + + + + + + + + + + + + + %msg + + + ${ENV_NAME}.telemetry.raw + + + + + + + + + bootstrap.servers=${SUNBIRD_KAFKA_URL} + + acks=0 + + linger.ms=15000 + + max.block.ms=0 + + client.id=${HOSTNAME}-${CONTEXT_NAME}-logback-relaxed + + + + + + + + + + \ No newline at end of file diff --git a/service/conf/routes b/service/conf/routes index f888b28d7a..edee741a61 100644 --- a/service/conf/routes +++ b/service/conf/routes @@ -6,7 +6,9 @@ POST /v1/user/create @controllers.usermanagement.UserController.createUser(request: play.mvc.Http.Request) POST /v2/user/create @controllers.usermanagement.UserController.createUserV2(request: play.mvc.Http.Request) POST /v3/user/create @controllers.usermanagement.UserController.createUserV3Sync(request: play.mvc.Http.Request) -POST /v1/user/signup @controllers.usermanagement.UserController.createUserV3(request: play.mvc.Http.Request) +#/v4/user/create is used only Managed-User creation, this is not for regular user creation. +POST /v4/user/create @controllers.usermanagement.UserController.createUserV4(request: play.mvc.Http.Request) +POST /v1/user/signup @controllers.usermanagement.UserController.createUserV3(request: play.mvc.Http.Request) PATCH /v1/user/update @controllers.usermanagement.UserController.updateUser(request: play.mvc.Http.Request) PATCH /private/user/v1/update @controllers.usermanagement.UserController.updateUser(request: play.mvc.Http.Request) GET /v1/user/read/:uid @controllers.usermanagement.UserController.getUserById(uid:String, request: play.mvc.Http.Request) @@ -16,6 +18,7 @@ GET /v1/user/get/:idType/:id @controllers.usermanagement.UserControll POST /v1/user/search @controllers.usermanagement.UserController.searchUser(request: play.mvc.Http.Request) POST /private/user/v1/search @controllers.usermanagement.UserController.searchUser(request: play.mvc.Http.Request) GET /private/user/v1/read/:externalId @controllers.usermanagement.UserController.getUserById(externalId:String, request: play.mvc.Http.Request) +GET /v1/user/managed/:lua_uuid @controllers.usermanagement.UserController.getManagedUsers(lua_uuid:String, request: play.mvc.Http.Request) GET /v1/user/mediatype/list @controllers.usermanagement.UserProfileController.getProfileSupportedSocialMediaTypes(request: play.mvc.Http.Request) POST /v1/user/profile/visibility @controllers.usermanagement.UserProfileController.setProfileVisibility(request: play.mvc.Http.Request) diff --git a/service/pom.xml b/service/pom.xml index cf22afa764..18cebff375 100644 --- a/service/pom.xml +++ b/service/pom.xml @@ -50,10 +50,33 @@ play-guice_${scala.major.version} ${play2.version} + + com.typesafe.play + play-logback_2.11 + ${play2.version} + runtime + + + slf4j-api + org.slf4j + + + + + com.typesafe + config + 1.3.0 + org.sunbird mw-service 1.0-SNAPSHOT + + + slf4j-api + org.slf4j + + com.typesafe.play @@ -72,6 +95,10 @@ com.google.guava guava + + slf4j-api + org.slf4j + @@ -86,6 +113,53 @@ + + org.scala-lang + scala-library + ${scala.version} + + + + org.apache.httpcomponents + httpclient + 4.5.1 + + + + com.typesafe.akka + akka-slf4j_${scala.major.version} + ${learner.akka.version} + + + com.typesafe.akka + akka-testkit_${scala.major.version} + ${learner.akka.version} + test + + + org.powermock + powermock-module-junit4 + 1.6.5 + test + + + junit + junit + + + + + org.powermock + powermock-api-mockito + 1.6.5 + test + + + junit + junit + 4.12 + test + com.typesafe.play filters-helpers_${scala.major.version} @@ -96,6 +170,11 @@ play-akka-http-server_${scala.major.version} ${play2.version} + + com.github.danielwegener + logback-kafka-appender + 0.2.0-RC2 + ${basedir}/app diff --git a/service/test/controllers/ApplicationTest.java b/service/test/controllers/ApplicationTest.java index da08e4179c..52b760f411 100644 --- a/service/test/controllers/ApplicationTest.java +++ b/service/test/controllers/ApplicationTest.java @@ -3,13 +3,11 @@ import static org.junit.Assert.assertEquals; import modules.OnRequestHandler; -import org.junit.Ignore; import org.junit.Test; import org.powermock.core.classloader.annotations.PrepareForTest; import org.sunbird.actor.service.SunbirdMWService; import org.sunbird.common.exception.ProjectCommonException; import org.sunbird.common.models.response.Response; -import org.sunbird.common.models.response.ResponseParams; import org.sunbird.common.responsecode.ResponseCode; import play.mvc.Result; @@ -27,14 +25,6 @@ public void testGetApiVersionSuccess() { assertEquals("v1", version); } - @Test - public void testCreateResponseParamObjSuccess() { - ResponseCode code = ResponseCode.getResponse(ResponseCode.success.getErrorCode()); - code.setResponseCode(ResponseCode.OK.getResponseCode()); - ResponseParams params = BaseController.createResponseParamObj(code); - assertEquals(ResponseCode.success.name(), params.getStatus()); - } - @Test public void testCreateResponseOnExceptionSuccess() { ProjectCommonException exception = @@ -47,21 +37,6 @@ public void testCreateResponseOnExceptionSuccess() { assertEquals(ResponseCode.courseIdRequiredError.getErrorCode(), response.getParams().getErr()); } - @Test - public void testCreateSuccessResponseSuccess() { - Response response = new Response(); - Result result = BaseController.createSuccessResponse(null, response); - assertEquals(ResponseCode.OK.getResponseCode(), result.status()); - } - - @Test - public void testCreateResponseParamObjFailure() { - ResponseCode code = ResponseCode.getResponse(ResponseCode.authTokenRequired.getErrorCode()); - code.setResponseCode(ResponseCode.CLIENT_ERROR.getResponseCode()); - ResponseParams params = BaseController.createResponseParamObj(code); - assertEquals(ResponseCode.authTokenRequired.name(), params.getStatus()); - } - @Test(expected = RuntimeException.class) public void testCreateCommonExceptionResponseSuccess() { ResponseCode code = ResponseCode.getResponse(ResponseCode.authTokenRequired.getErrorCode()); diff --git a/service/test/controllers/BaseApplicationTest.java b/service/test/controllers/BaseApplicationTest.java index 49d84d959a..2ebd96749d 100644 --- a/service/test/controllers/BaseApplicationTest.java +++ b/service/test/controllers/BaseApplicationTest.java @@ -4,6 +4,7 @@ import akka.actor.ActorSystem; import akka.actor.Props; import com.fasterxml.jackson.databind.ObjectMapper; +import filters.AccessLogFilter; import java.io.File; import modules.OnRequestHandler; import modules.StartModule; @@ -17,6 +18,7 @@ import org.sunbird.common.models.response.ResponseParams; import org.sunbird.common.models.util.LoggerEnum; import org.sunbird.common.models.util.ProjectLogger; +import org.sunbird.telemetry.util.TelemetryWriter; import play.Application; import play.Mode; import play.inject.guice.GuiceApplicationBuilder; @@ -27,7 +29,7 @@ @RunWith(PowerMockRunner.class) @PowerMockIgnore("javax.management.*") -@PrepareForTest({RequestInterceptor.class}) +@PrepareForTest({RequestInterceptor.class, TelemetryWriter.class, AccessLogFilter.class}) public abstract class BaseApplicationTest { protected Application application; private ActorSystem system; @@ -46,7 +48,9 @@ public void setup(Class actorClass) { props = Props.create(actorClass); ActorRef subject = system.actorOf(props); BaseController.setActorRef(subject); + AccessLogFilter filter = PowerMockito.mock(AccessLogFilter.class); PowerMockito.mockStatic(RequestInterceptor.class); + PowerMockito.mockStatic(TelemetryWriter.class); PowerMockito.when(RequestInterceptor.verifyRequestData(Mockito.any())).thenReturn("userId"); PowerMockito.mockStatic(OnRequestHandler.class); PowerMockito.doReturn("12345678990").when(OnRequestHandler.class, "getCustodianOrgHashTagId"); diff --git a/service/test/controllers/usermanagement/UserControllerTest.java b/service/test/controllers/usermanagement/UserControllerTest.java index dd843c9715..ea6e67fb24 100644 --- a/service/test/controllers/usermanagement/UserControllerTest.java +++ b/service/test/controllers/usermanagement/UserControllerTest.java @@ -423,4 +423,11 @@ public String getResponseCode(Result result) { public int getResponseStatus(Result result) { return result.status(); } + + @Test + public void testGetManagedUsersSuccess() { + Result result = performTest("/v1/user/managed/102fcbd2-8ec1-4870-b9e1-5dc01f2acc75?withTokens=false", "GET", null); + assertEquals(getResponseCode(result), ResponseCode.success.getErrorCode().toLowerCase()); + assertTrue(getResponseStatus(result) == 200); + } }