diff --git a/.env.sample b/.env.sample index 71744772..b6b56c3e 100644 --- a/.env.sample +++ b/.env.sample @@ -28,4 +28,79 @@ KEYCLOAK_PUBLIC_KEY_PATH = "keycloak-public-keys" DISABLE_LEARNER_SERVICE_ON_OFF = "ON" // Disable learner service check -FORM_SERVICE_URL = "http://player:3000" // Base url for form search \ No newline at end of file +FORM_SERVICE_URL = "http://player:3000" // Base url for form search + + +# Redis configuration + +REDIS_URL = redis://localhost:6379 // Redis connection url +REDIS_USERNAME = "redis" // Redis username +REDIS_PWD = "1234" // Redis password +REDIS_DB = 1 // Redis db index +REDIS_TTL = 86400 // Redis ttl (for how many seconds a given key value will continue to be part of the dataset) + +# creation portal migration Script + +MASTER_USER_EMAIL = "n11@yopmail.com" // master user name of the sunbird enviornment to generate token +MASTER_USER_PWD = "password" // master user pwd of the sunbird enviornment to generate token +TOKEN_GEN_GRANT_TYPE = "password-grant" // grant type to generate token for the sunbird enviornment +TOKEN_GEN_CLIENT = "client-id" // client to generate token for the sunbird enviornment +TOKEN_GEN_CLIENT_SECRET = "client-secret-key" // client secret to generate token for the sunbird enviornment + +ED_BASE_URL = "https://dev.sunbirded.org/" // base host url of the sunbird enviornment +ED_AUTHORIZATION = "Bearer + 'token'" // base bearer token with all the permissions to run the script of the sunbird enviornment + +CREATION_PORTAL_URL = "https://dock.sunbirded.org/" // creation portal Url + +CREATION_PORTAL_AUTHORIZATION= "Bearer + 'token'" // creation portal bearer token with all the permissions for below urls, + + + +# Migration + + # API'S required for migration + + GEN_TOKEN: "auth/realms/sunbird/protocol/openid-connect/token" // To generate token + READ_USER: "api/user/v5/read/" // To read user data Authorization: ED_AUTHORIZATION + SEARCH_USER: "api/user/v3/search" // To search user data, Authorization: ED_AUTHORIZATION + CREATE_QUESTION_SET: "api/questionset/v1/create" // To create questionset, Authorization: CREATION_PORTAL_AUTHORIZATION + UPDATE_QUESTION_SET_HIERARCHY: "api/questionset/v1/hierarchy/update" // To update questionset hierarchy, Authorization: CREATION_PORTAL_AUTHORIZATION + PUBLISH_QUESTION_SET: "api/questionset/v1/publish" // To publish questionset, Authorization: CREATION_PORTAL_AUTHORIZATION + READ_QUESTION_SET: "questionset/v1/hierarchy" // To read questionset, Authorization: CREATION_PORTAL_AUTHORIZATION + CREATE_QUESTION: "api/question/v1/create" // To create question, Authorization: CREATION_PORTAL_AUTHORIZATION + PUBLISH_QUESTION: "api/question/v1/publish" // To publish question, Authorization: CREATION_PORTAL_AUTHORIZATION + CREATE_PROGRAM: "api/program/v1/create" // To create program, Authorization: CREATION_PORTAL_AUTHORIZATION + UPDATE_PROGRAM: "api/program/v1/update" // To update program, Authorization: CREATION_PORTAL_AUTHORIZATION + ADD_PROGRAM_NOMINATION: "api/program/v1/nomination/add" // To add nomination to program, Authorization: CREATION_PORTAL_AUTHORIZATION + UPDATE_PROGRAM_NOMINATION: "api/program/v1/nomination/update" // To update program nomination, Authorization: CREATION_PORTAL_AUTHORIZATION + PUBLISH_PROGRAM: "api/program/v1/publish" // To publish program, Authorization: CREATION_PORTAL_AUTHORIZATION + + # Default users to create program and question + + DEFAULT_SLUG = 'sunbird' // default slug + + DEFAULT_USER_ID_TO_CREATE_PROGRAM = '5a587cc1-e018-4859-a0a8-e842650b9d64' // default user id to create program if solution author is not present + DEFAULT_USER_CHANNEL_ID_TO_CREATE_PROGRAM = '01285019302823526477' // default user channel id to create program if solution author is not present + DEFAULT_USER_SOURCING_ORG_NAME_TO_CREATE_PROGRAM = 'NIT' // default user sourcing org name + DEFAULT_PROGRAM_CREATOR_ORGANISATION_ID = '937dd865-b256-4c1a-9830-a9b5b89f0913'// default user org id to create program if solution author is not present + + + DEFAULT_FRAMEWORK_ID = 'nit_tpd' // default framework id to create program + DEFAULT_FRAMEWORK_TYPE = 'TPD' // default framework type to create program + + DEFAULT_USER_ID_TO_ADD_CONTRIBUTOR = 'bb551fff-121e-4a18-b969-984ac62bd572' // default user id to nominate and add contributor to program + + DEFAULT_CONTRIBUTOR_USER_ID = '4e397c42-495e-4fdb-8558-f98176230916' // default user id to contribute content to the program + DEFAULT_CONTRIBUTOR_USER_NAME = 'check1@yopmail.com' // default user name to contribute content to the program + DEFAULT_CONTRIBUTOR_USER_CHANNEL_ID = '01309282781705830427' // default user user channel to contribute content to the program + + +# API'S required for Transformation + + COPY_QUESTION_SET: "/api/questionset/v1/copy" // To copy questionset + UPDATE_QUESTION_SET:"/api/questionset/v1/update" // To update questionset + READ_QUESTION: "/api/question/v1/read" // To read questionset + UPDATE_QUESTION_SET_HIERARCHY // To update questionset hierarchy + PUBLISH_QUESTION_SET // To publish questionset + READ_QUESTION_SET // To read questionset + diff --git a/package.json b/package.json index 587c2697..f3ed49ad 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "test": "mocha --timeout 10000", "start": "node app.js", "dev": "nodemon app.js", - "coverage": " nyc --reporter=lcov mocha --timeout 10000 test --exit" + "coverage": " nyc --reporter=lcov mocha --timeout 10000 test --exit", + "creation_portal_script": "node scripts/creation-portal-migration/index.js" }, "keywords": [ "shikshalokam", @@ -19,6 +20,7 @@ "author": "Akash Shah ", "license": "ISC", "dependencies": { + "axios": "^0.26.1", "body-parser": "^1.18.2", "bunyan": "^1.8.12", "cache-manager": "^2.9.0", @@ -28,7 +30,9 @@ "commander": "^2.20.0", "cookie-parser": "^1.4.3", "cors": "^2.8.4", - "csvtojson": "^2.0.8", + "csv-parse": "^5.3.0", + "csv-stringify": "^6.2.0", + "csvtojson": "^2.0.10", "dotenv": "^6.1.0", "express": "^4.16.3", "express-cassandra": "^2.3.2", @@ -45,6 +49,7 @@ "jwt-decode": "^2.2.0", "kafka-node": "^4.1.3", "keycloak-auth-utils": "^3.3.0", + "lodash": "^4.17.21", "log": "^1.4.0", "mathjs": "^5.2.3", "mkdir": "0.0.2", @@ -60,6 +65,7 @@ "node-cache": "^5.1.2", "p-each-series": "^2.1.0", "path": "^0.12.7", + "query-string": "^7.1.1", "request": "^2.88.0", "require-all": "^2.2.0", "uuid": "^3.3.2", diff --git a/scripts/creation-portal-migration/README.md b/scripts/creation-portal-migration/README.md new file mode 100644 index 00000000..03a31275 Binary files /dev/null and b/scripts/creation-portal-migration/README.md differ diff --git a/scripts/creation-portal-migration/SL-DataMapping.csv b/scripts/creation-portal-migration/SL-DataMapping.csv new file mode 100644 index 00000000..c5d2910d --- /dev/null +++ b/scripts/creation-portal-migration/SL-DataMapping.csv @@ -0,0 +1,22 @@ +ENV,authorId,mappedUserId,userName,rootOrgId,rootOrgName,org_id,srcOrgAdminId,srcOrgAdminUserName,contributorOrgAdminId,contributorOrgAdminUserName,solutionId,solutionName,programId,programName +STAGE,140558b9-7df4-4993-be3c-31eb8b9ca368,d8d54588-82f7-420d-b098-c03948135d6f,abhi234,01283607456185548825093,NCERT,fba93280-27b5-4d29-90e0-1f79ecbfa4bf,8e92e8da-83fe-43f1-b390-44da44675718,akhil23,8e92e8da-83fe-43f1-b390-44da44675718,akhil23,5f34e44681871d939950bca7,TN01-Mantra4Change-APSWREIS School Leader Feedback,e01178e0-7c76-11ed-bcf5-df48f63ad78b,MIGRATED 21TH TN01-Mantra4Change-APSWREIS School Leader Feedback sourcing project +STAGE,86d2d978-5b20-4453-8a76-82b5a4c728c9,b8e3c5f2-07b3-49f3-964f-ef8e90897513,karan121,01338111579044249633,dockstaging,d7da22f6-b737-4817-a194-6a205e535559,2730f876-735d-4935-ba52-849c524a53fe,dockstaging1@yopmail.com,2730f876-735d-4935-ba52-849c524a53fe,dockstaging1@yopmail.com,5f34ec17585244939f89f90d,MH01-Mantra4Change-APSWREIS School Leader Feedback,b00e8f10-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH MH01-Mantra4Change-APSWREIS School Leader Feedback sourcing project +STAGE,9304641b-71c6-4e95-ac2c-27f222904fbe,b717deee-4251-4161-9aae-cd73bf9055f3,rakesh22,01334203864941363283,Haryana,09cfa04a-e841-4168-b320-a3e7c19d8e88,be0ac426-2145-4ca1-a3b7-0d14947a3b3b,haryana1@yopmail.com,be0ac426-2145-4ca1-a3b7-0d14947a3b3b,haryana1@yopmail.com,5f36d6d019377eecddb06946,Need Assessment Form_Teacher Training,b1955621-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Need Assessment Form_Teacher Training sourcing project +STAGE,60c4bfaa-1650-413c-9fdf-32444a68e78d,18c80735-4823-432f-bd70-b2ffa1b68d70,raj119,0133725426790973441,LMS_12Staging,345b54ff-2563-4123-bc7e-4b5111c805a3,f836b1a5-4008-4283-acf9-f29078e88f9c,lmps2@yopmail.com,f836b1a5-4008-4283-acf9-f29078e88f9c,lmps2@yopmail.com,5f6db0cd7157bee754e6abdd,MH01-Mantra4Change-APSWREIS School Leader Feedback,b50b4300-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH MH01-Mantra4Change-APSWREIS School Leader Feedback sourcing project +STAGE,b87160fb-16c3-4951-82cc-31149bbb64b9,47859d2b-16a2-4555-83d5-8821876f86d4,kamesh99,01338113710893465654,dockstaging_vdn,7278c982-872c-4854-942b-b9aa1a32292d,8eee44cf-088a-4bdf-b0f0-f0c4cd0d1b7b,mahesh2@yopmail.com,8eee44cf-088a-4bdf-b0f0-f0c4cd0d1b7b,mahesh2@yopmail.com,5f7580ce5ccb683ca97f365b,Doubt Resolution-Test,b54f50e0-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Doubt Resolution-Test sourcing project +STAGE,66926c63-df26-4040-a222-3240c5c1dcea,559f4029-5c86-42e1-b465-92b57e194d78,ranu21,013085024460783616158023,Classmate,398a880a-bdee-41e1-84c4-b968edb20874,38949d9d-4a35-482e-b45d-85475e0c17df,google2yopmail.com_sw81,38949d9d-4a35-482e-b45d-85475e0c17df,google2yopmail.com_sw81,5f870d83d144f124575da5c2,Enrollment challenges in DIKSHA Courses,b67fe1a1-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Enrollment challenges in DIKSHA Courses sourcing project +STAGE,1deba81d-3be0-4f9a-b2c7-e284ac75227f,08f44793-f256-4ed8-bee5-b0cbc083a082,mamta22,01338113627113881647,org4thOct2021,596c410a-1dfd-4a8d-8832-1dee41df601a,4bdfca08-0f4e-4cd1-a899-dad9a15d8ac0,4oct_pb6t,4bdfca08-0f4e-4cd1-a899-dad9a15d8ac0,4oct_pb6t,5f8745f5788bc8241ebcb172,Teachers' Weekly Check-in Form,b6c68790-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Teachers' Weekly Check-in Form sourcing project +STAGE,c9f5bb44-5a55-460c-8466-5299a1065689,c3aa35d3-344e-4b16-a845-25ca72285fec,anupma17,01338111839367987237,org3rdOct2021,bd76269b-785a-4e37-973e-b87104a40024,257566b5-613a-43d9-a61b-385cacc9ac52,3oct_ubnp,257566b5-613a-43d9-a61b-385cacc9ac52,3oct_ubnp,5f874f7abbaab2241230d1dc,Enrollment challenges in DIKSHA Courses,b7098400-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Enrollment challenges in DIKSHA Courses sourcing project +STAGE,a96826e9-ecd3-4d43-b9c9-37b4eaaf056e,cb9f1598-8f0f-4ca8-b02d-3b9e7d3d7a6a,lalita26,01347079436417433655,Shiksha,70795630-bd0a-438a-9310-90c6cc913ab5,f38ebb4a-fe11-4faf-98bd-4d7023b20abb,shiksha1yopmail.com_em2j,f38ebb4a-fe11-4faf-98bd-4d7023b20abb,shiksha1yopmail.com_em2j,5f89288cbbaab2241230d1e7,MH01-Mantra4Change-APSWREIS School Leader Feedback,b77983e1-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH MH01-Mantra4Change-APSWREIS School Leader Feedback sourcing project +STAGE,1dc2e743-1504-47e1-adad-54749e2b833c,fa7474d8-1fc5-418f-b236-f0703d95eb8f,manoj87,01344484093886464035,Sunrise,6c0e71b0-3620-429f-9da3-aec213e13928,616df817-97d3-4b0e-a622-f2494e957b26,sunrise1yopmail.com_eeod,616df817-97d3-4b0e-a622-f2494e957b26,sunrise1yopmail.com_eeod,5f9e3f0b2132c21d9c061b8a,Need Assessment Form_Teacher Training,b7ec42e1-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Need Assessment Form_Teacher Training sourcing project +STAGE,575de5bb-e295-4546-9fc4-32f81b5ed081,75f8ad98-d888-4bac-97f4-0c273c200e7b,jay65,013535284215791616159,Dayanand Sagar,bcf2cdc0-39f3-45c0-bc1d-a8d643e05a4a,33512b57-af74-4f6b-86b0-cb7af15d1c09,dayanandyopmail.com_mslq,33512b57-af74-4f6b-86b0-cb7af15d1c09,dayanandyopmail.com_mslq,5fa28620b6bd9b757dc4e943,स्कूल सुरक्षा चेकलिस्ट,b8befc30-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH स्कूल सुरक्षा चेकलिस्ट sourcing project +STAGE,0c274517-d3b9-4858-9d88-b41cfcc2727e,57848f7c-f736-4781-a27f-206e663e3b4e,kiran584,01346442741037465621,cokreate,4f9703cb-05ec-4ebf-8967-ecd7a71ce346,e616ae45-ec26-41e4-85b2-146e031b3ec1,cokreate3yopmail.com_jwt1,e616ae45-ec26-41e4-85b2-146e031b3ec1,cokreate3yopmail.com_jwt1,5fa299f0b6bd9b757dc4e95c,MH01-Mantra4Change-APSWREIS School Leader Feedback,b92f2320-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH MH01-Mantra4Change-APSWREIS School Leader Feedback sourcing project +STAGE,2b655fd1-201d-4d2a-a1b7-9048a25c0afa,3b247583-89e3-46ae-b7f8-bea66ac7d364,shrishti26,01345815127107174426,Globe,228b25b1-a08a-4ba9-bb4f-513641924eaf,6ff8dd54-541b-4694-b1aa-b8295add8301,globeyopmail.com_b8iu,6ff8dd54-541b-4694-b1aa-b8295add8301,globeyopmail.com_b8iu,5fa2a08a9e65d8758624e977,We love reading program-Teacher Check in,b97309f0-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH We love reading program-Teacher Check in sourcing project +STAGE,5cc9d214-c938-4655-8ec2-c1fdab29888b,d7850ce5-7076-463e-bdf5-4e112118fa74,ram45,01347076031606784034,Google,bb8dac15-782e-42c6-a6d4-e425e7b9a1af,94409d3e-b76f-4afb-ae51-b308d87c9834,anbu2yopmail.com_kayh,94409d3e-b76f-4afb-ae51-b308d87c9834,anbu2yopmail.com_kayh,5fa3b9594ddf782be2d9600c,Teachers' Weekly Check-in Form,ba16eb11-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Teachers' Weekly Check-in Form sourcing project +STAGE,9b303e72-e45b-42b6-8ef6-163092144a6b,0fd600dd-0d56-4824-85c8-02477ed0a9e0,yash172,013476546243641344142,Sony,61ee884a-bbb2-421c-91b9-7583ec3c3d8f,bc9f4f4c-7e28-4b9c-9cb3-08a84b5828a3,sonydefect1yopmail.com_2u9k,bc9f4f4c-7e28-4b9c-9cb3-08a84b5828a3,sonydefect1yopmail.com_2u9k,5fae38794ddf782be2d9603f,MH01-Mantra4Change-APSWREIS School Leader Feedback,bab96ca1-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH MH01-Mantra4Change-APSWREIS School Leader Feedback sourcing project +STAGE,23e491b1-7c90-4497-823e-f01f104e81f1,cc33df21-c4e4-40f0-93bb-6e7d93220b81,nehal23,013496244294746112177,Roseland,07f7c48c-b368-4f9d-a5b8-b17828a94e90,47a90330-0e47-42b3-b569-4ee0565a589d,roseland10yopmail.com_8eey,47a90330-0e47-42b3-b569-4ee0565a589d,roseland10yopmail.com_8eey,5fb74511eff083796933d5a5,Baseline Data collection form- We Love Reading Program,bd05cda1-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Baseline Data collection form- We Love Reading Program sourcing project +STAGE,3eeb8aef-b167-42ae-b2a3-515772a6e946,8defd75a-a28f-4bd7-be8a-82f29dbdd3f8,ayush213,0131602658018017280,AushaOrg,46e44ca6-7571-4599-aec7-228d3b1d557e,f149cf81-8b8f-4471-b20f-f3ef65df9243,demo3org,f149cf81-8b8f-4471-b20f-f3ef65df9243,demo3org,5fbb5b34eff083796933d5cf,Baseline Data collection form- We Love Reading Program,bd7a6160-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Baseline Data collection form- We Love Reading Program sourcing project +STAGE,19a22722-9e35-4f80-9412-f2668d50ec3c,0a544b58-50f9-4da0-9c03-dbbb0b9dd486,vivek87,0126796199493140480,Staging Custodian Organization,c97b9d1f-1b0e-42ef-ac9e-1b711ef7bd11,7ff56e27-4eec-475e-bb77-8457e34244a2,upsmfadmin,7ff56e27-4eec-475e-bb77-8457e34244a2,upsmfadmin,5fc72c723e9df47967eed966,Digi-Saksham Baseline Survey,ce712f30-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Digi-Saksham Baseline Survey sourcing project +STAGE,0f209f21-a093-421e-b867-561d85bc011b,1b216423-6a3c-4bcb-8ca1-07e3e2d2252e,aman56,013610958661779456198,Aloe,db2fc098-b963-4c96-b2c3-8fec2478fd3e,0a48c4dd-4662-47ca-a1fd-240ede6afabf,hdy1@yopmail.com,0a48c4dd-4662-47ca-a1fd-240ede6afabf,hdy1@yopmail.com,5fc8b5bcc9de717993cb4077,Need Assessment Form_Teacher Training,cf077bc1-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Need Assessment Form_Teacher Training sourcing project +STAGE,d4a823ad-3adc-4658-9b32-6011021f3633,cb67ff46-e9d5-44f8-a241-485ef6c948af,shilpi232,013655711988719616228,UPSMF,a9736891-e436-4bb2-98dd-6f6e3903b9fb,f6a8fac1-ccb7-41b1-a622-32639276d116,upsmf_pfms,f6a8fac1-ccb7-41b1-a622-32639276d116,upsmf_pfms,5fc8d9823e9df47967eed9b4,Digi-Saksham Baseline Survey,d160ae00-7c77-11ed-bcf5-df48f63ad78b,MIGRATED 21TH Digi-Saksham Baseline Survey sourcing project +STAGE,1405f334-ee59-42fc-befb-51986221881e,1405f334-ee59-42fc-befb-51986221881e,orgadmin007,01269878797503692810,Tamil Nadu,7c5a96ca-bef8-4027-8736-4fa1ae6f9180,124da479-71a8-4241-b899-877df83bd7f3,May31,124da479-71a8-4241-b899-877df83bd7f3,May31,6026743a262f8023e110727f,Enrollment challenges in DIKSHA Courses-1613132857976,,Migrated Enrollment challenges in DIKSHA Courses-1613132857976) \ No newline at end of file diff --git a/scripts/creation-portal-migration/api-list/headers.js b/scripts/creation-portal-migration/api-list/headers.js new file mode 100644 index 00000000..6d070fce --- /dev/null +++ b/scripts/creation-portal-migration/api-list/headers.js @@ -0,0 +1,96 @@ +const { default: axios } = require("axios"); +const { CONFIG } = require("../constant/config"); +const querystring = require("query-string"); +const jwt = require("jsonwebtoken"); +const logger = require("../logger"); + +const genToken = async (url, body, type) => { + const isValid = await validateToken(type); + + const headers = { + "Content-Type": "application/x-www-form-urlencoded", + }; + + if (!isValid) { + const res = await axios.post(url, body, headers).catch((err) => { + logger.error(`Error while generateToken Error: ${JSON.stringify(err?.response?.data)}`) + return err; + }); + return res ? res?.data?.access_token : ""; + } else { + const token = this.ed_token; + // console.log("rbdsnbnsf", this.ed_token); + // type === "ed" ? this.ed_token : this.ed_token + // this.creation_portal_token; + + return token; + } +}; + +const validateToken = (type) => { + const token = type === "ed" ? this.ed_token : this.ed_token; + // creation_portal_token; + + try { + if (token) { + const decoded = jwt.decode(token, {header: true}); + if (Date.now() >= decoded?.exp * 1000) { + return false; + } + return true; + } + return false; + } catch (err) { + return false; + } +}; + +const generateToken = async (type) => { + let url = ""; + let body = {}; + url = CONFIG.HOST.ed + CONFIG.APIS.token; + switch (type) { + case "ed": + // url = CONFIG.HOST.ed + CONFIG.APIS.token; + body = querystring.stringify({ ...CONFIG.KEYS.ED.QUERY }); + this.ed_token = await genToken(url, body, "ed"); + return this.ed_token; + case "creation_portal": + // url = CONFIG.HOST.creation_portal + CONFIG.APIS.token; + body = querystring.stringify({ ...CONFIG.KEYS.CREATION_PORTAL.QUERY }); + this.creation_portal_token = await genToken(url, body, "creation_portal"); + return this.creation_portal_token; + } +}; + +const getHeaders = async (isTokenReq, type) => { + let headers = {}; + + switch (type) { + case "ed": + headers = { + "Content-Type": "application/json", + Authorization: CONFIG.KEYS.ED.AUTHORIZATION, + }; + if (isTokenReq) { + headers["x-authenticated-user-token"] = await generateToken("ed"); + } + break; + + case "creation_portal": + headers = { + "Content-Type": "application/json", + Authorization: CONFIG.KEYS.CREATION_PORTAL.AUTHORIZATION, + }; + if (isTokenReq) { + headers["x-authenticated-user-token"] = await generateToken("creation_portal"); + } + break; + } + + return headers; +}; + +module.exports = { + getHeaders, +}; diff --git a/scripts/creation-portal-migration/api-list/program.js b/scripts/creation-portal-migration/api-list/program.js new file mode 100644 index 00000000..c10462c0 --- /dev/null +++ b/scripts/creation-portal-migration/api-list/program.js @@ -0,0 +1,124 @@ +const { default: axios } = require("axios"); +const { request } = require("chai"); +const { CONFIG } = require("../constant/config"); +const { getHeaders } = require("./headers"); + + + +const createProgram = async (templateData) => { + const url = CONFIG.HOST.creation_portal + CONFIG.APIS.create_program; + const data = { + request: { + ...templateData, + }, + }; + const config = { + method: "post", + url: url, + headers: await getHeaders(false, "creation_portal"), + data: data, + }; + + const res = await axios(config).catch(err => {}); + + return res?.data?.result?.program_id; +}; + +const updateProgram = async (templateData) => { + const url = CONFIG.HOST.creation_portal + CONFIG.APIS.update_program; + const data = { + request: { + ...templateData, + }, + }; + const config = { + method: "post", + url: url, + headers: await getHeaders(false, "creation_portal"), + data: data, + }; + const res = await axios(config); + return res.data; +}; + +const publishProgram = async (templateData) => { + const url = CONFIG.HOST.creation_portal + CONFIG.APIS.publish_program; + const data = { + request: { + ...templateData, + }, + }; + const config = { + method: "post", + url: url, + headers: await getHeaders(false, "creation_portal"), + data: data, + }; + + const res = await axios(config); + return res.data; +}; +const nominateProgram = async (program_id, orgAdmin) => { + const url = + CONFIG.HOST.creation_portal + CONFIG.APIS.add_program_nomination; + const data = { + request: { + program_id: program_id, + status: "Pending", + collection_ids: [], + createdby: orgAdmin?.srcOrgAdminId, + targetprimarycategories: [ + { + name: "Observation", + identifier: "obj-cat:observation_questionset_all", + targetObjectType: "QuestionSet", + }, + { + name: "Survey", + identifier: "obj-cat:survey_questionset_all", + targetObjectType: "QuestionSet", + }, + ], + content_types: [], + organisation_id: orgAdmin?.org_id, + user_id: orgAdmin?.mappedUserId|| process.env.DEFAULT_CONTRIBUTOR_ORG_ADMIN_ID, + }, + }; + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "creation_portal"), + data: data, + }; + + const res = await axios(config); + return res.data; +}; + +const updateContributorToProgram = async (reqData) => { + const url = + CONFIG.HOST.creation_portal + CONFIG.APIS.update_program_nomination; + const data = { + request: { + ...reqData, + }, + }; + + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "creation_portal"), + data: data, + }; + + const res = await axios(config); + return res.data; +}; + +module.exports = { + createProgram, + updateProgram, + publishProgram, + nominateProgram, + updateContributorToProgram, +}; diff --git a/scripts/creation-portal-migration/api-list/question.js b/scripts/creation-portal-migration/api-list/question.js new file mode 100644 index 00000000..d06e1289 --- /dev/null +++ b/scripts/creation-portal-migration/api-list/question.js @@ -0,0 +1,118 @@ +const { default: axios } = require("axios"); +const { CONFIG } = require("../constant/config"); +const logger = require("../logger"); +const { getHeaders } = require("./headers"); + +// Questionset + +const createQuestionSet = async (templateData) => { + const url = CONFIG.HOST.creation_portal + CONFIG.APIS.create_questionset; + const data = { + request: { + questionset: { ...templateData }, + }, + }; + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "creation_portal"), + data: data, + }; + const res = await axios(config); + + return res?.data?.result?.identifier; +}; + +const updateQuestionSetHierarchy = async (templateData) => { + const url = CONFIG.HOST.creation_portal + CONFIG.APIS.update_hierarchy; + + const config = { + method: "patch", + url: url, + headers: await getHeaders(true, "creation_portal"), + data: templateData, + }; + + const res = await axios(config); + return res?.data?.result?.identifiers; +}; + +const publishQuestionSet = async (questionsetId) => { + const url = + CONFIG.HOST.creation_portal + + CONFIG.APIS.publish_questionset + + "/" + + questionsetId; + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "creation_portal"), + data: {}, + }; + + const res = await axios(config); + return res?.data?.result?.identifier; +}; + +const readQuestionSetHierarchy = async (questionSetId) => { + const url = + CONFIG.HOST.creation_portal + + CONFIG.APIS.read_questionset + + questionSetId + + "?mode=edit"; + + const config = { + method: "get", + url: url, + headers: await getHeaders(true, "creation_portal"), + }; + + const res = await axios(config); + return res?.data?.result?.questionSet; +}; + +// Questions +const createQuestions = async (templateData, questionId) => { + const url = CONFIG.HOST.creation_portal + CONFIG.APIS.create_question; + const data = { + request: { + question: { ...templateData }, + }, + }; + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "creation_portal"), + data: data, + }; + const res = await axios(config).catch((err) => { + logger.error(`Error while creating the question for questionid: ${questionId} Error: + ${JSON.stringify(err.response.data)}`); + }); + return res?.data?.result?.identifier; +}; + +const publishQuestion = async (questionId) => { + const url = + CONFIG.HOST.creation_portal + + CONFIG.APIS.publish_question + + "/" + + questionId; + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "creation_portal") + }; + + const res = await axios(config) + return res?.data?.result?.identifier; +}; + +module.exports = { + createQuestionSet, + updateQuestionSetHierarchy, + publishQuestionSet, + createQuestions, + publishQuestion, + readQuestionSetHierarchy, +}; diff --git a/scripts/creation-portal-migration/api-list/user.js b/scripts/creation-portal-migration/api-list/user.js new file mode 100644 index 00000000..bdc21dc6 --- /dev/null +++ b/scripts/creation-portal-migration/api-list/user.js @@ -0,0 +1,79 @@ +const { default: axios } = require("axios"); +const { CONFIG } = require("../constant/config"); +const logger = require("../logger"); +const { getHeaders } = require("./headers"); + +const readUser = async (userId) => { + const params = "organisations,roles,locations,declarations,externalIds"; + const url = + CONFIG.HOST.ed + CONFIG.APIS.read_user + userId + "?fields=" + params; + + const config = { + method: "get", + url: url.trim(), + headers: await getHeaders(true, "ed"), + }; + + const res = await axios(config).catch((err) => { + logger.error(`Error while reading User: ${JSON.stringify(err)}`); + }); + return res.data?.result?.response; +}; + +const searchUser = async (userId) => { + const url = CONFIG.HOST.ed + CONFIG.APIS.search_user; + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "ed"), + data: { + request: { filters: { id: userId } }, + }, + }; + + const res = await axios(config).catch((err) => { + logger.error( + `Error while searching User: ${JSON.stringify(err?.response?.data)}` + ); + }); + return res?.data?.result?.response?.content; +}; + +const getOpenSaberUserOrgId = async () => { + const query = { + id: "open-saber.registry.search", + ver: "1.0", + ets: "11234", + params: { + did: "", + key: "", + msgid: "", + }, + request: { + entityType: ["User_Org"], + filters: {}, + limit: 10000, + offset: 0, + }, + }; + const url = CONFIG.HOST.creation_portal + CONFIG.APIS.open_saber_user_org_search; + const config = { + method: "post", + url: url, + headers: await getHeaders(true, "creation_portal"), + data: query + }; + + const res = await axios(config).catch((err) => { + logger.error( + `Error while searching User: ${JSON.stringify(err?.response?.data)}` + ); + }); + return res?.data?.result?.Org || [] +} + +module.exports = { + readUser, + searchUser, + getOpenSaberUserOrgId +}; diff --git a/scripts/creation-portal-migration/constant/config.js b/scripts/creation-portal-migration/constant/config.js new file mode 100644 index 00000000..548b4ff2 --- /dev/null +++ b/scripts/creation-portal-migration/constant/config.js @@ -0,0 +1,61 @@ +require("dotenv").config(); + +const CONFIG = { + DB: { + DB_HOST: process.env.MONGODB_URL, + DB_NAME: process.env.DB_NAME, + TABLES: { + solutions: "solutions", + criteria_questions: "criteriaQuestions", + questions: "questions", + }, + }, + + HOST: { + ed: process.env.ED_BASE_URL, + creation_portal: process.env.CREATION_PORTAL_URL, + }, + APIS: { + token: process.env.GEN_TOKEN || "auth/realms/sunbird/protocol/openid-connect/token", + read_user: process.env.READ_USER || "api/user/v5/read", + search_user: process.env.SEARCH_USER || "api/user/v3/search", + open_saber_user_org_search: process.env.OPEN_SABER_USER_ORG_SEARCH || "api/reg/search", + create_questionset: process.env.CREATE_QUESTION_SET || "api/questionset/v1/create", + update_hierarchy: process.env.UPDATE_QUESTION_SET_HIERARCHY || "api/questionset/v1/hierarchy/update", + publish_questionset: process.env.PUBLISH_QUESTION_SET || "api/questionset/v1/publish", + read_questionset: "api/" + process.env.READ_QUESTION_SET + "/" || "api/questionset/v1/hierarchy/", + create_question: process.env.CREATE_QUESTION || "api/question/v1/create", + publish_question: process.env.PUBLISH_QUESTION || "api/question/v1/publish", + create_program: process.env.CREATE_PROGRAM || "api/program/v1/create", + update_program: process.env.UPDATE_PROGRAM || "api/program/v1/update", + add_program_nomination: process.env.ADD_PROGRAM_NOMINATION || "api/program/v1/nomination/add", + update_program_nomination: process.env.UPDATE_PROGRAM_NOMINATION || "api/program/v1/nomination/update", + publish_program: process.env.PUBLISH_PROGRAM || "api/program/v1/publish", + }, + KEYS: { + ED: { + QUERY: { + username: process.env.MASTER_USER_EMAIL, + password: process.env.MASTER_USER_PWD, + grant_type: process.env.TOKEN_GEN_GRANT_TYPE, + client_id: process.env.TOKEN_GEN_CLIENT, + client_secret: process.env.TOKEN_GEN_CLIENT_SECRET, + }, + AUTHORIZATION: process.env.ED_AUTHORIZATION, + }, + CREATION_PORTAL: { + QUERY: { + username: process.env.MASTER_USER_EMAIL, + password: process.env.MASTER_USER_PWD, + grant_type: process.env.TOKEN_GEN_GRANT_TYPE, + client_id: process.env.TOKEN_GEN_CLIENT, + client_secret: process.env.TOKEN_GEN_CLIENT_SECRET, + }, + AUTHORIZATION: process.env.CREATION_PORTAL_AUTHORIZATION, + }, + }, +}; + +module.exports = { + CONFIG, +}; diff --git a/scripts/creation-portal-migration/db/dbConfig.js b/scripts/creation-portal-migration/db/dbConfig.js new file mode 100644 index 00000000..1e2eb679 --- /dev/null +++ b/scripts/creation-portal-migration/db/dbConfig.js @@ -0,0 +1,35 @@ +const { CONFIG } = require("../constant/config"); + +const mongoose = require("mongoose"); +const logger = require("../logger"); + + +const connect = async () => { + try { + const Conn = mongoose.createConnection(); + // connect to database + console.log("MONGODB_URL", CONFIG.DB.DB_HOST) + this.database = await Conn.openUri(CONFIG.DB.DB_HOST, { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + Conn.on("error", console.error.bind(console, "connection error:")); + } catch (err) { + console.log("Error While connecting to DB", err); + logger.error(`Error While connecting to DB`, err); + process.exit(); + } +}; + +const createDBInstance = async () => { + await connect(); +}; + +const getDBInstance = () => { + return this.database; +}; + +module.exports = { + createDBInstance, + getDBInstance, +}; diff --git a/scripts/creation-portal-migration/db/index.js b/scripts/creation-portal-migration/db/index.js new file mode 100644 index 00000000..b1c9d5bc --- /dev/null +++ b/scripts/creation-portal-migration/db/index.js @@ -0,0 +1,35 @@ +const { getDBInstance } = require("./dbConfig"); +const { ObjectId } = require("mongodb"); +const logger = require("../logger"); + +const findAll = async (clName, query) => { + try { + const db = await getDBInstance(); + return await db + .collection(clName) + .find({ ...query }) + .toArray(); + } catch (err) { + logger.error(`findAll Error: , ${err}`); + } +}; + +const updateById = async (clName, id, query) => { + try { + const db = await getDBInstance(); + const res = await db + .collection(clName) + .updateOne( + { _id: ObjectId(id) }, + { $set: { ...query } }, + { upsert: true } + ); + } catch (err) { + logger.error(`"updateById = ", ${id}, "Error: ", ${err}`); + } +}; + +module.exports = { + findAll, + updateById, +}; diff --git a/scripts/creation-portal-migration/index.js b/scripts/creation-portal-migration/index.js new file mode 100644 index 00000000..520bf737 --- /dev/null +++ b/scripts/creation-portal-migration/index.js @@ -0,0 +1,90 @@ +require("dotenv").config({path: "./../../.env"}); +const { createDBInstance } = require("./db/dbConfig"); +const { findAll } = require("./db"); +const { + getQuestionSetTemplates, +} = require("./template/generate/gQuestionSet.js"); + +const logger = require("./logger"); +const { CONFIG } = require("./constant/config"); + +const migrateData = async (req, res) => { + try { + + const programMigration = { + migrated: 0, + updated: 0, + published: 0, + nominated: 0, + contributor: 0, + accepted: 0, + }; + const questionSetMigration = { + migrated: 0, + hierarchy: 0, + branching: 0, + published: 0, + }; + + const migratedCount = { + totalCount: 0, + success: { + program: { + existing: { + ...programMigration, + }, + current: { + ...programMigration, + }, + }, + questionSet: { + existing: { + ...questionSetMigration, + }, + current: { + ...questionSetMigration, + }, + }, + }, + failed: { + program: { + migrated: { count: 0, ids: [] }, + updated: { count: 0, ids: [] }, + published: { count: 0, ids: [] }, + nominated: { count: 0, ids: [] }, + contributor: { count: 0, ids: [] }, + accepted: { count: 0, ids: [] }, + }, + questionSet: { + migrated: { count: 0, ids: [] }, + hierarchy: { count: 0, ids: [] }, + branching: { count: 0, ids: [] }, + published: { count: 0, ids: [] }, + }, + question: { count: 0, ids: [] } + }, + }; + const db = await createDBInstance(); + + const data = await findAll(CONFIG.DB.TABLES.solutions, { + programId: { $exists: true }, + type: { $in: ["observation", "survey"] }, + }); + + migratedCount.totalCount = data.length; + + const template = await getQuestionSetTemplates( + data, + migratedCount + ); + + logger.info(`\n migratedCount ${JSON.stringify(migratedCount)}`); + process.exit(); + } catch (err) { + logger.error(`Error while migrating : ${err}`) + + throw new Error("Error occured", err); + } +}; + +migrateData(); \ No newline at end of file diff --git a/scripts/creation-portal-migration/logger.js b/scripts/creation-portal-migration/logger.js new file mode 100644 index 00000000..8f25b11d --- /dev/null +++ b/scripts/creation-portal-migration/logger.js @@ -0,0 +1,38 @@ +var path = require("path"); +var fs = require("fs"); +var Logger = require("bunyan"); + +const date = + new Date().getDate() + + "-" + + (new Date().getMonth() + 1) + + "-" + + new Date().getFullYear(); + + var dir = __dirname + '/logs'; + + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } ; + +var logger = new Logger({ + name: "creation-portal-migration", + streams: [ + { + level: "error", + path: path.join(__dirname, `/logs/${date}-error.log`), + }, + { + level: "debug", + path: path.join(__dirname, `/logs/${date}-debug.log`), + }, + { + level: "info", + path: path.join(__dirname, `/logs/${date}-info.log`), + }, + ], +}); + + + +module.exports = logger; diff --git a/scripts/creation-portal-migration/orgDetails.js b/scripts/creation-portal-migration/orgDetails.js new file mode 100644 index 00000000..8aeb34cb --- /dev/null +++ b/scripts/creation-portal-migration/orgDetails.js @@ -0,0 +1,80 @@ +require("dotenv").config({ path: "./../../.env" }); +const { createDBInstance } = require("./db/dbConfig"); +const { findAll } = require("./db"); +const { CONFIG } = require("./constant/config"); +const { compact, uniq } = require("lodash"); +const fs = require("fs"); +const { searchUser, getOpenSaberUserOrgId } = require("./api-list/user"); + +const getUserIds = async () => { + try { + const db = await createDBInstance(); + + console.log("./../creation-portal-migration", db); + const data = await findAll(CONFIG.DB.TABLES.solutions, { + programId: { $exists: true }, + type: { $in: ["observation", "survey"] }, + }); + + const userIds = data.map((solution) => solution.author); + const solutions = data.map((solution) => { + return { + userId: solution.author, + solutionId: solution._id, + solutionName: solution.name, + programId: solution?.migrationReference?.sourcingProgramId || "", + programName: `Migrated ${solution.name}`, + }; + }); + const uniqUsers = compact([...new Set(userIds)]); + const usersList = await searchUser(uniqUsers); + const openSaberOrg = await getOpenSaberUserOrgId(); + const d = writeToCSVFile(usersList, uniqUsers, openSaberOrg, solutions); + console.log(`\n migratedCount userIds`, d); + } catch (err) { + console.log(`Error while migrating : ${err}`); + throw new Error("Error occured", err); + } +}; + +writeToCSVFile = (users, usersIdsInDb, openSaberOrg, solutions) => { + const filename = __dirname + "/SL-DataMapping.csv"; + fs.writeFile( + filename, + extractAsCSV(users, usersIdsInDb, openSaberOrg, solutions), + (err) => { + if (err) { + console.log("Error writing to csv file", err); + } else { + console.log(`saved as ${filename}`); + } + } + ); +}; + +const extractAsCSV = (users, usersIdsInDb, openSaberOrg, solutions) => { + const header = [ + `ENV,authorId,mappedUserId,userName,rootOrgId,rootOrgName,org_id,srcOrgAdminId,srcOrgAdminUserName,contributorOrgAdminId,contributorOrgAdminUserName,solutionId,solutionName,programId,programName`, + ]; + + let rows = usersIdsInDb.map((id) => { + const match = users.find((user) => user.userId === id); + const solution = solutions.find((s) => s.userId === id); + console.log("solutionsolution", solution); + const org = openSaberOrg.find((o) => o.createdBy === id); + return `STAGE,${id},${match?.userId || ""},${match?.userName || ""},${ + match?.rootOrgId || "" + },${match?.rootOrgName || ""},${org?.orgId || ""},${""},${""},${""},${""},${ + solution?.solutionId || "" + },${solution?.solutionName || ""},${solution?.programId || ""},${ + solution?.programName || "" + }`; + }); + + rows = uniq(rows); + rows = compact(rows); + const d = header.concat(rows).join("\n"); + return d; +}; + +getUserIds(); diff --git a/scripts/creation-portal-migration/template/config/question.js b/scripts/creation-portal-migration/template/config/question.js new file mode 100644 index 00000000..abdcb900 --- /dev/null +++ b/scripts/creation-portal-migration/template/config/question.js @@ -0,0 +1,307 @@ +const questionTemplate = { + date: { + name: "Migrated Question", + code: "externalId", + mimeType: "application/vnd.sunbird.question", + primaryCategory: "responseType", + interactionTypes: "responseType", + showRemarks: "showRemarks", + instructions: { + default: "tip", + }, + body: "question", + editorState: { + question: "question", + }, + responseDeclaration: { + response1: { + type: "string", + }, + }, + interactions: { + validation: "validation", + response1: { + validation: { + pattern: "dateFormat", + }, + autoCapture: "autoCapture", + }, + }, + hints: "hint", + evidence: { + mimeType: "file.type", + }, + }, + slider: { + name: "Migrated Question-Slider Type", + code: "externalId", + mimeType: "application/vnd.sunbird.question", + primaryCategory: "responseType", + interactionTypes: "responseType", + showRemarks: "showRemarks", + instructions: { + default: "tip", + }, + body: "question", + editorState: { + question: "question", + }, + responseDeclaration: { + response1: { + type: "integer", + maxScore: 1, + }, + }, + interactions: { + validation: { + required: "validation.required", + }, + response1: { + validation: { + range: { + min: "validation.min", + max: "validation.max", + }, + }, + step: "1", + }, + }, + hints: "hint", + evidence: { + mimeType: "file.type", + }, + }, + multiselect: { + name: "Migrated Question", + code: "externalId", + mimeType: "application/vnd.sunbird.question", + primaryCategory: "Multiselect Multiple Choice Question", + interactionTypes: ["choice"], + showRemarks: "showRemarks", + body: "question", + hints: "hint", + interactions: { + response1: { + type: "choice", + options: [ + { + label: "options[0]", + value: 0, + }, + { + label: "options[1]", + value: 1, + }, + { + label: "options[2]", + value: 2, + }, + { + label: "options[3]", + value: 3, + }, + { + label: "options[4]", + value: 4, + }, + ], + }, + validation: "validation", + }, + editorState: { + options: [ + { + answer: false, + value: { + body: "options[0]", + value: 0, + }, + }, + { + answer: false, + value: { + body: "options[1]", + value: 1, + }, + }, + { + answer: false, + value: { + body: "options[2]", + value: 2, + }, + }, + { + answer: false, + value: { + body: "options[3]", + value: 3, + }, + }, + { + answer: false, + value: { + body: "options[4]", + value: 4, + }, + }, + ], + question: "question", + }, + instructions: { + default: "tip", + }, + evidence: { + mimeType: "file.type", + }, + responseDeclaration: { + response1: { + maxScore: 1, + cardinality: "multiple", + type: "integer", + correctResponse: { + outcomes: { + SCORE: 1, + }, + }, + mapping: [], + }, + }, + }, + mcq: { + name: "Migrated Question", + code: "externalId", + description: "", + showRemarks: "showRemarks", + mimeType: "application/vnd.sunbird.question", + primaryCategory: "Multiselect Multiple Choice Question", + interactionTypes: ["choice"], + body: "question", + interactions: { + validation: "validation", + response1: { + type: "choice", + options: [ + { + value: 0, + label: "options[0]", + }, + { + value: 1, + label: "options[1]", + }, + ], + }, + }, + editorState: { + options: [ + { + answer: false, + value: { + body: "options[0]", + value: 0, + }, + }, + { + answer: false, + value: { + body: "options[1]", + value: 1, + }, + }, + ], + question: "question", + }, + responseDeclaration: { + response1: { + maxScore: 0, + cardinality: "single", + type: "integer", + correctResponse: { + outcomes: { + SCORE: 0, + }, + }, + }, + }, + instructions: { + default: "tip", + }, + hints: "hint", + evidence: { + mimeType: "file.type", + }, + }, + text: { + name: "Migrated Question", + code: "externalId", + mimeType: "application/vnd.sunbird.question", + primaryCategory: "Text", + interactionTypes: ["text"], + showRemarks: "showRemarks", + body: "question", + instructions: { + default: "tip", + }, + editorState: { + question: "question", + }, + responseDeclaration: { + response1: { + type: "string", + maxScore: 1, + }, + }, + interactions: { + validation: { + required: "validation.required", + }, + response1: { + validation: { + limit: { + maxLength: "100", + }, + }, + type: { + number: "validation.isNumber", + }, + }, + }, + hints: "hint", + evidence: { + mimeType: "file.type", + }, + }, + +}; + +const questionStatic = { + date: ["name", "mimeType", "responseDeclaration"], + slider: ["name", "mimeType", "responseDeclaration"], + multiselect: [ + "name", + "mimeType", + "primaryCategory", + "interactionTypes", + "responseDeclaration", + ], + mcq: [ + "name", + "mimeType", + "primaryCategory", + "interactionTypes", + "responseDeclaration", + ], + text: [ + "name", + "mimeType", + "primaryCategory", + "interactionTypes", + "responseDeclaration", + ] +}; + +module.exports = { + questionTemplate, + questionStatic, +}; diff --git a/scripts/creation-portal-migration/template/generate/gProgram.js b/scripts/creation-portal-migration/template/generate/gProgram.js new file mode 100644 index 00000000..50d6b3ea --- /dev/null +++ b/scripts/creation-portal-migration/template/generate/gProgram.js @@ -0,0 +1,386 @@ +const { isEmpty, pick, has } = require("lodash"); +const { + createProgram, + updateProgram, + publishProgram, + nominateProgram, + updateContributorToProgram, +} = require("../../api-list/program"); +const logger = require("../../logger"); +const { + getContributorAndSrcAdminData, + updateCsvFile, +} = require("../helpers/csvHelper"); +const { updateSolutionById } = require("../helpers/questionsetHelper"); + +const getDate = (increment) => { + const d = new Date( + new Date().setDate(new Date().getDate() + increment) + ).toISOString(); + + return d; +}; + +const createProgramTemplate = async (solution, program_id, migratedCount) => { + const userData = await getContributorAndSrcAdminData(solution, program_id); + + if (!userData?.srcOrgAdmin) { + return; + } + if (has(solution, 'migrationReference')) { + solution.migrationReference.sourcingProgramId = userData?.srcOrgAdmin?.programId.trim() ? userData?.srcOrgAdmin?.programId.trim() : solution?.migrationReference?.sourcingProgramId; + } else { + const programId = userData?.srcOrgAdmin?.programId.trim() ? userData?.srcOrgAdmin?.programId.trim() : solution?.migrationReference?.sourcingProgramId; + solution = { + ...solution, + migrationReference:{ + sourcingProgramId: programId + } + } + } + + const id = `${solution._id}`; + const userId = userData?.srcOrgAdmin + ? userData?.srcOrgAdmin?.srcOrgAdminId + : process.env.DEFAULT_SRC_ORG_ADMIN_TO_CREATE_PROGRAM; + const rootOrgId = userData?.srcOrgAdmin + ? userData?.srcOrgAdmin?.rootOrgId + : process.env.DEFAULT_SRC_ORG_ADMIN_ROOT_ORG_ID; + + const months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUNE", "JULY", "AUG", "SEP", "OCT", "NOV", "DEC"]; + const template = { + name: `MIGRATED ${months[new Date().getMonth()]} ${new Date().getDate()} ${new Date().getFullYear()} ${solution?.name} sourcing project`, + description: `${solution?.name} sourcing project description`, + nomination_enddate: `${getDate(1)}`, + rewards: null, + shortlisting_enddate: `${getDate(1)}`, + enddate: `${getDate(2)}`, + content_submission_enddate: `${getDate(1)}`, + type: "public", + target_type: "searchCriteria", + content_types: [], + target_collection_category: [], + sourcing_org_name: + userData?.srcOrgAdmin?.rootOrgName || + process.env.DEFAULT_USER_SRC_ORG_NAME_TO_CREATE_PROGRAM, + rootorg_id: rootOrgId, + createdby: userId, + createdOn: `${getDate(0)}`, + startdate: `${getDate(1)}`, + slug: process.env.DEFAULT_SLUG, + status: "Draft", + program_id: "", + rolemapping: [], + config: { + defaultContributeOrgReview: false, + roles: [ + { + id: 1, + name: "CONTRIBUTOR", + tabs: [1], + default: true, + defaultTab: 1, + }, + { + id: 2, + name: "REVIEWER", + tabs: [2], + defaultTab: 2, + }, + ], + }, + }; + + let programId = solution?.migrationReference?.sourcingProgramId; + + let query = {}; + + if (!program_id) { + if (isEmpty(programId)) { + programId = await createProgram(template).catch((err) => { + logger.error(`Error while creating program for solution_id: ${ + solution?._id + } Error: + ${JSON.stringify(err?.response?.data)}`); + migratedCount.failed.program.migrated.count++; + if (!migratedCount.failed.program.migrated.ids.includes(id)) { + migratedCount.failed.program.migrated.ids.push(id); + } + }); + programName = `` + programId && + (await updateCsvFile( + userData.csvData, + userData.srcOrgAdmin, + programId, + template?.name + )); + } else { + migratedCount.success.program.existing.migrated++; + } + if (isEmpty(programId)) { + return; + } + logger.info( + `Sourcing Program created for solution_id: ${solution?._id} === ${programId}` + ); + query = { ...query, "migrationReference.sourcingProgramId": programId }; + } else { + migratedCount.success.program.existing.migrated++; + } + + if (!solution?.migrationReference?.isSrcProgramUpdated) { + const update_res = await updateProgramTemplate(programId, solution); + if (!update_res) { + migratedCount.failed.program.updated.count++; + if (!migratedCount.failed.program.updated.ids.includes(id)) { + migratedCount.failed.program.updated.ids.push(id); + } + await updateSolutionDb(query, solution, migratedCount); + return; + } + logger.info( + `Sourcing Program updated for solution_id: ${solution?._id} === ${programId}` + ); + + query = { + ...query, + "migrationReference.isSrcProgramUpdated": true, + }; + } else { + migratedCount.success.program.existing.updated++; + } + + if (!solution?.migrationReference?.isSrcProgramPublished) { + const pub_res = await publishProgramTemplate(programId, solution?._id, userData.srcOrgAdmin); + + if (!pub_res) { + migratedCount.failed.program.published.count++; + if (!migratedCount.failed.program.published.ids.includes(id)) { + migratedCount.failed.program.published.ids.push(id); + } + // updateFailedCount(migratedCount, "published", solution?._id); + await updateSolutionDb(query, solution, migratedCount); + return; + } + logger.info( + `Sourcing Program published for solution_id: ${solution?._id} === ${programId}` + ); + + query = { + ...query, + "migrationReference.isSrcProgramPublished": true, + }; + } else { + migratedCount.success.program.existing.published++; + } + + if (!solution?.migrationReference?.isNominated) { + console.log(); + const res = await nominateProgram(programId, userData?.srcOrgAdmin).catch( + (err) => { + // updateFailedCount(migratedCount, "nominated", solution?._id); + migratedCount.failed.program.nominated.count++; + if (!migratedCount.failed.program.nominated.ids.includes(id)) { + migratedCount.failed.program.nominated.ids.push(id); + } + logger.error(`Error while nominating program for solution_id: ${ + solution?._id + } Error: + ${JSON.stringify(err?.response?.data)}`); + } + ); + if (!res) { + await updateSolutionDb(query, solution, migratedCount); + return; + } + logger.info( + `Sourcing Program nominated for solution_id: ${solution?._id} === ${programId}` + ); + + query = { ...query, "migrationReference.isNominated": true }; + } else { + migratedCount.success.program.existing.nominated++; + } + + if (!solution?.migrationReference?.isContributorAdded) { + const add_contri = { + program_id: programId, + user_id: + userData?.srcOrgAdmin?.contributorOrgAdminId || + process.env.DEFAULT_CONTRIBUTOR_ORG_ADMIN_ID, + rolemapping: { + CONTRIBUTOR: [ + userData?.mappedUserId || + process.env.DEFAULT_CONTRIBUTOR_USER_ID, + ], + }, + }; + + const update_nom = await updateContributorToProgram(add_contri).catch( + (err) => { + migratedCount.failed.program.contributor.count++; + if (!migratedCount.failed.program.contributor.ids.includes(id)) { + migratedCount.failed.program.contributor.ids.push(id); + } + // updateFailedCount(migratedCount, "contributor", solution?._id); + logger.error(`Error while adding contributor program for solution_id: ${ + solution?._id + } Error: + ${JSON.stringify(err?.response?.data)}`); + } + ); + + if (!update_nom) { + await updateSolutionDb(query, solution, migratedCount); + return; + } + logger.info( + `Sourcing Program added contributor for solution_id: ${solution?._id} === ${programId}` + ); + + query = { ...query, "migrationReference.isContributorAdded": true }; + } else { + migratedCount.success.program.existing.contributor++; + } + + if (!solution?.migrationReference?.isContributorAccepted) { + const accept_contri = { + program_id: programId, + user_id: + userData?.srcOrgAdmin?.mappedUserId || + process.env.DEFAULT_CONTRIBUTOR_ORG_ADMIN_ID, + status: "Approved", + updatedby: userId, + }; + const update_nom = await updateContributorToProgram(accept_contri).catch( + (err) => { + logger.error(`Error while accepting nomination to the program for solution_id: ${ + solution?._id + } Error: + ${JSON.stringify(err?.response?.data)}`); + migratedCount.failed.program.accepted.count++; + if (!migratedCount.failed.program.accepted.ids.includes(id)) { + migratedCount.failed.program.accepted.ids.push(id); + } + // updateFailedCount(migratedCount, "accepted", solution?._id); + } + ); + + if (!update_nom) { + await updateSolutionDb(query, solution, migratedCount); + return; + } + logger.info( + `Sourcing Program accepted nomination for solution_id: ${solution?._id} === ${programId}` + ); + + query = { ...query, "migrationReference.isContributorAccepted": true }; + } else { + migratedCount.success.program.existing.accepted++; + } + + if (!isEmpty(query)) { + await updateSolutionDb(query, solution, migratedCount); + } + return { programId, contributor: userData?.srcOrgAdmin }; +}; + +const updateSolutionDb = async (query, solution, migratedCount) => { + const res = await updateSolutionById({ + id: solution._id.toString(), + query: { ...query }, + }).catch((err) => { + logger.error( + `Error while updating program in solutions collection: ${solution?._id} Error: ${err}` + ); + }); + + if (query.hasOwnProperty("migrationReference.sourcingProgramId")) { + migratedCount.success.program.current.migrated++; + } + if (query.hasOwnProperty("migrationReference.isSrcProgramUpdated")) { + migratedCount.success.program.current.updated++; + } + if (query.hasOwnProperty("migrationReference.isSrcProgramPublished")) { + migratedCount.success.program.current.published++; + } + if (query.hasOwnProperty("migrationReference.isNominated")) { + migratedCount.success.program.current.nominated++; + } + if (query.hasOwnProperty("migrationReference.isContributorAdded")) { + migratedCount.success.program.current.contributor++; + } + if (query.hasOwnProperty("migrationReference.isContributorAccepted")) { + migratedCount.success.program.current.accepted++; + } +}; + +const updateProgramTemplate = async (program_id, solution) => { + const template = { + config: { + defaultContributeOrgReview: false, + roles: [ + { + id: 1, + name: "CONTRIBUTOR", + tabs: [1], + default: true, + defaultTab: 1, + }, + { + id: 2, + name: "REVIEWER", + tabs: [2], + defaultTab: 2, + }, + ], + framework: [process.env.DEFAULT_FRAMEWORK_ID], + frameworkObj: { + code: process.env.DEFAULT_FRAMEWORK_ID, + name: process.env.DEFAULT_FRAMEWORK_NAME, + type: process.env.DEFAULT_FRAMEWORK_TYPE, + identifier: process.env.DEFAULT_FRAMEWORK_ID, + }, + sharedContext: [], + }, + targetprimarycategories: [ + { + identifier: "obj-cat:observation_questionset_all", + name: "Observation", + targetObjectType: "QuestionSet", + }, + { + identifier: "obj-cat:survey_questionset_all", + name: "Survey", + targetObjectType: "QuestionSet", + }, + ], + targetprimarycategorynames: ["Observation", "Survey"], + program_id: program_id, + }; + + const upd_res = await updateProgram(template).catch((err) => { + logger.error(`Error while updating program for solution_id: ${ + solution?._id + } Error: + ${JSON.stringify(err?.response?.data)}`); + }); + return upd_res; +}; + +const publishProgramTemplate = async (program_id, id, contributor) => { + const template = { + channel: process.env.DEFAULT_SLUG, + program_id: program_id, + }; + return await publishProgram(template).catch((err) => { + logger.error(`Error while publishing program for solution_id: ${id} Error: + ${JSON.stringify(err?.response?.data)}`); + }); +}; + +module.exports = { + createProgramTemplate, + publishProgramTemplate, +}; diff --git a/scripts/creation-portal-migration/template/generate/gQuestion.js b/scripts/creation-portal-migration/template/generate/gQuestion.js new file mode 100644 index 00000000..65d7ddce --- /dev/null +++ b/scripts/creation-portal-migration/template/generate/gQuestion.js @@ -0,0 +1,284 @@ +const { questionTemplate, questionStatic } = require("../config/question"); + +const getQBodyParagraph = (questionData) => { + return questionData + .map((data) => { + return `

${data}

`; + }) + .join(""); +}; + +const getQBodyDiv = (questionData) => { + const divs = questionData + .map((data) => { + return `

${data} 

`; + }) + .join(""); + const div = `
${divs}
`; + return div; +}; + +const getDateTemplate = (question) => { + const template = {}; + console.log("getDate"); + + for (let key in questionTemplate.date) { + const keyL = key.toLowerCase(); + if (questionStatic.date.includes(key)) { + template[key] = questionTemplate.date[key]; + } else if (keyL === "interactiontypes") { + template[key] = [question[questionTemplate.date[key]]]; + } else if (keyL === "body") { + template[key] = getQBodyParagraph(question[questionTemplate.date[key]]); + } else if (keyL === "editorstate") { + template[key] = { + question: getQBodyParagraph(question[questionTemplate.date["body"]]), + }; + } else if (keyL === "interactions") { + template[key] = { + validation: { + required: question["validation"]["required"] ? 'Yes' : 'No', + }, + response1: { + validation: { + pattern: question["dateFormat"], + }, + autoCapture: question["autoCapture"], + }, + }; + } else if (keyL === "evidence") { + template[key] = question["file"] + ? { ...question["file"], mimeType: question["file"]["type"] } + : { mimeType: [] }; + } else if (keyL === "instructions") { + template[key] = { default: question["tip"] }; + } else if (keyL === 'showremarks') { + template[key] = question[questionTemplate.date[key]] === true ? 'Yes' : 'No'; + } + else { + template[key] = question[questionTemplate.date[key]] || ""; + } + } + + return template; +}; + +const getSliderTemplate = (question) => { + const template = {}; + console.log("getSlider"); + + for (let key in questionTemplate.slider) { + const keyL = key.toLowerCase(); + if (questionStatic.slider.includes(key)) { + template[key] = questionTemplate.slider[key]; + } else if (keyL === "interactiontypes") { + template[key] = [question[questionTemplate.slider[key]]]; + } else if (keyL === "body") { + template[key] = getQBodyParagraph(question[questionTemplate.slider[key]]); + } else if (keyL === "editorstate") { + template[key] = { + question: getQBodyParagraph(question[questionTemplate.slider["body"]]), + }; + } else if (keyL === "interactions") { + template[key] = { + validation: { + required: question["validation"]["required"] ? 'Yes' : 'No', + }, + response1: { + validation: { + range: { + min: question["validation"]["min"], + max: question["validation"]["max"], + }, + }, + step: "1", + }, + }; + } else if (keyL === "evidence") { + template[key] = question["file"] + ? {...question["file"], mimeType: question["file"]["type"] } + : { mimeType: [] }; + } else if (keyL === "instructions") { + template[key] = { default: question["tip"] }; + } else if (keyL === 'showremarks') { + template[key] = question[questionTemplate.date[key]] === true ? 'Yes' : 'No'; + } else { + template[key] = question[questionTemplate.slider[key]] || ""; + } + } + return template; +}; + +const getOptions = (options) => { + options.map((values, index) => { + + values.value = `${values?.value}`; + values.label = `${values.label}`; + }); + return options; +}; + +const getEditorOptions = (options) => { + const data = options.map((values, index) => { + return { + answer: false, + value: { + body: `

${values.label}

`, + value: index, + }, + }; + }); + return data; +}; + +const getMSMCQTemplate = (question) => { + const template = {}; + + console.log("getMSMCQ"); + + + for (let key in questionTemplate.multiselect) { + const keyL = key.toLowerCase(); + if (questionStatic.multiselect.includes(key)) { + template[key] = questionTemplate.multiselect[key]; + } else if (keyL === "interactiontypes") { + template[key] = [question[questionTemplate.multiselect[key]]]; + } else if (keyL === "body") { + template[key] = getQBodyDiv(question[questionTemplate.multiselect[key]]); + } else if (keyL === "editorstate") { + template[key] = { + question: getQBodyDiv(question[questionTemplate.multiselect["body"]]), + options: getEditorOptions(question["options"]), + }; + } else if (keyL === "interactions") { + template[key] = { + validation: { + required: question["validation"]["required"] ? 'Yes' : 'No', + }, + response1: { + type: "choice", + options: getOptions(question["options"]), + }, + }; + } else if (keyL === "evidence") { + template[key] = question["file"] + ? { ...question["file"], mimeType: question["file"]["type"] } + : { mimeType: [] }; + } else if (keyL === "instructions") { + template[key] = { default: question["tip"] }; + } else if (keyL === 'showremarks') { + template[key] = question[questionTemplate.date[key]] === true ? 'Yes' : 'No'; + } else { + template[key] = question[questionTemplate.multiselect[key]] || ""; + } + } + + return template; +}; + +const getMCQTemplate = (question) => { + const template = {}; + console.log(); + console.log("getMcq", JSON.stringify(questionTemplate.mcq)); + console.log(); + + for (let key in questionTemplate.mcq) { + const keyL = key.toLowerCase(); + if (questionStatic.mcq.includes(key)) { + template[key] = questionTemplate.mcq[key]; + } else if (keyL === "interactiontypes") { + template[key] = [question[questionTemplate.mcq[key]]]; + } else if (keyL === "body") { + template[key] = getQBodyDiv(question[questionTemplate.mcq[key]]); + } else if (keyL === "editorstate") { + template[key] = { + question: getQBodyDiv(question[questionTemplate.mcq["body"]]), + options: getEditorOptions(question["options"]), + }; + } else if (keyL === "interactions") { + template[key] = { + validation: { + required: question["validation"]["required"] ? 'Yes' : 'No', + }, + response1: { + type: "choice", + options: getOptions(question["options"]), + }, + }; + } else if (keyL === "evidence") { + template[key] = question["file"] + ? { ...question["file"], mimeType: question["file"]["type"] } + : { mimeType: [] }; + } else if (keyL === "instructions") { + template[key] = { default: question["tip"] }; + } else if (keyL === 'showremarks') { + template[key] = question[questionTemplate.date[key]] === true ? 'Yes' : 'No'; + }else { + template[key] = question[questionTemplate.mcq[key]] || ""; + } + } + + return template; +}; + +const getTextTemplate = (question, type) => { + const template = {}; + console.log("getText"); + + + for (let key in questionTemplate.text) { + const keyL = key.toLowerCase(); + if (questionStatic.text.includes(key)) { + template[key] = questionTemplate.text[key]; + } else if (keyL === "interactiontypes") { + template[key] = [question[questionTemplate.text[key]]]; + } else if (keyL === "body") { + template[key] = getQBodyParagraph(question[questionTemplate.text[key]]); + } else if (keyL === "editorstate") { + template[key] = { + question: getQBodyParagraph(question[questionTemplate.text["body"]]), + }; + } else if (keyL === "interactions") { + template[key] = { + validation: { + required: question["validation"]["required"] ? 'Yes' : 'No', + }, + response1: { + validation: { + limit: { + maxLength: "100", + }, + }, + type: { + number: + type === "text" + ? "No" + : question["validation"]["IsNumber"] + ? "Yes" + : "No", + }, + }, + }; + } else if (keyL === "evidence") { + template[key] = question["file"] + ? { ...question["file"], mimeType: question["file"]["type"] } + : { mimeType: [] }; + } else if (keyL === "instructions") { + template[key] = { default: question["tip"] }; + } else if (keyL === 'showremarks') { + template[key] = question[questionTemplate.date[key]] === true ? 'Yes' : 'No'; + }else { + template[key] = question[questionTemplate.text[key]] || ""; + } + } + return template; +}; + + +module.exports = { + getDateTemplate, + getSliderTemplate, + getMSMCQTemplate, + getTextTemplate, + getMCQTemplate, +}; diff --git a/scripts/creation-portal-migration/template/generate/gQuestionSet.js b/scripts/creation-portal-migration/template/generate/gQuestionSet.js new file mode 100644 index 00000000..c477c402 --- /dev/null +++ b/scripts/creation-portal-migration/template/generate/gQuestionSet.js @@ -0,0 +1,239 @@ +const { ObjectId } = require("mongodb"); +const { createQuestionSet } = require("../../api-list/question"); + +const { CONFIG } = require("./../../constant/config"); +const { findAll, updateById } = require("../../db"); +const logger = require("../../logger"); +const { updateHierarchyTemplate } = require("../helpers/hierarchyHelper"); +const { setQuestionSetTemplate } = require("../helpers/questionsetHelper"); +const { createProgramTemplate } = require("./gProgram"); +const { getCriteriaData, initHierarchy } = require("../migrate/common"); +const { createSection } = require("../migrate/matrix"); +const { getNonMatrixQuestions } = require("../migrate/nonmatrix"); + +const getQuestionSetTemplates = async (solutions, migratedCount) => { + const data = []; + // solutions.map(async (solution) => { + for (let solution of solutions) { + let programId = solution?.migrationReference?.sourcingProgramId; + const programData = await createProgramTemplate( + solution, + programId, + migratedCount + ).catch(error => { + console.log("Errror", error); + }); + programId = programData?.programId; + solution.author = programData?.contributor?.mappedUserId ? programData?.contributor?.mappedUserId : solution.author; + logger.debug( + `-----------------------sourcingProgramId---------------------- + ${programId}` + ); + // if (!programId) { + // return; + // } + // data.push(programId) + // return; + if (programId) { + data.push(await migrateQuestionset(solution, programId, migratedCount, programData?.contributor)); + } + // }) + } + + return data; +}; + +const migrateQuestionset = async (solution, programId, migratedCount, contributor) => { + logger.debug( + `-----------------------migrateQuestionset---------------------- + ${programId}` + ); + let templateData = setQuestionSetTemplate(solution, programId, contributor); + const questionSetId = solution?._id.toString(); + + let questionSetMigratedId = solution.referenceQuestionSetId; + + if (questionSetMigratedId) { + migratedCount.success.questionSet.existing.migrated++; + } else { + questionSetMigratedId = await createQuestionSet(templateData).catch( + (err) => { + logger.error(`migrateQuestionset: Error while creating Questionset for solution_id: ${questionSetId} Error: + ${JSON.stringify(err?.response?.data)}`); + if (!migratedCount.failed.questionSet.migrated.ids.includes(questionSetId)) { + migratedCount.failed.questionSet.migrated.count++; + migratedCount.failed.questionSet.migrated.ids.push(questionSetId); + } + } + ); + + logger.info( + `migrateQuestionset: questionSetMigratedId: + ${questionSetMigratedId}` + ); + + + if (!questionSetMigratedId) { + return; + } + + await updateById(CONFIG.DB.TABLES.solutions, questionSetId, { + referenceQuestionSetId: questionSetMigratedId, + }).catch((err) => { + logger.error( + `migrateQuestionset: Error while updating solution referenceQuestionSetId: + ${err}` + ); + + }); + + migratedCount.success.questionSet.current.migrated++; + } + + let hierarchy = initHierarchy( + questionSetId, + solution, + programId, + questionSetMigratedId + ); + let matrixHierarchy = { criterias: [] }; + + let data = await migrateCriteriaQuestions( + solution, + hierarchy, + matrixHierarchy, + migratedCount + ); + + for (let i = 0; i < data.matrixHierarchy.criterias.length; i++) { + const cri = data.matrixHierarchy.criterias[i]; + data.hierarchy.criterias.push(cri); + } + + + await updateHierarchyTemplate( + data.hierarchy, + solution, + programId, + migratedCount + ); + + return data.hierarchy; +}; + +const migrateCriteriaQuestions = async ( + solution, + hierarchy, + matrixHierarchy, + migratedCount +) => { + logger.debug( + `migrateCriteriaQuestions: ${solution?._id}` + ); + + let criteriaIds = solution?.themes[0]?.criteria || []; + criteriaIds = criteriaIds.map((criteria) => ObjectId(criteria?.criteriaId)); + const criterias = await findAll(CONFIG.DB.TABLES.criteria_questions, { + _id: { $in: criteriaIds }, + }).catch((err) => {}); + + for (let i = 0; i < criterias.length; i++) { + const criteria = criterias[i]; + let questionIds = criteria?.evidences[0].sections[0]?.questions || []; + questionIds = questionIds.map((question) => question?._id); + + const criteriaQuestions = await findAll(CONFIG.DB.TABLES.questions, { + _id: { $in: questionIds }, + }).catch((err) => {}); + + hierarchy.criterias[i] = getCriteriaData(criteria, solution?.type); + + logger.info( + `migrateCriteriaQuestions: --------------------criteria---------------------- ${criteria?.name}` + ); + + const data = await migrateQuestions( + (type = solution?.type), + criteriaQuestions, + hierarchy, + matrixHierarchy, + migratedCount, + (index = i), + (criteriaId = criteria?._id.toString()) + ); + + hierarchy = data.hierarchy; + matrixHierarchy = data.matrixHierarchy; + } + return { hierarchy, matrixHierarchy }; +}; + +const migrateQuestions = async ( + type, + questions, + hierarchy, + matrixHierarchy, + migratedCount, + index, + criteriaId +) => { + let matrixQuestions = {}; + let nonMatrixQuestions = []; + + + logger.info( + `migrateQuestions: criteria:${criteriaId} questions: ${questions.length} ` + ); + + for (let i = 0; i < questions.length; i++) { + const question = questions[i]; + + + logger.info( + `migrateQuestions: criteria:${criteriaId} question: ${question?._id} question responseType: ${question?.responseType} ` + ); + + + if (question?.responseType === "matrix") { + + + const data = await createSection( + type, + matrixHierarchy, + matrixQuestions, + questions, + criteriaId, + question, + migratedCount + ); + matrixQuestions = data.matrixQuestions; + matrixHierarchy = data.matrixHierarchy; + questions = data.questions; + + } else { + const data = await getNonMatrixQuestions( + question, + questions, + nonMatrixQuestions, + matrixQuestions, + matrixHierarchy, + hierarchy, + index, + type, + migratedCount, + criteriaId + ); + + hierarchy = data.hierarchy; + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + nonMatrixQuestions = data.nonMatrixQuestions; + questions = data.questions; + } + } + return { hierarchy, matrixHierarchy }; +}; + +module.exports = { + getQuestionSetTemplates, +}; diff --git a/scripts/creation-portal-migration/template/generate/template.js b/scripts/creation-portal-migration/template/generate/template.js new file mode 100644 index 00000000..8257873e --- /dev/null +++ b/scripts/creation-portal-migration/template/generate/template.js @@ -0,0 +1,41 @@ +const getSectionTemplate = (section) => { + return { + _id: section._id, + __v: 0, + concepts: [], + createdAt: section?.createdAt, + createdFor: [], + criteriaType: "manual", + description: "Matrix section description", + evidences: [ + { + code: "OB", + sections: [ + { + code: "S1", + questions: [], + }, + ], + }, + ], + externalId: section?.externalId, + flag: "", + frameworkCriteriaId: "", + keywords: ["Keyword 1", "Keyword 2"], + language: ["English"], + name: "Matrix Section", + owner: "", + remarks: "", + resourceType: ["Program", "Framework", "Criteria"], + score: "", + showRemarks: null, + timesUsed: "", + updatedAt: section?.updatedAt, + weightage: "", + referenceQuestionSetId: null, + }; +}; + +module.exports = { + getSectionTemplate, +}; diff --git a/scripts/creation-portal-migration/template/helpers/csvHelper.js b/scripts/creation-portal-migration/template/helpers/csvHelper.js new file mode 100644 index 00000000..a9d0a8e1 --- /dev/null +++ b/scripts/creation-portal-migration/template/helpers/csvHelper.js @@ -0,0 +1,95 @@ +const { pick } = require("lodash"); + +const { searchUser } = require("../../api-list/user"); + +const fs = require("fs"); +let { parse } = require("csv-parse"); +const csvtojson = require("csvtojson"); +const path = require("path"); +const { dirname } = require("path"); + + +const getCsvData = async (solution) => { + const filename = path.resolve(dirname("creation-portal-migration")) + "/SL-DataMapping.csv"; + console.log("fulasvnbsvfbndvfd", filename); + let srcOrgAdmin = []; + return new Promise(async (resolve, reject) => { + const data = []; + let index = 0; + fs.createReadStream(filename) + .pipe(parse()) + .on("error", (error) => { + reject(error); + }) + .on("data", (row) => { + index = data.length; + index === 0 && srcOrgAdmin.push(row); + data.push(row); + const csvUserIndex = data[0].indexOf("authorId"); + const csvUserId = row[csvUserIndex]; + const pIndex = data[0].indexOf("programId"); + + if (index > 0) { + if (solution.author === csvUserId) { + srcOrgAdmin.push(row); + if (!row[pIndex]) { + row[pIndex] = + solution?.migrationReference?.sourcingProgramId || ""; + } + } + } + }) + .on("end", () => { + const header = data; + const d = header.join("\n"); + srcOrgAdmin = srcOrgAdmin.join("\n"); + fs.writeFileSync(filename, d, (err) => { + if (err) { + reject(err); + } + }); + resolve({ data: d, srcOrgAdmin }); + }); + }); +}; + +const updateCsvFile = async (csvData = [], columnToUpdate, programId, programName) => { + const filename = __dirname + "/SL-DataMapping.csv"; + const data = await csvtojson().fromString(csvData); + + let header = Object.keys(data[0]); + const csvD = []; + data.forEach((d) => { + d?.rootOrgId === columnToUpdate?.rootOrgId && (d.programId = programId, d.programName=programName); + csvD.push(Object.values(d)); + }); + + csvD.unshift(header); + const d = csvD.join("\n"); + console.log(); + console.log(); + + fs.writeFileSync(filename, d, (err) => { + if (err) { + console.log("errororor", err); + } + }); +}; + +const getContributorAndSrcAdminData = async (solution, program_id) => { + // const userData = await searchUser(solution.author).catch((error) => { + // console.log("Error", error); + // }); + // const contributor = pick(userData[0], ["userId", "userName", "rootOrgId"]); + // contributor.rootOrgId = "01329314824202649627"; + // const csv = await getCsvData(solution, contributor?.rootOrgId); + const csv = await getCsvData(solution); + const srcOrgAdmin = await csvtojson().fromString(csv.srcOrgAdmin); + return { csvData: csv.data, srcOrgAdmin: srcOrgAdmin[0] }; +}; + +module.exports = { + getCsvData, + updateCsvFile, + getContributorAndSrcAdminData, +}; diff --git a/scripts/creation-portal-migration/template/helpers/hierarchyHelper.js b/scripts/creation-portal-migration/template/helpers/hierarchyHelper.js new file mode 100644 index 00000000..c40a412a --- /dev/null +++ b/scripts/creation-portal-migration/template/helpers/hierarchyHelper.js @@ -0,0 +1,535 @@ +const { + pick, + findIndex, + get, + compact, + find, + omit, + isArray, + uniq, +} = require("lodash"); +const { + publishQuestionSet, + updateQuestionSetHierarchy, + readQuestionSetHierarchy, +} = require("../../api-list/question"); +const { CONFIG } = require("./../../constant/config"); +const { updateById } = require("../../db"); +const logger = require("../../logger"); + +const updateHierarchyChildren = ( + hierarchy, + referenceQuestionId, + index, + question +) => { + logger.debug( + `updateHierarchyChildren: referenceQuestionId = ${referenceQuestionId}` + ); + + if ( + referenceQuestionId && + !hierarchy.criterias[index].questions.includes(referenceQuestionId) + ) { + hierarchy.criterias[index].questions.push(referenceQuestionId); + } + + if (question?.page) { + const page = question?.page ? question?.page?.trim() : "" + if ( + hierarchy.criterias[index].pageQuestions.hasOwnProperty(page) + ) { + if ( + !hierarchy.criterias[index].pageQuestions[page].includes( + referenceQuestionId + ) + ) { + hierarchy.criterias[index].pageQuestions[page].push( + referenceQuestionId + ); + } + } else { + hierarchy.criterias[index].pageQuestions[page] = [ + referenceQuestionId, + ]; + } + } + + return hierarchy; +}; + +const getOperator = (visibleIf) => { + const operator = + visibleIf.operator === "===" + ? "eq" + : visibleIf.operator === "!==" || visibleIf.operator === "!=" + ? "ne" + : ""; + + return operator; +}; + +const getPrecondition = (visible, parentId, parentQuestion) => { + logger.debug( + `getPrecondition: parentId = ${parentId}; visible: ${JSON.stringify( + visible + )}` + ); + return { + and: [ + { + [getOperator(visible)]: [ + { + var: `${parentId}.response1.value`, + type: "interactions", + }, + [findIndex(parentQuestion.options, { + value: isArray(visible?.value) ? visible?.value[0] : visible?.value, + })], + ], + }, + ], + }; +}; + +const updateHierarchyTemplate = async ( + hierarchy, + solution, + programId, + migratedCount +) => { + // console.log("updateHierarchyTemplate", JSON.stringify(hierarchy)); + await updateCriteriasList(hierarchy, solution, programId, migratedCount); +}; + +const branchingQuestionSetHierarchy = async (hierarchy, newCriterias) => { + + logger.debug("branchingQuestionSetHierarchy", JSON.stringify(hierarchy)); + + + let questionSetHierarchy = {}; + if (hierarchy.questionset && hierarchy.isHierarchyUpdated) { + questionSetHierarchy = await readQuestionSetHierarchy( + hierarchy?.questionset + ).catch(err => { + console.log("Error", err); + return; + }); + console.log("questionset", hierarchy.questionset ) + logger.info(`${"questionset", hierarchy.questionset, "questionSetHierarchy", questionSetHierarchy }`) + } + + const updateHierarchyData = { + request: { + data: { + nodesModified: {}, + hierarchy: { + [hierarchy.questionset]: { + children: [], + root: true, + }, + }, + }, + }, + }; + + + for (let i = 0; i < newCriterias.length; i++) { + const criteria = newCriterias[i]; + const hierarchyData = find(questionSetHierarchy.children, { + name: criteria?.name, + }); + criteria.referenceQuestionSetId = + hierarchy.questionset && hierarchy.isHierarchyUpdated + ? hierarchyData?.identifier + : criteria.referenceQuestionSetId; + if (criteria?.referenceQuestionSetId) { + const metadata = pick(criteria, [ + "code", + "name", + "description", + "mimeType", + "primaryCategory", + "allowMultipleInstances", + "instances", + ]); + updateHierarchyData.request.data.nodesModified[ + criteria.referenceQuestionSetId + ] = { + metadata: { + ...metadata, + allowBranching: "Yes", + branchingLogic: get(criteria, "branchingLogic") || {}, + }, + objectType: "QuestionSet", + root: false, + isNew: false, + }; + updateHierarchyData.request.data.hierarchy[ + hierarchy.questionset + ].children.push(criteria.referenceQuestionSetId); + + updateHierarchyData.request.data.hierarchy[ + criteria.referenceQuestionSetId + ] = { + children: compact(criteria.questions), + root: false, + }; + } + } + + + updateHierarchyData.request.data.hierarchy[hierarchy.questionset].children = uniq(updateHierarchyData.request.data.hierarchy[hierarchy.questionset].children); + return updateHierarchyData; +}; + +const updateSolutionsDb = async ( + query, + referenceQuestionsetId, + migratedCount +) => { + const res = await updateById( + CONFIG.DB.TABLES.solutions, + referenceQuestionsetId, + query + ).catch((err) => { + logger.error( + `Error while updating questionset in solutions collection: ${solution?._id}` + ); + }); + + if (query.hasOwnProperty("migrationReference.isHierarchyUpdated")) { + migratedCount.success.questionSet.current.hierarchy++; + } + if (query.hasOwnProperty("migrationReference.isBranchingUpdated")) { + migratedCount.success.questionSet.current.branching++; + } + if (query.hasOwnProperty("migrationReference.isPublished")) { + migratedCount.success.questionSet.current.published++; + } +}; + +const updateCriteriasList = async ( + hierarchy, + solution, + programId, + migratedCount +) => { + logger.debug( + `updateHierarchyTemplate: programId = ${programId}; solution: ${solution?._id}` + ); + const updateHierarchyData = { + request: { + data: { + nodesModified: {}, + hierarchy: { + [hierarchy.questionset]: { + children: [], + root: true, + }, + }, + }, + }, + }; + + + let pageSections = {}; + const newCriterias = []; + + for (let i = 0; i < hierarchy.criterias.length; i++) { + let criteria = hierarchy.criterias[i]; + const pageKeys = Object.keys(criteria.pageQuestions) || []; + const branchingKeys = Object.keys(criteria.branchingLogic) || []; + let questionsCopy = []; + if (!criteria.isMatrix) { + questionsCopy = criteria.questions; + for (let index = 0; index < criteria.questions.length; index++) { + const qId = criteria.questions[index]; + if (branchingKeys.includes(qId)) { + if (criteria.branchingLogic[qId].target.length > 0) { + const data = updatePageData( + pageKeys, + criteria, + pageSections, + questionsCopy, + qId, + qId, + true + ); + questionsCopy = data.questionsCopy; + pageSections = data.pageSections; + criteria = data.criteria; + } else { + const parentId = criteria.branchingLogic[qId].source[0]; + const data = updatePageData( + pageKeys, + criteria, + pageSections, + questionsCopy, + parentId, + qId, + true + ); + questionsCopy = data.questionsCopy; + pageSections = data.pageSections; + criteria = data.criteria; + } + } else { + const data = updatePageData( + pageKeys, + criteria, + pageSections, + questionsCopy, + qId, + qId, + false + ); + questionsCopy = data.questionsCopy; + pageSections = data.pageSections; + criteria = data.criteria; + } + } + // console.log("questionscioy", questionsCopy.length, criteria?.name, criteria?.branchingLogic) + if (questionsCopy.length > 0) { + criteria.questions = questionsCopy; + newCriterias.push(criteria); + } + } else { + newCriterias.push(criteria); + } + } + + const pageSectionKeys = Object.keys(pageSections); + for ( + let pageSectionIndex = 0; + pageSectionIndex < pageSectionKeys.length; + pageSectionIndex++ + ) { + // console.log(); + // console.log( + // "pageSectionkeys", + // pageSectionKeys, + // pageSections[pageSectionIndex] + // ); + // console.log(); + + newCriterias.push(pageSections[pageSectionKeys[pageSectionIndex]]); + } + + for (let section = 0; section < newCriterias.length; section++) { + const sectionData = newCriterias[section]; + const metadata = pick(sectionData, [ + "code", + "name", + "description", + "mimeType", + "primaryCategory", + "allowMultipleInstances", + "instances", + ]); + updateHierarchyData.request.data.nodesModified[sectionData.name] = { + metadata: { + ...metadata, + }, + objectType: "QuestionSet", + root: false, + isNew: true, + }; + updateHierarchyData.request.data.hierarchy[ + hierarchy.questionset + ].children.push(sectionData?.name); + + updateHierarchyData.request.data.hierarchy[sectionData.name] = { + children: compact(sectionData.questions), + root: false, + }; + } + + logger.info( + `updateHierarchyTemplate: Hierarchydata = ${JSON.stringify( + updateHierarchyData + )}` + ); + + const questionsetId = hierarchy.questionsetDbId; + let query = {}; + if (!hierarchy.isHierarchyUpdated) { + updateHierarchyData.request.data.hierarchy[hierarchy.questionset].children = uniq(updateHierarchyData.request.data.hierarchy[hierarchy.questionset].children); + const result = await updateQuestionSetHierarchy(updateHierarchyData).catch( + (err) => { + logger.error(`Error while updating the questionset for solution_id: ${questionsetId} Error: + ${JSON.stringify(err.response.data)}`); + + if ( + !migratedCount.failed.questionSet.hierarchy.ids.includes( + hierarchy?.questionset + ) + ) { + migratedCount.failed.questionSet.hierarchy.count++; + migratedCount.failed.questionSet.hierarchy.ids.push( + hierarchy?.questionset + ); + } + } + ); + + if (!result) { + await updateSolutionsDb(query, questionsetId, migratedCount); + return; + } + query = { + ...query, + "migrationReference.isHierarchyUpdated": true, + }; + + for (let i = 0; i < newCriterias.length; i++) { + const criterias = newCriterias[i]; + newCriterias[i].referenceQuestionSetId = result[criterias.name]; + } + } else { + migratedCount.success.questionSet.existing.hierarchy++; + } + + if (!hierarchy.isBranchingUpdated) { + const branchinghierarchy = await branchingQuestionSetHierarchy( + hierarchy, + newCriterias + ); + + const result = await updateQuestionSetHierarchy(branchinghierarchy).catch( + (err) => { + logger.error(`Error while updating the questionset branching for solution_id: ${questionsetId} Error: + ${JSON.stringify(err.response.data)}`); + + if ( + !migratedCount.failed.questionSet.branching.ids.includes( + hierarchy?.questionset + ) + ) { + migratedCount.failed.questionSet.branching.count++; + migratedCount.failed.questionSet.branching.ids.push( + hierarchy?.questionset + ); + } + } + ); + + if (!result) { + await updateSolutionsDb(query, questionsetId, migratedCount); + return; + } + query = { + ...query, + "migrationReference.isBranchingUpdated": true, + }; + } else { + migratedCount.success.questionSet.existing.branching++; + } + + if (!hierarchy.isPublished) { + const res = await publishQuestionSet(hierarchy.questionset).catch((err) => { + logger.error(`Error while publishing the questionset for solution_id: ${questionsetId} === ${ + hierarchy?.questionset + } Error: + ${JSON.stringify(err.response.data)}`); + + if ( + !migratedCount.failed.questionSet.published.ids.includes( + hierarchy?.questionset + ) + ) { + migratedCount.failed.questionSet.published.count++; + + migratedCount.failed.questionSet.published.ids.push( + hierarchy?.questionset + ); + } + }); + if (!res) { + await updateSolutionsDb(query, questionsetId, migratedCount); + return; + } + query = { + ...query, + "migrationReference.isPublished": true, + }; + } else if (hierarchy.isPublished) { + migratedCount.success.questionSet.existing.published++; + } + const res = await updateSolutionsDb(query, questionsetId, migratedCount); +}; + +const updatePageData = ( + pageKeys, + criteria, + pageSections, + questionsCopy, + idInPages, + idToAdd, + isBranching +) => { + let pageName = ""; + for (let page = 0; page < pageKeys.length; page++) { + pageName = criteria.pageQuestions[pageKeys[page]].includes(idInPages) + ? pageKeys[page].trim() + : pageName.trim(); + } + if (pageName && pageSections.hasOwnProperty(pageName)) { + if (!pageSections[pageName].questions.includes(idToAdd)) { + pageSections[pageName].questions.push(idToAdd); + questionsCopy = questionsCopy.filter((id) => id !== idToAdd); + } else { + questionsCopy = questionsCopy.filter((id) => id !== idToAdd); + } + } else if (pageName && !pageSections.hasOwnProperty(pageName)) { + questionsCopy = questionsCopy.filter((id) => id !== idToAdd); + pageSections[pageName] = { + questions: [idToAdd], + referenceQuestionSetId: "", + criDbId: "", + code: criteria?.code, + name: `Page ${pageName}`, + description: `Description ${pageName}`, + mimeType: "application/vnd.sunbird.questionset", + primaryCategory: "observation", + allowMultipleInstances: "", + instances: {}, + branchingLogic: {}, + isMatrix: false, + }; + } + + if (pageName && isBranching) { + const branching = criteria.branchingLogic[idToAdd]; + + if (!pageSections[pageName].branchingLogic.hasOwnProperty(idToAdd)) { + pageSections[pageName].branchingLogic = { + ...pageSections[pageName].branchingLogic, + [idToAdd]: {...branching}, + }; + delete criteria.branchingLogic[idToAdd]; + } + + for (let target=0; target < branching.target.length; target++) { + + if (!pageSections[pageName].branchingLogic.hasOwnProperty(idToAdd)) { + pageSections[pageName].branchingLogic = { + ...pageSections[pageName].branchingLogic, + [branching.target[target]]: criteria.branchingLogic[branching.target[target]] , + }; + delete criteria.branchingLogic[branching.target[target]]; + } + } + + } + + return { questionsCopy, pageSections, criteria }; +}; + +module.exports = { + updateHierarchyChildren, + updateHierarchyTemplate, + branchingQuestionSetHierarchy, + getOperator, + getPrecondition, +}; diff --git a/scripts/creation-portal-migration/template/helpers/questionsetHelper.js b/scripts/creation-portal-migration/template/helpers/questionsetHelper.js new file mode 100644 index 00000000..09e637b5 --- /dev/null +++ b/scripts/creation-portal-migration/template/helpers/questionsetHelper.js @@ -0,0 +1,158 @@ +const { capitalize, isEmpty, get } = require("lodash"); +const { ObjectId } = require("mongodb"); +const { createQuestions, publishQuestion } = require("../../api-list/question"); +const { CONFIG } = require("./../../constant/config"); +const { updateById, findAll } = require("../../db"); +const logger = require("../../logger"); +const { + getDateTemplate, + getSliderTemplate, + getMSMCQTemplate, + getMCQTemplate, + getTextTemplate, +} = require("../generate/gQuestion"); + +const setQuestionSetTemplate = (solution, programId, contributor) => { + let templateData = { + name: solution?.name, + description: solution?.description, + code: solution?.externalId, + mimeType: "application/vnd.sunbird.questionset", + primaryCategory: solution?.type, + entityType: capitalize(solution?.entityType), + language: solution?.language, + keywords: solution?.keywords, + startDate: solution?.startDate, + endDate: solution?.endDate, + createdBy: + solution?.author || process.env.DEFAULT_CONTRIBUTOR_USER_ID, + organisationId: + contributor?.org_id || process.env.DEFAULT_SRC_ORG_ADMIN_ORG_ID, + creator: contributor?.userName || process.env.DEFAULT_CONTRIBUTOR_USER_NAME, + createdFor: [ + contributor?.rootOrgId || process.env.DEFAULT_SRC_ORG_ADMIN_ROOT_ORG_ID, + ], + channel: + contributor?.rootOrgId || process.env.DEFAULT_SRC_ORG_ADMIN_ROOT_ORG_ID, + programId: programId, + author: contributor?.userName || process.env.DEFAULT_CONTRIBUTOR_USER_NAME, + framework: process.env.DEFAULT_FRAMEWORK_ID, + }; + + return templateData; +}; + +const createQuestionTemplate = async (question, migratedCount) => { + + const type = question?.responseType; + let referenceQuestionId = question?.referenceQuestionId; + let query = {}; + let questionToMigrate = {}; + + let isPublished = question?.migrationReference?.isPublished; + + if (type && !referenceQuestionId) { + if (type.toLowerCase() === "date") { + questionToMigrate = getDateTemplate(question); + } + if (type.toLowerCase() === "slider") { + questionToMigrate = getSliderTemplate(question); + } + if (type.toLowerCase() === "multiselect") { + questionToMigrate = getMSMCQTemplate(question); + } + if (type.toLowerCase() === "radio") { + questionToMigrate = getMCQTemplate(question); + } + if (type.toLowerCase() === "text" || type.toLowerCase() === "number") { + questionToMigrate = getTextTemplate(question, type); + } + + if (!isEmpty(questionToMigrate)) { + referenceQuestionId = await createQuestions( + questionToMigrate, + question._id + ); + question.referenceQuestionId = referenceQuestionId; + } + } + + if (referenceQuestionId && !isPublished) { + const res = await publishQuestion(referenceQuestionId).catch((err) => { + if (!migratedCount.failed.question.ids.includes(referenceQuestionId)) { + migratedCount.failed.question.count++; + migratedCount.failed.question.ids.push(referenceQuestionId); + } + + logger.error(`Error while publishing the question for referenceQuestionId: ${referenceQuestionId} Error: + ${JSON.stringify(err.response.data)}`); + }); + + logger.info( + `createQuestion Template publish response: ${res} , "referenceQuestionId" ${referenceQuestionId} questionId, ${question?._id}` + ); + + if (res) { + question = { + ...question, + migrationReference: { isPublished: true }, + }; + isPublished = true; + logger.info(`createQuestion Template published: ${referenceQuestionId}`); + } + } + + if (referenceQuestionId) { + question.referenceQuestionId = referenceQuestionId; + + query = { + referenceQuestionId, + "migrationReference.isPublished": isPublished, + }; + } else { + query = { + ...query, + "migrationReference.isPublished": isPublished, + }; + } + + if (!isEmpty(query) && question) { + await updateById(CONFIG.DB.TABLES.questions, question._id, { + ...query, + }); + } + return question; +}; + +const updateSolutionById = async ({ id, query }) => { + return await updateById(CONFIG.DB.TABLES.solutions, id, query); +}; + +const getQuestionFromDB = async (questionId) => { + const readQuestion = await findAll(CONFIG.DB.TABLES.questions, { + _id: ObjectId(questionId), + }); + return readQuestion[0]; +}; + +const isVisibleIfPresent = (question) => { + return !isEmpty(get(question, "visibleIf")); +}; + +const isChildrenPresent = (question) => { + return !isEmpty(get(question, "children")); +}; + +const isInstanceQuestionsPresent = (question) => { + return !isEmpty(get(question, "instanceQuestions")); +}; + +module.exports = { + setQuestionSetTemplate, + createQuestionTemplate, + updateSolutionById, + getQuestionFromDB, + isVisibleIfPresent, + isChildrenPresent, + isInstanceQuestionsPresent, +}; diff --git a/scripts/creation-portal-migration/template/migrate/common.js b/scripts/creation-portal-migration/template/migrate/common.js new file mode 100644 index 00000000..3487b5cf --- /dev/null +++ b/scripts/creation-portal-migration/template/migrate/common.js @@ -0,0 +1,232 @@ +const { isEmpty } = require("lodash"); +const { getPrecondition } = require("../helpers/hierarchyHelper"); +const { + getQuestionFromDB, + createQuestionTemplate, +} = require("../helpers/questionsetHelper"); +const logger = require("../../logger"); + +const initHierarchy = (questionsetid, solution, programId, referenceQuestionSetId) => { + return { + questionset: referenceQuestionSetId, + questionsetDbId: questionsetid, + isHierarchyUpdated: solution?.migrationReference?.isHierarchyUpdated || false, + isBranchingUpdated: solution?.migrationReference?.isBranchingUpdated || false, + isPublished: solution?.migrationReference?.isPublished || false, + sourcingProgramId: programId, + isSrcProgramUpdated: solution?.migrationReference?.isSrcProgramUpdated || false, + isSrcProgramPublished: solution?.migrationReference?.isSrcProgramPublished || false, + isNominated: solution?.migrationReference?.isNominated || false, + isContributorAdded: solution?.migrationReference?.isContributorAdded || false, + isContributorAccepted: solution?.migrationReference?.isContributorAccepted || false, + criterias: [], + }; +}; + +const getCriteriaData = (criteria, type, question = {}) => { + if (isEmpty(question)) { + return { + referenceQuestionSetId: "", + criDbId: criteria?._id.toString(), + code: criteria?.externalId, + name: criteria?.name, + description: criteria?.description, + mimeType: "application/vnd.sunbird.questionset", + primaryCategory: type, + questions: [], + branchingLogic: {}, + allowMultipleInstances: "", + instances: {}, + pageQuestions: {}, + isMatrix: false, + }; + } else { + return { + referenceQuestionSetId: "", + _id: criteria?._id, + criDbId: criteria?._id.toString(), + code: criteria?.externalId, + name: criteria?.name, + description: criteria?.description, + mimeType: "application/vnd.sunbird.questionset", + primaryCategory: type, + questions: [], + branchingLogic: {}, + allowMultipleInstances: "Yes", + instances: { label: question?.instanceIdentifier }, + pageQuestions: {}, + isMatrix: true + }; + } +}; + +const isSectionMatched = (matrixQuestions, criteriaId, matrixId) => { + logger.debug( + `isSectionMatched: criteriaId = ${criteriaId} matrixId = ${matrixId}; matrixQuestions: ${matrixQuestions}` + ); + if (matrixQuestions.hasOwnProperty(criteriaId)) { + if (matrixQuestions[criteriaId].hasOwnProperty(matrixId)) return true; + } + return false; +}; + +const isQuestionMatched = (data, id) => { + + logger.debug(`isQuestionMatched: id = ${id}; `); + + for (let i = 0; i < data.length; i++) { + const qid = data[i]._id; + + if (qid.toString() === id.toString()) { + return data[i]; + } + } + + return false; +}; + +const isQuestionMatchedInMatrixQuestions = ( + matrixQuestions, + criteriaId, + id +) => { + + logger.debug( + `isQuestionMatchedInMatrixQuestions: criteriaId = ${criteriaId}; id = ${id}; matrixQuestions: ${matrixQuestions}` + ); + + if (matrixQuestions.hasOwnProperty(criteriaId)) { + const keys = Object.keys(matrixQuestions[criteriaId]); + + for (let i = 0; i < keys.length; i++) { + const que = matrixQuestions[criteriaId][keys[i]]; + const questions = que?.questions || []; + return isQuestionMatched(questions, id); + } + } + + return false; +}; + +const getQuestion = async (questions, questions2, id, migratedCount) => { + + let matched = isQuestionMatched(questions, id); + + let question = {}; + + if (matched === false) { + matched = isQuestionMatched(questions2, id); + } + + if (matched === false) { + question = await getQuestionFromDB(id); + } + + if (matched !== false && !isEmpty(matched)) { + question = matched; + } + + if (!isEmpty(question) && (!question?.referenceQuestionId || !question?.migrationReference?.isPublished)) { + question = await createQuestionTemplate(question, migratedCount); + } + + logger.info( + `getQuestion: qid = ${id}; question: ${JSON.stringify(question)}` + ); + + return question; +}; + +const updateMatrixHierarchyBranching = ( + matrixHierarchy, + criteriaId, + matrixId, + parentId, + pQuestion, + child +) => { + const criterias = matrixHierarchy?.criterias || []; + + logger.debug( + `updateMatrixHierarchyBranching: criteriaId = ${criteriaId}; matrixId = ${matrixId}; parentId: ${parentId}; child: ${child}` + ); + + for (let i = 0; i < criterias; i++) { + const criteria = criterias[i]; + if (criteria._id.toString() === criteriaId.toString()) { + matrixHierarchy = updateHierarchyBranching( + matrixHierarchy, + i, + parentId, + pQuestion, + child + ); + } + } + + return matrixHierarchy; +}; + +const updateHierarchyBranching = ( + branching, + index, + parentId, + pQuestion, + child +) => { + const referenceQuestionId = child?.referenceQuestionId; + + const visible = child?.visibleIf ? child?.visibleIf[0] : {}; + + logger.debug( + `updateHierarchyBranching: referenceQuestionId = ${referenceQuestionId}; parentId = ${parentId}; visible: ${visible}` + ); + + if (!isEmpty(visible)) { + if (hasProperty(branching, index, parentId) && referenceQuestionId) { + if ( + !branching.criterias[index].branchingLogic[parentId].target.includes( + referenceQuestionId + ) + ) { + branching.criterias[index].branchingLogic[parentId].target.push( + referenceQuestionId + ); + } + + branching.criterias[index].branchingLogic[referenceQuestionId] = { + target: [], + preCondition: getPrecondition(visible, parentId, pQuestion), + source: [parentId], + }; + } else if (referenceQuestionId) { + branching.criterias[index].branchingLogic[parentId] = { + target: [referenceQuestionId], + preCondition: {}, + source: [], + }; + branching.criterias[index].branchingLogic[referenceQuestionId] = { + target: [], + preCondition: getPrecondition(visible, parentId, pQuestion), + source: [parentId], + }; + } + } + + return branching; +}; + +const hasProperty = (hierarchy, index, id) => { + return hierarchy.criterias[index].branchingLogic.hasOwnProperty(id); +}; + +module.exports = { + initHierarchy, + getCriteriaData, + isSectionMatched, + getQuestion, + isQuestionMatchedInMatrixQuestions, + isQuestionMatched, + updateMatrixHierarchyBranching, + updateHierarchyBranching, +}; diff --git a/scripts/creation-portal-migration/template/migrate/matrix.js b/scripts/creation-portal-migration/template/migrate/matrix.js new file mode 100644 index 00000000..2cc7a21c --- /dev/null +++ b/scripts/creation-portal-migration/template/migrate/matrix.js @@ -0,0 +1,448 @@ +const { + isChildrenPresent, + isVisibleIfPresent, +} = require("../helpers/questionsetHelper"); +const { + getQuestion, + getCriteriaData, + isQuestionMatched, + isSectionMatched, + updateMatrixHierarchyBranching, +} = require("./common"); + +const { getSectionTemplate } = require("../generate/template"); +const { compact, isEmpty } = require("lodash"); +const logger = require("../../logger"); + +const createSection = async ( + type, + matrixHierarchy, + matrixQuestions, + questions, + criteriaId, + matrixQue, + migratedCount +) => { + const matrixId = matrixQue?._id ? matrixQue?._id.toString() : ""; + logger.debug( + `createSection: criteria:${criteriaId} question: ${matrixQue?._id} question responseType: ${matrixQue?.responseType} ` + ); + + if (!isSectionMatched(matrixQuestions, criteriaId, matrixId)) { + const section = getSectionTemplate(matrixQue); + + const newCriteria = getCriteriaData(section, type, matrixQue); + + logger.info( + `createSection: criteria:${criteriaId} question: ${matrixQue?._id}: ------------------Matrix as New Criteria---------------- ${newCriteria?.name}` + ); + + matrixHierarchy.criterias.push(newCriteria); + + if (isEmpty(matrixQuestions)) { + matrixQuestions[criteriaId] = { [matrixId]: { questions: [] } }; + } else { + matrixQuestions[criteriaId][matrixId] = { questions: [] }; + } + + const visible = !isEmpty(matrixQue?.visibleIf) + ? matrixQue?.visibleIf[0] + : ""; + + if (visible) { + const parentId = visible?._id; + + let pQuestion = isQuestionMatched(questions, parentId); + + if (pQuestion !== false) { + for (let q = 0; q < questions.length; q++) { + const que = questions[q]; + if (que._id.toString() === parentId.toString()) { + const children = que.children.map((child) => + child.toString() !== matrixQue._id.toString() ? child : null + ); + que.children = compact(children); + } + questions[q] = que; + } + } + } + } + + const instanceQuestions = matrixQue?.instanceQuestions || []; + const instanceData = await getInstanceQuestions( + instanceQuestions, + matrixHierarchy, + questions, + matrixQuestions, + criteriaId, + matrixQue._id.toString(), + type, + migratedCount + ); + + matrixHierarchy = instanceData.matrixHierarchy; + matrixQuestions = instanceData.matrixQuestions; + questions = instanceData.questions; + + return { matrixHierarchy, matrixQuestions, questions }; +}; + +const getInstanceQuestions = async ( + instanceQuestions, + matrixHierarchy, + questions, + matrixQuestions, + criteriaId, + matrixId, + type, + migratedCount +) => { + logger.debug( + `getInstanceQuestions: criteria:${criteriaId} question: ${matrixId}` + ); + + for (let i = 0; i < instanceQuestions.length; i++) { + const childId = instanceQuestions[i]; + + let child = await getQuestion( + questions, + matrixQuestions[criteriaId][matrixId], + childId + ); + + const data = await getMatrixQuestions( + child, + questions, + matrixQuestions, + criteriaId, + matrixId, + matrixHierarchy, + type, + migratedCount + ); + questions = data.questions; + matrixQuestions = data.matrixQuestions; + matrixHierarchy = data.matrixHierarchy; + } + + return { matrixQuestions, matrixHierarchy, questions }; +}; + +const getMatrixQuestions = async ( + question, + questions, + matrixQuestions, + criteriaId, + matrixId, + matrixHierarchy, + type, + migratedCount +) => { + logger.debug( + `getMatrixQuestions: criteriaId = ${criteriaId}; matrixId = ${matrixId}; question: ${question?._id}` + ); + + if (!isChildrenPresent(question) && !isVisibleIfPresent(question)) { + const data = noChildrenAndnoVisibleIf( + matrixQuestions, + criteriaId, + question, + matrixId, + matrixHierarchy, + questions + ); + + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + } else if (isChildrenPresent(question) && !isVisibleIfPresent(question)) { + const data = await childrenAndnoVisibleIf( + question, + questions, + matrixQuestions, + matrixHierarchy, + criteriaId, + matrixId, + type, + migratedCount + ); + + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + questions = data.questions; + } else if (!isChildrenPresent(question) && isVisibleIfPresent(question)) { + const data = await noChildrenAndVisibleIf( + question, + questions, + matrixQuestions, + matrixHierarchy, + criteriaId, + matrixId, + migratedCount, + type + ); + + questions = data.questions; + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + } + return { matrixHierarchy, matrixQuestions, questions }; +}; + +const noChildrenAndnoVisibleIf = ( + matrixQuestions, + criteriaId, + question, + matrixId, + matrixHierarchy, + questions +) => { + + + logger.debug( + `noChildrenAndnoVisibleIf: criteriaId = ${criteriaId}; matrixId = ${matrixId}; question: ${question?._id}` + ); + + const data = updateMatrixHierarchyQuestions( + matrixQuestions, + criteriaId, + question, + matrixId, + matrixHierarchy, + questions + ); + + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + questions = data.questions; + + return { matrixHierarchy, matrixQuestions, questions }; +}; + +const childrenAndnoVisibleIf = async ( + question, + questions, + matrixQuestions, + matrixHierarchy, + criteriaId, + matrixId, + type, + migratedCount +) => { + const children = question?.children || []; + + logger.info( + `childrenAndnoVisibleIf: criteriaId = ${criteriaId} matrixId = ${matrixId} question = ${question?._id} children = ${children.length}` + ); + + const updatedData = updateMatrixHierarchyQuestions( + matrixQuestions, + criteriaId, + question, + matrixId, + matrixHierarchy, + questions + ); + matrixHierarchy = updatedData.matrixHierarchy; + matrixQuestions = updatedData.matrixQuestions; + questions = updatedData.questions; + + for (let i = 0; i < children.length; i++) { + const childId = children[i]; + let child = await getQuestion( + questions, + matrixQuestions[criteriaId][matrixId], + childId, + migratedCount + ); + + logger.info( + `childrenAndnoVisibleIf: criteriaId = ${criteriaId} matrixId = ${matrixId} childId = ${child?._id} child = ${child} responseType: ${child?.responseType}` + ); + + if (child.responseType === "matrix") { + const data = await createSection( + type, + matrixHierarchy, + matrixQuestions, + questions, + criteriaId, + question, + migratedCount + ); + matrixQuestions = data.matrixQuestions; + matrixHierarchy = data.matrixHierarchy; + questions = data.questions; + } else { + const matched = isQuestionMatched( + matrixQuestions[criteriaId][matrixId], + question._id + ); + + if (matched === false) { + matrixQuestions[criteriaId][matrixId].questions.push(child); + matrixHierarchy = updateMatrixHierarchy( + matrixHierarchy, + matrixId, + child?.referenceQuestionId, + criteriaId + ); + matrixHierarchy = updateMatrixHierarchyBranching( + matrixHierarchy, + criteriaId, + matrixId, + question?.referenceQuestionId, + question, + child + ); + } + } + } + + return { matrixHierarchy, matrixQuestions, questions }; +}; + +const noChildrenAndVisibleIf = async ( + question, + questions, + matrixQuestions, + matrixHierarchy, + criteriaId, + matrixId, + migratedCount, + type +) => { + const visible = question?.visibleIf ? question.visibleIf[0] : ""; + const parentId = visible._id; + const pQuestion = await getQuestion( + questions, + matrixQuestions[criteriaId][matrixId], + parentId, + migratedCount + ); + + logger.debug( + `noChildrenAndVisibleIf: criteriaId = ${criteriaId} matrixId = ${matrixId} questionId = ${question?._id} responseType: ${question?.responseType} visible = ${visible} ` + ); + + const updatedData = updateMatrixHierarchyQuestions( + matrixQuestions, + criteriaId, + question, + matrixId, + matrixHierarchy, + questions + ); + matrixHierarchy = updatedData.matrixHierarchy; + matrixQuestions = updatedData.matrixQuestions; + questions = updatedData.questions; + + const pMatched = isQuestionMatched( + matrixQuestions[criteriaId][matrixId], + pQuestion._id + ); + + if (pMatched === false) { + matrixQuestions[criteriaId][matrixId].questions.push(pQuestion); + matrixHierarchy = updateMatrixHierarchy( + matrixHierarchy, + matrixId, + pQuestion?.referenceQuestionId, + criteriaId + ); + matrixHierarchy = updateMatrixHierarchyBranching( + matrixHierarchy, + criteriaId, + matrixId, + pQuestion?.referenceQuestionId, + pQuestion, + question + ); + + const data = await getMatrixQuestions( + pQuestion, + questions, + matrixQuestions, + criteriaId, + matrixId, + matrixHierarchy, + type, + migratedCount + ); + questions = data.questions; + matrixQuestions = data.matrixQuestions; + matrixHierarchy = data.matrixHierarchy; + } + // } + + return { questions, matrixHierarchy, matrixQuestions }; +}; + +const updateMatrixHierarchy = ( + matrixHierarchy, + matrixId, + referenceQuestionId, + criteriaId +) => { + logger.debug( + `updateMatrixHierarchy: matrixId = ${matrixId}; referenceQuestionId = ${referenceQuestionId}` + ); + + const criterias = matrixHierarchy.criterias || []; + for (let i = 0; i < criterias.length; i++) { + const criteria = criterias[i]; + if (criteria?._id.toString() === matrixId) { + if (!criteria.questions.includes(referenceQuestionId)) { + criteria.questions.push(referenceQuestionId); + } + } + criterias[i] = criteria; + } + matrixHierarchy.criterias = criterias; + + logger.info( + `updateMatrixHierarchy: matrixHierarchy: ${JSON.stringify(matrixHierarchy)}` + ); + + return matrixHierarchy; +}; + +const updateMatrixHierarchyQuestions = ( + matrixQuestions, + criteriaId, + question, + matrixId, + matrixHierarchy, + questions +) => { + logger.debug( + `updateMatrixHierarchyQuestions: criteriaId = ${criteriaId}; matrixId = ${matrixId}; question: ${question?._id}: referenceQuestionId: ${question?.referenceQuestionId}` + ); + + const matched = isQuestionMatched( + matrixQuestions[criteriaId][matrixId], + question._id + ); + + logger.info( + `updateMatrixHierarchyQuestions: isQuestionMatched: matched = ${ + matched === false ? matched : true + };` + ); + + if (matched === false) { + matrixQuestions[criteriaId][matrixId].questions.push(question); + matrixHierarchy = updateMatrixHierarchy( + matrixHierarchy, + matrixId, + question?.referenceQuestionId, + criteriaId + ); + } + + return { matrixHierarchy, matrixQuestions, questions }; +}; + +module.exports = { + createSection, +}; diff --git a/scripts/creation-portal-migration/template/migrate/nonmatrix.js b/scripts/creation-portal-migration/template/migrate/nonmatrix.js new file mode 100644 index 00000000..7b7a127d --- /dev/null +++ b/scripts/creation-portal-migration/template/migrate/nonmatrix.js @@ -0,0 +1,359 @@ +const { + isChildrenPresent, + isVisibleIfPresent, +} = require("../helpers/questionsetHelper"); +const { + isQuestionMatchedInMatrixQuestions, + getQuestion, + isQuestionMatched, + updateHierarchyBranching, +} = require("./common"); + +const { + updateHierarchyChildren, +} = require("../helpers/hierarchyHelper"); +const { createSection } = require("./matrix"); + +const logger = require("../../logger"); + + +const updateNonMatrixHierarchyChildren = ( + question, + nonMatrixQuestions, + matrixQuestions, + hierarchy, + index, + criteriaId, + questions, + matrixHierarchy +) => { + + logger.debug(`updateNonMatrixHierarchyChildren: question = ${question?._id} criteriaId=${criteriaId}`) + + let matched = isQuestionMatched(nonMatrixQuestions, question._id); + + if (matched === false) { + matched = isQuestionMatchedInMatrixQuestions( + matrixQuestions, + criteriaId, + question._id + ); + + if (matched === false) { + hierarchy = updateHierarchyChildren( + hierarchy, + question?.referenceQuestionId, + index, + question + ); + nonMatrixQuestions.push(question); + } + } + + + return { + hierarchy, + nonMatrixQuestions, + questions, + matrixQuestions, + matrixHierarchy, + }; +}; + +const getNonMatrixQuestions = async ( + question, + questions, + nonMatrixQuestions, + matrixQuestions, + matrixHierarchy, + hierarchy, + index, + type, + migratedCount, + criteriaId +) => { + logger.debug(`getNonMatrixQuestions: criteriaId = ${criteriaId} question = ${question?._id}`) + + question = await getQuestion( + questions, + nonMatrixQuestions, + question._id, + migratedCount + ); + + if (!isChildrenPresent(question) && !isVisibleIfPresent(question)) { + + const data = nonMatrixNoChildrenAndNoVisibleIf( + question, + nonMatrixQuestions, + matrixQuestions, + hierarchy, + index, + criteriaId, + questions, + matrixHierarchy + ); + + nonMatrixQuestions = data.nonMatrixQuestions; + hierarchy = data.hierarchy; + questions = data.questions; + matrixQuestions = data.matrixQuestions; + matrixHierarchy = data.matrixHierarchy; + + } else if (isChildrenPresent(question) && !isVisibleIfPresent(question)) { + + const data = await nonMatrixChildrenAndNoVisibleIf( + question, + questions, + nonMatrixQuestions, + matrixQuestions, + matrixHierarchy, + hierarchy, + index, + type, + migratedCount, + criteriaId + ); + hierarchy = data.hierarchy; + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + nonMatrixQuestions = data.nonMatrixQuestions; + questions = data.questions; + + } else if (!isChildrenPresent(question) && isVisibleIfPresent(question)) { + + const data = await nonMatrixNoChildrenAndVisibleIf( + question, + questions, + nonMatrixQuestions, + matrixQuestions, + matrixHierarchy, + hierarchy, + index, + type, + migratedCount, + criteriaId + ); + hierarchy = data.hierarchy; + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + nonMatrixQuestions = data.nonMatrixQuestions; + questions = data.questions; + + } + + return { + hierarchy, + matrixHierarchy, + matrixQuestions, + nonMatrixQuestions, + questions, + }; +}; + +const nonMatrixNoChildrenAndNoVisibleIf = ( + question, + nonMatrixQuestions, + matrixQuestions, + hierarchy, + index, + criteriaId, + questions, + matrixHierarchy +) => { + + logger.debug(`nonMatrix NoChildrenAndNoVisibleIf: criteriaId = ${criteriaId} question = ${question?._id}`) + + return updateNonMatrixHierarchyChildren( + question, + nonMatrixQuestions, + matrixQuestions, + hierarchy, + index, + criteriaId, + questions, + matrixHierarchy + ); +}; + +const nonMatrixChildrenAndNoVisibleIf = async ( + question, + questions, + nonMatrixQuestions, + matrixQuestions, + matrixHierarchy, + hierarchy, + index, + type, + migratedCount, + criteriaId +) => { + + logger.debug(`nonMatrix ChildrenAndNoVisibleIf: criteriaId = ${criteriaId} question = ${question?._id}`) + + const data = updateNonMatrixHierarchyChildren( + question, + nonMatrixQuestions, + matrixQuestions, + hierarchy, + index, + criteriaId, + questions, + matrixHierarchy + ); + nonMatrixQuestions = data.nonMatrixQuestions; + hierarchy = data.hierarchy; + + const children = question?.children || []; + + for (let i = 0; i < children.length; i++) { + const childId = children[i]; + + let child = await getQuestion( + questions, + nonMatrixQuestions, + childId, + migratedCount + ); + + logger.info(`nonMatrix ChildrenAndNoVisibleIf: criteriaId = ${criteriaId} question = ${question?._id} child: ${child?._id} child responseType: ${child?.responseType}`) + + + if (child.responseType === "matrix") { + const data = await createSection( + type, + matrixHierarchy, + matrixQuestions, + questions, + criteriaId, + child, + migratedCount + ); + matrixQuestions = data.matrixQuestions; + matrixHierarchy = data.matrixHierarchy; + questions = data.questions; + } else { + const childWithHierarchy = updateNonMatrixHierarchyChildren( + child, + nonMatrixQuestions, + matrixQuestions, + hierarchy, + index, + criteriaId, + questions, + matrixHierarchy + ); + nonMatrixQuestions = childWithHierarchy.nonMatrixQuestions; + hierarchy = childWithHierarchy.hierarchy; + + hierarchy = updateHierarchyBranching( + hierarchy, + index, + question?.referenceQuestionId, + question, + child + ); + + } + } + + + return { + hierarchy, + matrixHierarchy, + matrixQuestions, + nonMatrixQuestions, + questions, + }; +}; + +const nonMatrixNoChildrenAndVisibleIf = async ( + question, + questions, + nonMatrixQuestions, + matrixQuestions, + matrixHierarchy, + hierarchy, + index, + type, + migratedCount, + criteriaId +) => { + + const visible = question?.visibleIf ? question.visibleIf[0] : ""; + const parentId = visible._id; + const pQuestion = await getQuestion( + questions, + nonMatrixQuestions, + parentId, + migratedCount + ); + logger.debug(`nonMatrix NoChildrenAndVisibleIf: criteriaId = ${criteriaId} question = ${question?._id} question visibleif= ${visible}`) + + const data = updateNonMatrixHierarchyChildren( + question, + nonMatrixQuestions, + matrixQuestions, + hierarchy, + index, + criteriaId, + questions, + matrixHierarchy + ); + nonMatrixQuestions = data.nonMatrixQuestions; + hierarchy = data.hierarchy; + + if (pQuestion.responseType === "matrix") { + const data = await createSection( + type, + matrixHierarchy, + matrixQuestions, + questions, + criteriaId, + pQuestion, + migratedCount + ); + matrixQuestions = data.matrixQuestions; + matrixHierarchy = data.matrixHierarchy; + questions = data.questions; + + } else { + hierarchy = updateHierarchyBranching( + hierarchy, + index, + pQuestion?.referenceQuestionId, + pQuestion, + question + ); + const data = await getNonMatrixQuestions( + pQuestion, + questions, + nonMatrixQuestions, + matrixQuestions, + matrixHierarchy, + hierarchy, + index, + type, + migratedCount, + criteriaId + ); + // return data; + hierarchy = data.hierarchy; + matrixHierarchy = data.matrixHierarchy; + matrixQuestions = data.matrixQuestions; + nonMatrixQuestions = data.nonMatrixQuestions; + questions = data.questions; + } + + return { + hierarchy, + matrixHierarchy, + matrixQuestions, + nonMatrixQuestions, + questions, + }; +}; + +module.exports = { + getNonMatrixQuestions, +};