Skip to content

Commit

Permalink
RAS-1400 Extend party enrolment to include business and survey details
Browse files Browse the repository at this point in the history
  • Loading branch information
LJBabbage committed Dec 17, 2024
1 parent af73b37 commit 937a847
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 59 deletions.
6 changes: 6 additions & 0 deletions _infra/helm/party/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ spec:
{{- else }}
value: "http://$(IAC_SERVICE_HOST):$(IAC_SERVICE_PORT)"
{{- end }}
- name: SURVEY_URL
{{- if .Values.dns.enabled }}
value: "http://survey.{{ .Values.namespace }}.svc.cluster.local:{{ .Values.dns.wellKnownPort }}"
{{- else }}
value: "http://$(SURVEY_SERVICE_HOST):$(SURVEY_SERVICE_PORT)"
{{- end }}
- name: NOTIFY_URL
{{- if .Values.dns.enabled }}
value: "http://notify-gateway.{{ .Values.namespace }}.svc.cluster.local:{{ .Values.dns.wellKnownPort }}/emails/"
Expand Down
2 changes: 2 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Config(object):
COLLECTION_EXERCISE_URL = os.getenv("COLLECTION_EXERCISE_URL")
FRONTSTAGE_URL = os.getenv("FRONTSTAGE_URL")
IAC_URL = os.getenv("IAC_URL")
SURVEY_URL = os.getenv("SURVEY_URL")

GOOGLE_CLOUD_PROJECT = os.getenv("GOOGLE_CLOUD_PROJECT", "test-project-id")
PUBSUB_TOPIC = os.getenv("PUBSUB_TOPIC", "ras-rm-notify-test")
Expand Down Expand Up @@ -96,6 +97,7 @@ class Config(object):
class DevelopmentConfig(Config):
DEBUG = True
LOGGING_LEVEL = "DEBUG"
SURVEY_URL = os.getenv("SURVEY_URL", "http://localhost:8080")


class TestingConfig(DevelopmentConfig):
Expand Down
47 changes: 44 additions & 3 deletions ras_party/controllers/enrolments_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
from sqlalchemy.orm.exc import NoResultFound

from ras_party.controllers.queries import (
query_enrolment_by_survey_business_respondent,
query_respondent_by_party_uuid,
query_respondent_enrolments,
)
from ras_party.models.models import Enrolment
from ras_party.controllers.survey_controller import get_surveys_details
from ras_party.models.models import Enrolment, RespondentStatus
from ras_party.support.session_decorator import with_query_only_db_session

logger = structlog.wrap_logger(logging.getLogger(__name__))
Expand All @@ -20,11 +22,50 @@ def respondent_enrolments(
session: session, party_uuid: UUID, business_id: UUID = None, survey_id: UUID = None, status: int = None
) -> list[Enrolment]:
"""
returns a list of respondent Enrolments. Business_id, survey_id and status can also be added as conditions
returns a list of respondent enrolments with business and survey details
"""

respondent = query_respondent_by_party_uuid(party_uuid, session)
if not respondent:
raise NoResultFound

return query_respondent_enrolments(session, respondent.id, business_id, survey_id, status)
enrolments = query_respondent_enrolments(session, respondent.id, business_id, survey_id, status)

if not enrolments:
return []

surveys_details = get_surveys_details()
respondents_enrolled = []
for enrolment, business_ref, business_attributes in enrolments:
survey_id = enrolment.survey_id
respondents_enrolled.append(
(
{
"enrolment_status": enrolment.status.name,
"business_details": {
"id": enrolment.business_id,
"name": business_attributes["name"],
"trading_as": business_attributes["trading_as"],
"ref": business_ref,
},
"survey_details": {
"id": survey_id,
"long_name": surveys_details.get(survey_id)["long_name"],
"short_name": surveys_details.get(survey_id)["short_name"],
"ref": surveys_details.get(survey_id)["ref"],
},
}
)
)
return respondents_enrolled


@with_query_only_db_session
def is_respondent_enrolled(party_uuid: UUID, business_id: UUID, survey_id: UUID, session: session) -> bool:
respondent = query_respondent_by_party_uuid(party_uuid, session)

if respondent and respondent.status == RespondentStatus.ACTIVE:
enrolment = query_enrolment_by_survey_business_respondent(respondent.id, business_id, survey_id, session)
if enrolment:
return True
return False
8 changes: 7 additions & 1 deletion ras_party/controllers/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,4 +660,10 @@ def query_respondent_enrolments(
if status:
additional_conditions.append(Enrolment.status == status)

return session.query(Enrolment).filter(and_(Enrolment.respondent_id == respondent_id, *additional_conditions)).all()
return (
session.query(Enrolment, Business.business_ref, BusinessAttributes.attributes)
.join(Business, Business.party_uuid == Enrolment.business_id)
.join(BusinessAttributes, BusinessAttributes.business_id == Enrolment.business_id)
.filter(and_(Enrolment.respondent_id == respondent_id, *additional_conditions))
.all()
)
13 changes: 0 additions & 13 deletions ras_party/controllers/respondent_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
)
from ras_party.controllers.notify_gateway import NotifyGateway
from ras_party.controllers.queries import (
query_enrolment_by_survey_business_respondent,
query_respondent_by_email,
query_respondent_by_names_and_emails,
query_respondent_by_party_uuid,
Expand All @@ -26,7 +25,6 @@
Enrolment,
PendingEnrolment,
Respondent,
RespondentStatus,
)
from ras_party.support.session_decorator import (
with_db_session,
Expand Down Expand Up @@ -251,14 +249,3 @@ def get_respondents_by_survey_and_business_id(survey_id: UUID, business_id: UUID
)

return respondents_enrolled


@with_query_only_db_session
def is_user_enrolled(party_uuid: UUID, business_id: UUID, survey_id: UUID, session: session) -> bool:
respondent = query_respondent_by_party_uuid(party_uuid, session)

if respondent and respondent.status == RespondentStatus.ACTIVE:
enrolment = query_enrolment_by_survey_business_respondent(respondent.id, business_id, survey_id, session)
if enrolment:
return True
return False
31 changes: 31 additions & 0 deletions ras_party/controllers/survey_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import logging

import requests
import structlog
from flask import current_app
from requests.exceptions import ConnectionError, HTTPError, Timeout

from ras_party.exceptions import ServiceUnavailableException

logger = structlog.wrap_logger(logging.getLogger(__name__))


def get_surveys_details() -> dict:
url = f'{current_app.config["SURVEY_URL"]}/surveys'
try:
response = requests.get(
url, auth=(current_app.config["SECURITY_USER_NAME"], current_app.config["SECURITY_USER_PASSWORD"])
)
response.raise_for_status()
except HTTPError:
logger.error("Survey returned a HTTPError")
raise
except ConnectionError:
raise ServiceUnavailableException("Survey service returned a connection error", 503)
except Timeout:
raise ServiceUnavailableException("Survey service has timed out", 504)

return {
survey["id"]: {"short_name": survey["shortName"], "long_name": survey["longName"], "ref": survey["surveyRef"]}
for survey in response.json()
}
11 changes: 11 additions & 0 deletions ras_party/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@ def __init__(self, description=None, error=None, **kwargs):
self.error = error
for k, v in kwargs.items():
self.__dict__[k] = v


class ServiceUnavailableException(Exception):
status_code = 500

def __init__(self, errors, status_code=None):
self.errors = errors if isinstance(errors, list) else [errors]
self.status_code = status_code

def to_dict(self):
return {"errors": self.errors}
20 changes: 18 additions & 2 deletions ras_party/views/enrolments_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
from sqlalchemy.orm.exc import NoResultFound
from werkzeug.exceptions import BadRequest, NotFound

from ras_party.controllers.enrolments_controller import respondent_enrolments
from ras_party.controllers.enrolments_controller import (
is_respondent_enrolled,
respondent_enrolments,
)
from ras_party.uuid_helper import is_valid_uuid4

logger = structlog.wrap_logger(logging.getLogger(__name__))
Expand Down Expand Up @@ -58,4 +61,17 @@ def get_respondent_enrolments(party_uuid: UUID) -> Response:
)
return BadRequest()

return make_response([enrolment.to_dict() for enrolment in enrolments], 200)
return make_response(enrolments, 200)


@enrolments_view.route(
"/is_respondent_enrolled/<party_uuid>/business_id/<business_id>/survey_id/<survey_id>", methods=["GET"]
)
def get_is_respondent_enrolled(party_uuid: UUID, business_id: UUID, survey_id: UUID) -> Response:
if not (is_valid_uuid4(party_uuid) and is_valid_uuid4(business_id) and is_valid_uuid4(survey_id)):
return make_response("Bad request, party_uuid, business or survey id not UUID", 400)

enrolled_status = is_respondent_enrolled(party_uuid=party_uuid, business_id=business_id, survey_id=survey_id)
if enrolled_status:
return make_response({"enrolled": True}, 200)
return make_response({"enrolled": False}, 200)
3 changes: 2 additions & 1 deletion ras_party/views/respondent_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from werkzeug.exceptions import BadRequest

from ras_party.controllers import respondent_controller
from ras_party.controllers.enrolments_controller import is_respondent_enrolled
from ras_party.uuid_helper import is_valid_uuid4

logger = structlog.wrap_logger(logging.getLogger(__name__))
Expand Down Expand Up @@ -132,7 +133,7 @@ def validate_respondent_claim():
if not (is_valid_uuid4(party_uuid) and is_valid_uuid4(business_id) and is_valid_uuid4(survey_id)):
return make_response("Bad request, party_uuid, business or survey id not UUID", 400)

if respondent_controller.is_user_enrolled(party_uuid, business_id, survey_id):
if is_respondent_enrolled(party_uuid, business_id, survey_id):
return make_response("Valid", 200)

return make_response("Invalid", 200)
Expand Down
9 changes: 9 additions & 0 deletions test/party_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,12 @@ def get_respondent_enrolments(self, party_id, payload={}):
f"/party-api/v1/enrolments/respondent/{party_id}", json=payload, headers=self.auth_headers
)
return response

def get_respondent_is_enrolments(self, party_uuid, business_id, survey_id):
response = self.client.get(
f"/party-api/v1/enrolments/is_respondent_enrolled/{party_uuid}"
f"/business_id/{business_id}"
f"/survey_id/{survey_id}",
headers=self.auth_headers,
)
return response
Loading

0 comments on commit 937a847

Please sign in to comment.