Skip to content

Commit

Permalink
publish assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
copelco committed Feb 11, 2025
1 parent 338e77d commit 867af0e
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 23 deletions.
7 changes: 1 addition & 6 deletions apps/odk_publish/consumers.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,7 @@ def receive(self, text_data):
self.publish_form_template(event_data=event_data)
except Exception as e:
logger.exception("Error publishing form")
tbe = traceback.TracebackException.from_exception(
exc=e,
capture_locals=True,
compact=True,
limit=1,
)
tbe = traceback.TracebackException.from_exception(exc=e, compact=True)
message = "".join(tbe.format())
# If the error is from ODK Central, format the error message for easier reading
if len(e.args) >= 2 and isinstance(e.args[1], Response):
Expand Down
24 changes: 21 additions & 3 deletions apps/odk_publish/etl/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,40 @@ def publish_form_template(event: PublishTemplateEvent, user: User, send_message:
)
send_message(f"Downloaded template: {file}")
with transaction.atomic():
# Create the next version
# Create the next version locally
template_version = FormTemplateVersion.objects.create(
form_template=form_template, user=user, file=file, version=version
)
# Create a version for each app user
# Create a version for each app user locally
app_users = form_template.project.app_users.filter(name__in=event.app_users)
app_user_versions = template_version.create_app_user_versions(
app_users=app_users, send_message=send_message
)
# Publish each app user version to ODK Central
# Get or create app users in ODK Central
central_app_user_assignments = client.odk_publish.get_or_create_app_users(
display_names=[app_user.name for app_user in app_users]
)
send_message(f"Synced user(s): {', '.join(central_app_user_assignments.keys())}")
# Assign this form to the app users
for app_user_version in app_user_versions:
central_app_user_assignments[app_user_version.app_user.name].xml_form_ids.append(
app_user_version.xml_form_id
)
# Publish each app user form version to ODK Central
for app_user_version in app_user_versions:
form = client.odk_publish.create_or_update_form(
xml_form_id=app_user_version.app_user_form_template.xml_form_id,
definition=app_user_version.file.read(),
)
send_message(f"Published form: {form.xmlFormId}")
# Create or update the form assignments on the server
for assignment in central_app_user_assignments.values():
client.odk_publish.assign_app_users_forms(app_users=[assignment])
send_message(f"Assigned user {assignment.displayName} to {assignment.xml_form_ids[0]}")
# Update AppUsers with null central_id
update_app_users_central_id(
project=form_template.project, app_users=central_app_user_assignments
)
send_message(f"Successfully published {version}", complete=True)


Expand Down
10 changes: 10 additions & 0 deletions apps/odk_publish/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,13 @@ class Meta:

def __str__(self):
return f"{self.app_user_form_template} - {self.form_template_version}"

@property
def xml_form_id(self) -> str:
"""The ODK Central xmlFormId for this version's AppUserFormTemplate."""
return self.app_user_form_template.xml_form_id

@property
def app_user(self) -> AppUser:
"""The app user for this version."""
return self.app_user_form_template.app_user
57 changes: 43 additions & 14 deletions tests/odk_publish/etl/load/test_publish.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import datetime as dt

import pytest
from django.core.files.uploadedfile import SimpleUploadedFile
from gspread.utils import ExportFormat

from apps.odk_publish.etl.load import PublishTemplateEvent, publish_form_template
from apps.odk_publish.etl.odk.publish import ProjectAppUserAssignment
from tests.odk_publish.factories import (
AppUserFormTemplateFactory,
FormTemplateFactory,
Expand All @@ -19,13 +22,13 @@ class TestPublishFormTemplate:
def send_message(self, message: str, complete: bool = False):
pass

def test_publish(self, mocker):
def test_publish(self, mocker, requests_mock):
project = ProjectFactory(central_server__base_url="https://central", central_id=2)
form_template = FormTemplateFactory(project=project, form_id_base="staff_registration")
# Create 2 app users
user_form1 = AppUserFormTemplateFactory(form_template=form_template)
user_form2 = AppUserFormTemplateFactory(form_template=form_template)
event = PublishTemplateEvent(form_template=form_template.id, app_users=["user1", "user2"])
user_form1 = AppUserFormTemplateFactory(form_template=form_template, app_user__name="user1")
user_form2 = AppUserFormTemplateFactory(form_template=form_template, app_user__name="user2")
event = PublishTemplateEvent(form_template=form_template.id, app_users=["user1"])
# Mock Gspread download
mock_gspread_client = mocker.patch("apps.odk_publish.etl.google.gspread_client")
mock_gspread_client.return_value.open_by_url.return_value.export.return_value = (
Expand All @@ -43,11 +46,44 @@ def test_publish(self, mocker):
"apps.odk_publish.etl.odk.publish.PublishService.get_unique_version_by_form_id",
return_value="2025-02-01-v1",
)

assignments = {
"user1": ProjectAppUserAssignment(
projectId=project.central_id,
id=user_form1.app_user.central_id,
type="field_key",
displayName="user1",
createdAt=dt.datetime.now(),
updatedAt=None,
deletedAt=None,
token="token1",
xml_form_ids=["staff_registration_user1"],
),
"user2": ProjectAppUserAssignment(
projectId=project.central_id,
id=user_form2.app_user.central_id,
type="field_key",
displayName="user2",
createdAt=dt.datetime.now(),
updatedAt=None,
deletedAt=None,
token="token1",
xml_form_ids=["staff_registration_user2"],
),
}
mock_get_users = mocker.patch(
"apps.odk_publish.etl.odk.publish.PublishService.get_or_create_app_users",
return_value=assignments,
)
mock_create_or_update_form = mocker.patch(
"apps.odk_publish.etl.odk.publish.PublishService.create_or_update_form",
return_value=mocker.Mock(),
)
mock_assign_app_users_forms = mocker.patch(
"apps.odk_publish.etl.odk.publish.PublishService.assign_app_users_forms"
)
publish_form_template(event=event, user=UserFactory(), send_message=self.send_message)
mock_get_users.assert_called_once()
mock_get_version.assert_called_once_with(xml_form_id_base=form_template.form_id_base)
mock_create_or_update_form.assert_has_calls(
[
Expand All @@ -61,16 +97,9 @@ def test_publish(self, mocker):
),
]
)
mock_get_version.assert_called_once_with(xml_form_id_base=form_template.form_id_base)
mock_create_or_update_form.assert_has_calls(
mock_assign_app_users_forms.assert_has_calls(
[
mocker.call(
definition=b"file content",
xml_form_id=user_form1.xml_form_id,
),
mocker.call(
definition=b"file content",
xml_form_id=user_form2.xml_form_id,
),
mocker.call(app_users=[assignments["user1"]]),
mocker.call(app_users=[assignments["user2"]]),
]
)

0 comments on commit 867af0e

Please sign in to comment.