-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from dimagi/sk/read-app-xml
extract module and assessment metadata from app CCZ
- Loading branch information
Showing
11 changed files
with
452 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import itertools | ||
import re | ||
import tempfile | ||
import xml.etree.ElementTree as ET | ||
import zipfile | ||
from dataclasses import dataclass | ||
|
||
import httpx | ||
from django.conf import settings | ||
|
||
XMLNS = "http://commcareconnect.com/data/v1/learn" | ||
XMLNS_PREFIX = "{%s}" % XMLNS | ||
|
||
|
||
@dataclass | ||
class Module: | ||
id: str | ||
name: str | ||
description: str | ||
time_estimate: int | ||
|
||
|
||
@dataclass | ||
class Assessment: | ||
id: str | ||
|
||
|
||
def get_connect_blocks_for_app(domain: str, app_id: str) -> list[str]: | ||
form_xmls = get_form_xml_for_app(domain, app_id) | ||
return list(itertools.chain.from_iterable(extract_connect_blocks(form_xml) for form_xml in form_xmls)) | ||
|
||
|
||
def get_form_xml_for_app(domain: str, app_id: str) -> list[str]: | ||
"""Download the CCZ for the given app and return the XML for each form.""" | ||
ccz_url = f"{settings.COMMCARE_HQ_URL}/a/{domain}/apps/api/download_ccz/" | ||
params = { | ||
"app_id": app_id, | ||
"latest": "release", | ||
} | ||
response = httpx.get(ccz_url, params=params) | ||
response.raise_for_status() | ||
|
||
form_xml = [] | ||
with tempfile.NamedTemporaryFile() as file: | ||
file.write(response.content) | ||
file.seek(0) | ||
|
||
form_re = re.compile(r"modules-\d+/forms-\d+\.xml") | ||
with zipfile.ZipFile(file, "r") as zip_ref: | ||
for file in zip_ref.namelist(): | ||
if form_re.match(file): | ||
with zip_ref.open(file) as xml_file: | ||
form_xml.append(xml_file.read().decode()) | ||
return form_xml | ||
|
||
|
||
def extract_connect_blocks(form_xml): | ||
xml = ET.fromstring(form_xml) | ||
yield from extract_modules(xml) | ||
yield from extract_assessments(xml) | ||
|
||
|
||
def extract_assessments(xml: ET.ElementTree) -> list[str]: | ||
for block in xml.findall(f".//{XMLNS_PREFIX}assessment"): | ||
yield Assessment(block.get("id")) | ||
|
||
|
||
def extract_modules(xml: ET.ElementTree): | ||
for block in xml.findall(f".//{XMLNS_PREFIX}module"): | ||
slug = block.get("id") | ||
name = get_element_text(block, "name") | ||
description = get_element_text(block, "description") | ||
time_estimate = get_element_text(block, "time_estimate") | ||
yield Module(slug, name, description, int(time_estimate) if time_estimate is not None else None) | ||
|
||
|
||
def get_element_text(parent, name) -> str | None: | ||
element = parent.find(f"{XMLNS_PREFIX}{name}") | ||
return element.text if element is not None else None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
This content comes from the https://staging.commcarehq.org/a/skelly/apps/view/a671db914232020002c1f294c675d1d8/ app. | ||
|
||
To update it from the app: | ||
|
||
1. Download the CCZ: https://staging.commcarehq.org/a/skelly/apps/api/download_ccz/?app_id=a671db914232020002c1f294c675d1d8 | ||
2. Extract the contents | ||
3. Update the files in this folder |
54 changes: 54 additions & 0 deletions
54
commcare_connect/opportunity/tests/data/demo_app/modules-0/forms-0.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns:orx="http://openrosa.org/jr/xforms" xmlns="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa" xmlns:vellum="http://commcarehq.org/xforms/vellum"> | ||
<h:head> | ||
<h:title>Module 1</h:title> | ||
<model> | ||
<instance> | ||
<data xmlns:jrm="http://dev.commcarehq.org/jr/xforms" xmlns="http://openrosa.org/formdesigner/52F02F3E-320D-4D91-9EBF-FF4F06226E98" uiVersion="1" version="72" name="Module 1"> | ||
<welcome_note/> | ||
<module_1> | ||
<module xmlns="http://commcareconnect.com/data/v1/learn" id="module_1"> | ||
<name>Module 1</name> | ||
<description>This is the first module in a series of modules | ||
that will take you through all you need to know.</description> | ||
<time_estimate>1</time_estimate> | ||
</module> | ||
</module_1> | ||
<orx:meta xmlns:cc="http://commcarehq.org/xforms"> | ||
<orx:deviceID/> | ||
<orx:timeStart/> | ||
<orx:timeEnd/> | ||
<orx:username/> | ||
<orx:userID/> | ||
<orx:instanceID/> | ||
<cc:appVersion/> | ||
<orx:drift/> | ||
</orx:meta> | ||
</data> | ||
</instance> | ||
<instance id="commcaresession" src="jr://instance/session"/> | ||
<bind nodeset="/data/welcome_note"/> | ||
<itext> | ||
<translation lang="en" default=""> | ||
<text id="welcome_note-label"> | ||
<value>Welcome to module 1</value> | ||
</text> | ||
</translation> | ||
</itext> | ||
<setvalue ref="/data/meta/deviceID" value="instance('commcaresession')/session/context/deviceid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/timeStart" value="now()" event="xforms-ready"/> | ||
<bind nodeset="/data/meta/timeStart" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/timeEnd" value="now()" event="xforms-revalidate"/> | ||
<bind nodeset="/data/meta/timeEnd" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/username" value="instance('commcaresession')/session/context/username" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/userID" value="instance('commcaresession')/session/context/userid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/instanceID" value="uuid()" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/appVersion" value="instance('commcaresession')/session/context/appversion" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/drift" value="if(count(instance('commcaresession')/session/context/drift) = 1, instance('commcaresession')/session/context/drift, '')" event="xforms-revalidate"/> | ||
</model> | ||
</h:head> | ||
<h:body> | ||
<trigger ref="/data/welcome_note" appearance="minimal"> | ||
<label ref="jr:itext('welcome_note-label')"/> | ||
</trigger> | ||
</h:body> | ||
</h:html> |
53 changes: 53 additions & 0 deletions
53
commcare_connect/opportunity/tests/data/demo_app/modules-0/forms-1.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns:orx="http://openrosa.org/jr/xforms" xmlns="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa" xmlns:vellum="http://commcarehq.org/xforms/vellum"> | ||
<h:head> | ||
<h:title>Module 2</h:title> | ||
<model> | ||
<instance> | ||
<data xmlns:jrm="http://dev.commcarehq.org/jr/xforms" xmlns="http://openrosa.org/formdesigner/EC1AD740-D2C9-4532-AECC-2D5CF5364696" uiVersion="1" version="72" name="Module 2"> | ||
<welcome_note/> | ||
<module_2> | ||
<module xmlns="http://commcareconnect.com/data/v1/learn" id="module_2"> | ||
<name>Module 2</name> | ||
<description>This is module 2 of the series.</description> | ||
<time_estimate>2</time_estimate> | ||
</module> | ||
</module_2> | ||
<orx:meta xmlns:cc="http://commcarehq.org/xforms"> | ||
<orx:deviceID/> | ||
<orx:timeStart/> | ||
<orx:timeEnd/> | ||
<orx:username/> | ||
<orx:userID/> | ||
<orx:instanceID/> | ||
<cc:appVersion/> | ||
<orx:drift/> | ||
</orx:meta> | ||
</data> | ||
</instance> | ||
<instance id="commcaresession" src="jr://instance/session"/> | ||
<bind nodeset="/data/welcome_note"/> | ||
<itext> | ||
<translation lang="en" default=""> | ||
<text id="welcome_note-label"> | ||
<value>Welcome to module 2</value> | ||
</text> | ||
</translation> | ||
</itext> | ||
<setvalue ref="/data/meta/deviceID" value="instance('commcaresession')/session/context/deviceid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/timeStart" value="now()" event="xforms-ready"/> | ||
<bind nodeset="/data/meta/timeStart" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/timeEnd" value="now()" event="xforms-revalidate"/> | ||
<bind nodeset="/data/meta/timeEnd" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/username" value="instance('commcaresession')/session/context/username" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/userID" value="instance('commcaresession')/session/context/userid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/instanceID" value="uuid()" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/appVersion" value="instance('commcaresession')/session/context/appversion" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/drift" value="if(count(instance('commcaresession')/session/context/drift) = 1, instance('commcaresession')/session/context/drift, '')" event="xforms-revalidate"/> | ||
</model> | ||
</h:head> | ||
<h:body> | ||
<trigger ref="/data/welcome_note" appearance="minimal"> | ||
<label ref="jr:itext('welcome_note-label')"/> | ||
</trigger> | ||
</h:body> | ||
</h:html> |
53 changes: 53 additions & 0 deletions
53
commcare_connect/opportunity/tests/data/demo_app/modules-1/forms-0.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns:orx="http://openrosa.org/jr/xforms" xmlns="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa" xmlns:vellum="http://commcarehq.org/xforms/vellum"> | ||
<h:head> | ||
<h:title>Module 3</h:title> | ||
<model> | ||
<instance> | ||
<data xmlns:jrm="http://dev.commcarehq.org/jr/xforms" xmlns="http://openrosa.org/formdesigner/11151AA2-1599-4C5E-8013-5E2197B6C68E" uiVersion="1" version="72" name="Module 3"> | ||
<welcome_note/> | ||
<module_3> | ||
<module xmlns="http://commcareconnect.com/data/v1/learn" id="module_3"> | ||
<name>Module 3</name> | ||
<description>Module 3 in the series</description> | ||
<time_estimate>3</time_estimate> | ||
</module> | ||
</module_3> | ||
<orx:meta xmlns:cc="http://commcarehq.org/xforms"> | ||
<orx:deviceID/> | ||
<orx:timeStart/> | ||
<orx:timeEnd/> | ||
<orx:username/> | ||
<orx:userID/> | ||
<orx:instanceID/> | ||
<cc:appVersion/> | ||
<orx:drift/> | ||
</orx:meta> | ||
</data> | ||
</instance> | ||
<instance id="commcaresession" src="jr://instance/session"/> | ||
<bind nodeset="/data/welcome_note"/> | ||
<itext> | ||
<translation lang="en" default=""> | ||
<text id="welcome_note-label"> | ||
<value>Welcome to module 3</value> | ||
</text> | ||
</translation> | ||
</itext> | ||
<setvalue ref="/data/meta/deviceID" value="instance('commcaresession')/session/context/deviceid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/timeStart" value="now()" event="xforms-ready"/> | ||
<bind nodeset="/data/meta/timeStart" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/timeEnd" value="now()" event="xforms-revalidate"/> | ||
<bind nodeset="/data/meta/timeEnd" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/username" value="instance('commcaresession')/session/context/username" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/userID" value="instance('commcaresession')/session/context/userid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/instanceID" value="uuid()" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/appVersion" value="instance('commcaresession')/session/context/appversion" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/drift" value="if(count(instance('commcaresession')/session/context/drift) = 1, instance('commcaresession')/session/context/drift, '')" event="xforms-revalidate"/> | ||
</model> | ||
</h:head> | ||
<h:body> | ||
<trigger ref="/data/welcome_note" appearance="minimal"> | ||
<label ref="jr:itext('welcome_note-label')"/> | ||
</trigger> | ||
</h:body> | ||
</h:html> |
114 changes: 114 additions & 0 deletions
114
commcare_connect/opportunity/tests/data/demo_app/modules-2/forms-0.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns:orx="http://openrosa.org/jr/xforms" xmlns="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa" xmlns:vellum="http://commcarehq.org/xforms/vellum"> | ||
<h:head> | ||
<h:title>Assessment</h:title> | ||
<model> | ||
<instance> | ||
<data xmlns:jrm="http://dev.commcarehq.org/jr/xforms" xmlns="http://openrosa.org/formdesigner/BD70B3D5-6CB4-4A2E-AD5B-C8E3E7BC37A7" uiVersion="1" version="72" name="Assessment"> | ||
<did_you_lean_anything/> | ||
<how_many_modules_are_there/> | ||
<score/> | ||
<your_score_is_score/> | ||
<demo> | ||
<assessment xmlns="http://commcareconnect.com/data/v1/learn" id="demo"> | ||
<user_score/> | ||
</assessment> | ||
</demo> | ||
<orx:meta xmlns:cc="http://commcarehq.org/xforms"> | ||
<orx:deviceID/> | ||
<orx:timeStart/> | ||
<orx:timeEnd/> | ||
<orx:username/> | ||
<orx:userID/> | ||
<orx:instanceID/> | ||
<cc:appVersion/> | ||
<orx:drift/> | ||
</orx:meta> | ||
</data> | ||
</instance> | ||
<instance id="commcaresession" src="jr://instance/session"/> | ||
<bind nodeset="/data/did_you_lean_anything"/> | ||
<bind nodeset="/data/how_many_modules_are_there"/> | ||
<bind nodeset="/data/score" calculate="if(/data/did_you_lean_anything = 'yes', 20, 0) + if(/data/how_many_modules_are_there = 'three', 50, 0)"/> | ||
<bind nodeset="/data/your_score_is_score"/> | ||
<bind nodeset="/data/demo/assessment/user_score" calculate="/data/score"/> | ||
<itext> | ||
<translation lang="en" default=""> | ||
<text id="did_you_lean_anything-label"> | ||
<value>Did you lean anything?</value> | ||
</text> | ||
<text id="did_you_lean_anything-yes-label"> | ||
<value>Yes</value> | ||
</text> | ||
<text id="did_you_lean_anything-no-label"> | ||
<value>No</value> | ||
</text> | ||
<text id="how_many_modules_are_there-label"> | ||
<value>How many modules are there?</value> | ||
</text> | ||
<text id="how_many_modules_are_there-one-label"> | ||
<value>One</value> | ||
</text> | ||
<text id="how_many_modules_are_there-two-label"> | ||
<value>Two</value> | ||
</text> | ||
<text id="how_many_modules_are_there-three-label"> | ||
<value>Three</value> | ||
</text> | ||
<text id="how_many_modules_are_there-four-label"> | ||
<value>Four</value> | ||
</text> | ||
<text id="your_score_is_score-label"> | ||
<value>Your score is: | ||
<output value="/data/score"/> | ||
</value> | ||
</text> | ||
</translation> | ||
</itext> | ||
<setvalue ref="/data/meta/deviceID" value="instance('commcaresession')/session/context/deviceid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/timeStart" value="now()" event="xforms-ready"/> | ||
<bind nodeset="/data/meta/timeStart" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/timeEnd" value="now()" event="xforms-revalidate"/> | ||
<bind nodeset="/data/meta/timeEnd" type="xsd:dateTime"/> | ||
<setvalue ref="/data/meta/username" value="instance('commcaresession')/session/context/username" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/userID" value="instance('commcaresession')/session/context/userid" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/instanceID" value="uuid()" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/appVersion" value="instance('commcaresession')/session/context/appversion" event="xforms-ready"/> | ||
<setvalue ref="/data/meta/drift" value="if(count(instance('commcaresession')/session/context/drift) = 1, instance('commcaresession')/session/context/drift, '')" event="xforms-revalidate"/> | ||
</model> | ||
</h:head> | ||
<h:body> | ||
<select ref="/data/did_you_lean_anything"> | ||
<label ref="jr:itext('did_you_lean_anything-label')"/> | ||
<item> | ||
<label ref="jr:itext('did_you_lean_anything-yes-label')"/> | ||
<value>yes</value> | ||
</item> | ||
<item> | ||
<label ref="jr:itext('did_you_lean_anything-no-label')"/> | ||
<value>no</value> | ||
</item> | ||
</select> | ||
<select1 ref="/data/how_many_modules_are_there"> | ||
<label ref="jr:itext('how_many_modules_are_there-label')"/> | ||
<item> | ||
<label ref="jr:itext('how_many_modules_are_there-one-label')"/> | ||
<value>one</value> | ||
</item> | ||
<item> | ||
<label ref="jr:itext('how_many_modules_are_there-two-label')"/> | ||
<value>two</value> | ||
</item> | ||
<item> | ||
<label ref="jr:itext('how_many_modules_are_there-three-label')"/> | ||
<value>three</value> | ||
</item> | ||
<item> | ||
<label ref="jr:itext('how_many_modules_are_there-four-label')"/> | ||
<value>four</value> | ||
</item> | ||
</select1> | ||
<trigger ref="/data/your_score_is_score" appearance="minimal"> | ||
<label ref="jr:itext('your_score_is_score-label')"/> | ||
</trigger> | ||
</h:body> | ||
</h:html> |
Oops, something went wrong.