Skip to content

Commit

Permalink
[To Main] DESENG-579: Add language to survey email links (#2507)
Browse files Browse the repository at this point in the history
* Add language to email links
  • Loading branch information
NatSquared authored May 14, 2024
1 parent a94a65a commit 55eb97a
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 60 deletions.
13 changes: 10 additions & 3 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## May 14, 2024

- **Bugfix** Add language code to email links [🎟️ DESENG-579](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-579)
- Added a language code to email template links so that they point to a valid page again
- The system tries to determine the language from the user's browser, but if it can't, it defaults to English
- A future, larger refactor could allow us to remember the user's language preference and always use that

## May 13, 2024

- **Bugfix** Date shown on rejection email preview is incorrect [🎟️ DESENG-597](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-597)
Expand Down Expand Up @@ -33,12 +40,12 @@
- **Feature** Ensure users can belong to more than one tenant [🎟️ DESENG-478](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-478)
- Tested users can belong to more than one tenant.
- Overide the default tenant filter for staff_user table to check with user_group_membership table.

## May 6, 2024

- **Feature** Auto-populate question descriptions [🎟️ DESENG-596](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-596)
- Upgrading the version of met-formio to version 1.0.15-rc1. This version has the changes to have a default
description for the form components. The changes were pushed to met-formio by the PR: https://github.com/bcgov/met-formio/pull/25.
- Upgrading the version of met-formio to version 1.0.15-rc1. This version has the changes to have a default
description for the form components. The changes were pushed to met-formio by the PR: https://github.com/bcgov/met-formio/pull/25.

## May 2, 2024

Expand Down
16 changes: 8 additions & 8 deletions met-api/sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ ACCESS_REQUEST_EMAIL_ADDRESS="[email protected]"

# Site paths for creating emails from templates
SITE_URL=http://localhost:3000
SURVEY_PATH=/surveys/submit/{survey_id}/{token}
SURVEY_PATH=/{lang}/surveys/submit/{survey_id}/{token}
USER_MANAGEMENT_PATH=/usermanagement
SUBMISSION_PATH=/engagements/{engagement_id}/edit/{token}
SUBSCRIBE_PATH=/engagements/{engagement_id}/subscribe/{token}
UNSUBSCRIBE_PATH=/engagements/{engagement_id}/unsubscribe/{participant_id}
ENGAGEMENT_PATH=/engagements/{engagement_id}/view
ENGAGEMENT_PATH_SLUG=/{slug}
ENGAGEMENT_DASHBOARD_PATH=/engagements/{engagement_id}/comments/public
ENGAGEMENT_DASHBOARD_PATH_SLUG=/{slug}/comments/public
SUBMISSION_PATH=/{lang}/engagements/{engagement_id}/edit/{token}
SUBSCRIBE_PATH=/{lang}/engagements/{engagement_id}/subscribe/{token}
UNSUBSCRIBE_PATH=/{lang}/engagements/{engagement_id}/unsubscribe/{participant_id}
ENGAGEMENT_PATH=/{lang}/engagements/{engagement_id}/view
ENGAGEMENT_PATH_SLUG=/{lang}/{slug}
ENGAGEMENT_DASHBOARD_PATH=/{lang}/engagements/{engagement_id}/comments/public
ENGAGEMENT_DASHBOARD_PATH_SLUG=/{lang}/{slug}/comments/public

#CDogs API settings
CDOGS_ACCESS_TOKEN=
Expand Down
18 changes: 10 additions & 8 deletions met-api/src/met_api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ def SQLALCHEMY_DATABASE_URI(self) -> str:
# such as `@gov.bc.ca` . Mainly used for dev and test environments.
SEND_EMAIL_INTERNAL_ONLY = env_truthy('SEND_EMAIL_INTERNAL_ONLY', default=False)

DEFAULT_LANGUAGE = os.getenv('DEFAULT_LANGUAGE', 'en')

EPIC_CONFIG = {
'ENABLED': env_truthy('EPIC_INTEGRATION_ENABLED'),
'JWT_OIDC_ISSUER': os.getenv('EPIC_JWT_OIDC_ISSUER'),
Expand Down Expand Up @@ -237,25 +239,25 @@ def SQLALCHEMY_DATABASE_URI(self) -> str:
# construct the links in the emails sent to users.
PATH_CONFIG = PATHS = {
'SITE': os.getenv('SITE_URL'),
'SURVEY': os.getenv('SURVEY_PATH', '/surveys/submit/{survey_id}/{token}'),
'SURVEY': os.getenv('SURVEY_PATH', '/{lang}/surveys/submit/{survey_id}/{token}'),
'USER_MANAGEMENT': os.getenv('USER_MANAGEMENT_PATH', '/usermanagement'),
'SUBMISSION': os.getenv(
'SUBMISSION_PATH', '/engagements/{engagement_id}/edit/{token}'
'SUBMISSION_PATH', '/{lang}/engagements/{engagement_id}/edit/{token}'
),
'SUBSCRIBE': os.getenv(
'SUBSCRIBE_PATH', '/engagements/{engagement_id}/subscribe/{token}'
'SUBSCRIBE_PATH', '/{lang}/engagements/{engagement_id}/subscribe/{token}'
),
'UNSUBSCRIBE': os.getenv(
'UNSUBSCRIBE_PATH', '/engagements/{engagement_id}/unsubscribe/{participant_id}'
'UNSUBSCRIBE_PATH', '/{lang}/engagements/{engagement_id}/unsubscribe/{participant_id}'
),
'ENGAGEMENT': {
'VIEW': os.getenv('ENGAGEMENT_PATH', '/engagements/{engagement_id}/view'),
'SLUG': os.getenv('ENGAGEMENT_PATH_SLUG', '/{slug}'),
'VIEW': os.getenv('ENGAGEMENT_PATH', '/{lang}/engagements/{engagement_id}/view'),
'SLUG': os.getenv('ENGAGEMENT_PATH_SLUG', '/{lang}/{slug}'),
'DASHBOARD': os.getenv(
'ENGAGEMENT_DASHBOARD_PATH', '/engagements/{engagement_id}/comments/public'
'ENGAGEMENT_DASHBOARD_PATH', '/{lang}/engagements/{engagement_id}/comments/public'
),
'DASHBOARD_SLUG': os.getenv(
'ENGAGEMENT_DASHBOARD_PATH_SLUG', '/{slug}/comments/public'
'ENGAGEMENT_DASHBOARD_PATH_SLUG', '/{lang}/{slug}/comments/public'
),
}
}
Expand Down
3 changes: 2 additions & 1 deletion met-api/src/met_api/schemas/email_verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ class Meta: # pylint: disable=too-few-public-methods
unknown = EXCLUDE

id = fields.Int(data_key='id')
verification_token = fields.Str(data_key='verification_token')
email_address = fields.Str(data_key='email_address')
participant_id = fields.Int(data_key='participant_id')
verification_token = fields.Str(data_key='verification_token')
language_code = fields.Str(data_key='language')
is_active = fields.Bool(data_key='is_active')
survey_id = fields.Int(data_key='survey_id')
type = EnumField(EmailVerificationType, by_value=True)
Expand Down
31 changes: 17 additions & 14 deletions met-api/src/met_api/services/email_verification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def _send_verification_email(email_verification: dict, subscription_type) -> Non
subject, body, args, template_id = EmailVerificationService._render_email_template(
survey,
email_verification.get('verification_token'),
email_verification.get('language_code', current_app.config['DEFAULT_LANGUAGE']),
email_verification.get('type'),
subscription_type,
participant_id
Expand All @@ -125,24 +126,26 @@ def _send_verification_email(email_verification: dict, subscription_type) -> Non
status_code=HTTPStatus.INTERNAL_SERVER_ERROR) from exc

@staticmethod
# pylint: disable-msg=too-many-arguments
def _render_email_template(
survey: SurveyModel,
token,
lang_code: str,
email_type: EmailVerificationType,
subscription_type,
participant_id,
):
if email_type == EmailVerificationType.Subscribe:
return EmailVerificationService._render_subscribe_email_template(
survey, token, subscription_type, participant_id)
survey, token, subscription_type, participant_id, lang_code)
# if email_type == EmailVerificationType.RejectedComment:
# TODO: move reject comment email verification logic here
# return
return EmailVerificationService._render_survey_email_template(survey, token)
return EmailVerificationService._render_survey_email_template(survey, token, lang_code)

@staticmethod
# pylint: disable-msg=too-many-locals
def _render_subscribe_email_template(survey: SurveyModel, token, subscription_type, participant_id):
def _render_subscribe_email_template(survey: SurveyModel, token, subscription_type, participant_id, lang_code):
# url is origin url excluding context path
engagement: EngagementModel = EngagementModel.find_by_id(survey.engagement_id)
tenant_name = EmailVerificationService._get_tenant_name(engagement.tenant_id)
Expand All @@ -155,10 +158,10 @@ def _render_subscribe_email_template(survey: SurveyModel, token, subscription_ty
paths = current_app.config['PATH_CONFIG']
template_id = templates['SUBSCRIBE']['ID']
confirm_path = paths.get('SUBSCRIBE').format(
engagement_id=engagement.id, token=token
engagement_id=engagement.id, token=token, lang=lang_code
)
unsubscribe_path = paths.get('UNSUBSCRIBE').format(
engagement_id=engagement.id, participant_id=participant_id
engagement_id=engagement.id, participant_id=participant_id, lang=lang_code
)
confirm_url = notification.get_tenant_site_url(engagement.tenant_id, confirm_path)
unsubscribe_url = notification.get_tenant_site_url(
Expand Down Expand Up @@ -186,27 +189,26 @@ def _render_subscribe_email_template(survey: SurveyModel, token, subscription_ty
return subject, body, args, template_id

@staticmethod
def _render_survey_email_template(survey: SurveyModel, token):
def _render_survey_email_template(survey: SurveyModel, token, lang_code):
# url is origin url excluding context path
engagement: EngagementModel = EngagementModel.find_by_id(survey.engagement_id)
engagement_name = engagement.name
paths = current_app.config['PATH_CONFIG']
templates = current_app.config['EMAIL_TEMPLATES']
subject_template = templates['VERIFICATION']['SUBJECT']
template = Template.get_template('email_verification.html')
survey_path = paths['SURVEY'].format(survey_id=survey.id, token=token)
engagement_path = EmailVerificationService.get_engagement_path(engagement)
survey_path = paths['SURVEY'].format(survey_id=survey.id, token=token, lang=lang_code)
engagement_path = EmailVerificationService.get_engagement_path(engagement, lang_code=lang_code)
site_url = notification.get_tenant_site_url(engagement.tenant_id)
tenant_name = EmailVerificationService._get_tenant_name(engagement.tenant_id)
args = {
'engagement_name': engagement_name,
'engagement_name': engagement.name,
'survey_url': f'{site_url}{survey_path}',
'engagement_url': f'{site_url}{engagement_path}',
'tenant_name': tenant_name,
'end_date': datetime.strftime(engagement.end_date, EmailVerificationService.full_date_format),
'email_environment': templates['ENVIRONMENT'],
}
subject = subject_template.format(engagement_name=engagement_name)
subject = subject_template.format(engagement_name=engagement.name)
body = template.render(
engagement_name=args.get('engagement_name'),
survey_url=args.get('survey_url'),
Expand All @@ -218,14 +220,15 @@ def _render_survey_email_template(survey: SurveyModel, token):
return subject, body, args, templates['VERIFICATION']['ID']

@staticmethod
def get_engagement_path(engagement: EngagementModel, is_public_url=True):
def get_engagement_path(engagement: EngagementModel, is_public_url=True, lang_code=None):
"""Get an engagement path."""
lang_code = lang_code or current_app.config['DEFAULT_LANGUAGE']
paths = current_app.config['PATH_CONFIG']
if is_public_url:
engagement_slug = EngagementSlugModel.find_by_engagement_id(engagement.id)
if engagement_slug:
return paths['ENGAGEMENT']['SLUG'].format(slug=engagement_slug.slug)
return paths['ENGAGEMENT']['VIEW'].format(engagement_id=engagement.id)
return paths['ENGAGEMENT']['SLUG'].format(slug=engagement_slug.slug, lang=lang_code)
return paths['ENGAGEMENT']['VIEW'].format(engagement_id=engagement.id, lang=lang_code)

@staticmethod
def _get_tenant_name(tenant_id):
Expand Down
13 changes: 7 additions & 6 deletions met-api/src/met_api/services/engagement_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,8 @@ def validate_fields(data):
@staticmethod
def _send_closeout_emails(engagement: EngagementModel) -> None:
"""Send the engagement closeout emails.Throws error if fails."""
subject, body, args = EngagementService._render_email_template(engagement)
lang_code = current_app.config['DEFAULT_LANGUAGE']
subject, body, args = EngagementService._render_email_template(engagement, lang_code)
participants = SubmissionModel.get_engaged_participants(engagement.id)
template_id = current_app.config['EMAIL_TEMPLATES']['CLOSEOUT']['ID']
emails = [participant.decode_email(participant.email_address) for participant in participants]
Expand All @@ -327,9 +328,9 @@ def _send_closeout_emails(engagement: EngagementModel) -> None:
status_code=HTTPStatus.INTERNAL_SERVER_ERROR) from exc

@staticmethod
def _render_email_template(engagement: EngagementModel):
def _render_email_template(engagement: EngagementModel, lang_code):
template = Template.get_template('email_engagement_closeout.html')
dashboard_path = EngagementService._get_dashboard_path(engagement)
dashboard_path = EngagementService._get_dashboard_path(engagement, lang_code)
engagement_url = notification.get_tenant_site_url(engagement.tenant_id, dashboard_path)
templates = current_app.config['EMAIL_TEMPLATES']
subject = templates['CLOSEOUT']['SUBJECT'].format(engagement_name=engagement.name)
Expand All @@ -356,9 +357,9 @@ def _get_tenant_name(tenant_id):
return tenant.name

@staticmethod
def _get_dashboard_path(engagement: EngagementModel):
def _get_dashboard_path(engagement: EngagementModel, lang_code):
engagement_slug = EngagementSlugModel.find_by_engagement_id(engagement.id)
paths = current_app.config['PATH_CONFIG']
if engagement_slug:
return paths['ENGAGEMENT']['DASHBOARD_SLUG'].format(slug=engagement_slug.slug)
return paths['ENGAGEMENT']['DASHBOARD'].format(engagement_id=engagement.id)
return paths['ENGAGEMENT']['DASHBOARD_SLUG'].format(slug=engagement_slug.slug, lang=lang_code)
return paths['ENGAGEMENT']['DASHBOARD'].format(engagement_id=engagement.id, lang=lang_code)
Loading

0 comments on commit 55eb97a

Please sign in to comment.