Skip to content

Commit

Permalink
Release 2023.12.1 (#1807)
Browse files Browse the repository at this point in the history
  • Loading branch information
angela-tran committed Dec 1, 2023
2 parents e21602f + 36fd3ba commit a88dff6
Show file tree
Hide file tree
Showing 38 changed files with 547 additions and 116 deletions.
9 changes: 5 additions & 4 deletions .devcontainer/devcontainer.json
Expand Up @@ -20,18 +20,19 @@
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"bungcip.better-toml",
"batisteo.vscode-django",
"bpruitt-goddard.mermaid-markdown-syntax-highlighting",
"eamodio.gitlens",
"esbenp.prettier-vscode",
"hashicorp.terraform",
"mhutchie.git-graph",
"monosans.djlint",
"ms-python.python",
"ms-python.vscode-pylance",
"mrorz.language-gettext",
"qwtel.sqlite-viewer"
"ms-python.python",
"ms-python.black-formatter",
"ms-python.flake8",
"qwtel.sqlite-viewer",
"tamasfe.even-better-toml"
]
}
}
Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/deploy.yml
Expand Up @@ -22,6 +22,21 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- uses: actions/setup-python@v4
with:
python-version-file: .github/workflows/.python-version
cache: pip
cache-dependency-path: "**/pyproject.toml"

- name: Write python packages to file
run: |
python -m venv .venv
source .venv/bin/activate
pip install pipdeptree
pip install -e .
pipdeptree
pipdeptree >> benefits/static/requirements.txt
- name: Write commit SHA to file
run: echo "${{ github.sha }}" >> benefits/static/sha.txt

Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/tests-pytest.yml
Expand Up @@ -5,6 +5,14 @@ on: [push, pull_request]
jobs:
pytest:
runs-on: ubuntu-latest
permissions:
# Gives the action the necessary permissions for publishing new
# comments in pull requests.
pull-requests: write
# Gives the action the necessary permissions for pushing data to the
# python-coverage-comment-action branch, and for editing existing
# comments (to avoid publishing multiple comments in the same PR)
contents: write
steps:
- name: Check out code
uses: actions/checkout@v4
Expand Down Expand Up @@ -34,3 +42,10 @@ jobs:
with:
name: coverage-report
path: benefits/static/coverage

- name: Coverage comment
uses: py-cov-action/python-coverage-comment-action@v3
with:
GITHUB_TOKEN: ${{ github.token }}
MINIMUM_GREEN: 90
MINIMUM_ORANGE: 80
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -10,3 +10,4 @@ benefits/static/sha.txt
__pycache__/
.coverage
.DS_Store
.venv
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Expand Up @@ -15,13 +15,13 @@ default_stages:

repos:
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v2.4.0
rev: v3.0.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: mixed-line-ending
Expand All @@ -34,7 +34,7 @@ repos:
args: ["--maxkb=1500"]

- repo: https://github.com/psf/black
rev: 23.9.1
rev: 23.11.0
hooks:
- id: black
types:
Expand All @@ -55,12 +55,12 @@ repos:
files: .py$

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.3
rev: v3.1.0
hooks:
- id: prettier
types_or: [javascript, css]

- repo: https://github.com/Riverside-Healthcare/djLint
rev: v1.32.1
rev: v1.34.0
hooks:
- id: djlint-django
11 changes: 2 additions & 9 deletions .vscode/settings.json
Expand Up @@ -12,17 +12,10 @@
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"[python]": {
"editor.defaultFormatter": "ms-python.python"
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.formatting.provider": "black",
"python.languageServer": "Pylance",
"python.linting.enabled": true,
"python.linting.flake8Enabled": true,
"python.testing.pytestArgs": [
"tests/pytest",
"--import-mode=importlib",
"--no-migrations"
],
"python.testing.pytestArgs": ["tests/pytest"],
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"[terraform]": {
Expand Down
2 changes: 1 addition & 1 deletion appcontainer/nginx.conf
Expand Up @@ -52,7 +52,7 @@ http {

# 404 known scraping file targets
# case-insensitive regex matches the given file extension anywhere in the request path
location ~* /.*\.(ash|asp|axd|cgi|com|env|json|php|ping|xml|ya?ml) {
location ~* /.*\.(ash|asp|axd|cgi|com|db|env|json|php|ping|sqlite|xml|ya?ml) {
access_log off;
log_not_found off;
return 404;
Expand Down
40 changes: 35 additions & 5 deletions benefits/core/migrations/0002_data.py
Expand Up @@ -28,13 +28,25 @@ def load_data(app, *args, **kwargs):
sbmtd_senior_type = EligibilityType.objects.create(
name="senior", label="Senior Discount (SBMTD)", group_id=os.environ.get("SBMTD_SENIOR_GROUP_ID", "group4")
)
sbmtd_mobility_pass_type = EligibilityType.objects.create(
name="mobility_pass",
label="Mobility Pass Discount (SBMTD)",
group_id=os.environ.get("SBMTD_MOBILITY_PASS_GROUP_ID", "group5"),
)

PemData = app.get_model("core", "PemData")

server_public_key = PemData.objects.create(
mst_server_public_key = PemData.objects.create(
label="Eligibility server public key",
remote_url=os.environ.get(
"SERVER_PUBLIC_KEY_URL", "https://raw.githubusercontent.com/cal-itp/eligibility-server/dev/keys/server.pub"
"MST_SERVER_PUBLIC_KEY_URL", "https://raw.githubusercontent.com/cal-itp/eligibility-server/dev/keys/server.pub"
),
)

sbmtd_server_public_key = PemData.objects.create(
label="Eligibility server public key",
remote_url=os.environ.get(
"SBMTD_SERVER_PUBLIC_KEY_URL", "https://raw.githubusercontent.com/cal-itp/eligibility-server/dev/keys/server.pub"
),
)

Expand Down Expand Up @@ -192,7 +204,7 @@ def load_data(app, *args, **kwargs):
api_auth_header=os.environ.get("COURTESY_CARD_VERIFIER_API_AUTH_HEADER", "X-Server-API-Key"),
api_auth_key=os.environ.get("COURTESY_CARD_VERIFIER_API_AUTH_KEY", "server-auth-token"),
eligibility_type=mst_courtesy_card_type,
public_key=server_public_key,
public_key=mst_server_public_key,
jwe_cek_enc=os.environ.get("COURTESY_CARD_VERIFIER_JWE_CEK_ENC", "A256CBC-HS512"),
jwe_encryption_alg=os.environ.get("COURTESY_CARD_VERIFIER_JWE_ENCRYPTION_ALG", "RSA-OAEP"),
jws_signing_alg=os.environ.get("COURTESY_CARD_VERIFIER_JWS_SIGNING_ALG", "RS256"),
Expand Down Expand Up @@ -220,6 +232,23 @@ def load_data(app, *args, **kwargs):
start_template="eligibility/start--senior.html",
)

sbmtd_mobility_pass_verifier = EligibilityVerifier.objects.create(
name=os.environ.get("MOBILITY_PASS_VERIFIER_NAME", "Eligibility Server Verifier"),
active=os.environ.get("MOBILITY_PASS_VERIFIER_ACTIVE", "True").lower() == "true",
api_url=os.environ.get("MOBILITY_PASS_VERIFIER_API_URL", "http://server:8000/verify"),
api_auth_header=os.environ.get("MOBILITY_PASS_VERIFIER_API_AUTH_HEADER", "X-Server-API-Key"),
api_auth_key=os.environ.get("MOBILITY_PASS_VERIFIER_API_AUTH_KEY", "server-auth-token"),
eligibility_type=sbmtd_mobility_pass_type,
public_key=sbmtd_server_public_key,
jwe_cek_enc=os.environ.get("MOBILITY_PASS_VERIFIER_JWE_CEK_ENC", "A256CBC-HS512"),
jwe_encryption_alg=os.environ.get("MOBILITY_PASS_VERIFIER_JWE_ENCRYPTION_ALG", "RSA-OAEP"),
jws_signing_alg=os.environ.get("MOBILITY_PASS_VERIFIER_JWS_SIGNING_ALG", "RS256"),
auth_provider=None,
selection_label_template="eligibility/includes/selection-label--sbmtd-mobility-pass.html",
start_template="eligibility/start--sbmtd-mobility-pass.html",
form_class="benefits.eligibility.forms.SBMTDMobilityPass",
)

PaymentProcessor = app.get_model("core", "PaymentProcessor")

mst_payment_processor = PaymentProcessor.objects.create(
Expand Down Expand Up @@ -337,9 +366,10 @@ def load_data(app, *args, **kwargs):
index_template="core/index--sbmtd.html",
eligibility_index_template="eligibility/index--sbmtd.html",
enrollment_success_template="enrollment/success--sbmtd.html",
help_template="core/includes/help--sbmtd.html",
)
sbmtd_agency.eligibility_types.set([sbmtd_senior_type])
sbmtd_agency.eligibility_verifiers.set([sbmtd_senior_verifier])
sbmtd_agency.eligibility_types.set([sbmtd_senior_type, sbmtd_mobility_pass_type])
sbmtd_agency.eligibility_verifiers.set([sbmtd_senior_verifier, sbmtd_mobility_pass_verifier])


class Migration(migrations.Migration):
Expand Down
8 changes: 8 additions & 0 deletions benefits/core/templates/core/includes/help--sbmtd.html
@@ -0,0 +1,8 @@
{% load i18n %}

<h2 class="h2-sm pt-4 pt-lg-8" id="mst-courtesy-card">{% translate "What is a Mobility Pass?" %}</h2>
<p class="pt-2 pt-lg-4">
{% blocktranslate trimmed %}
The Santa Barbara Metropolitan Transit District issues Mobility Pass cards to eligible riders. This transit benefit may need to be renewed in the future based on the expiration date of the Mobility Pass. Learn more at the <a href="https://sbmtd.gov/fares-passes/" target="_blank" rel="noopener noreferrer">SBMTD Fares & Passes</a>.
{% endblocktranslate %}
</p>
23 changes: 23 additions & 0 deletions benefits/eligibility/forms.py
Expand Up @@ -156,3 +156,26 @@ def __init__(self, *args, **kwargs):
*args,
**kwargs,
)


class SBMTDMobilityPass(EligibilityVerificationForm):
"""EligibilityVerification form for the SBMTD Mobility Pass."""

def __init__(self, *args, **kwargs):
super().__init__(
title=_("Agency card information"),
headline=_("Let’s see if we can confirm your eligibility."),
blurb=_("Please input your Mobility Pass number and last name below to confirm your eligibility."),
name_label=_("Last name (as it appears on Mobility Pass card)"),
name_placeholder="Garcia",
name_help_text=_("We use this to help confirm your Mobility Pass."),
sub_label=_("SBMTD Mobility Pass number"),
sub_help_text=_("This is a 4-digit number on the back of your card."),
sub_placeholder="1234",
name_max_length=255,
sub_input_mode="numeric",
sub_max_length=4,
sub_pattern=r"\d{4}",
*args,
**kwargs,
)
@@ -0,0 +1,15 @@
{% extends "eligibility/includes/media-item--idcardcheck.html" %}

{% load i18n %}

{% block heading %}
{% translate "Your current Mobility Pass number" %}
{% endblock heading %}

{% block body %}
<div class="media-body--details">
<p>
{% translate "You do not need to have your physical card, but you will need your 4-digit Mobility Pass number on the back of the card." %}
</p>
</div>
{% endblock body %}
@@ -0,0 +1,10 @@
{% extends "eligibility/includes/selection-label.html" %}
{% load i18n %}

{% block label %}
{% translate "SBMTD Mobility Pass" %}
{% endblock label %}

{% block description %}
{% translate "This option is for people who have a current SBMTD Mobility Pass." %}
{% endblock description %}
@@ -0,0 +1,25 @@
{% extends "eligibility/start.html" %}
{% load i18n %}

{% block page-title %}
{% translate "Agency card overview" %}
{% endblock page-title %}

{% block headline %}
<div class="col-lg-8">
<h1>{% translate "You selected a Mobility Pass transit benefit." %}</h1>
</div>
{% endblock headline %}

{% block media-item %}
{% include "eligibility/includes/media-item--idcardcheck--start--sbmtd-mobility-pass.html" %}
{% endblock media-item %}

{% block call-to-action %}
<div class="row d-flex justify-content-lg-end">
<div class="col-lg-3 offset-2 offset-sm-2 offset-lg-0 col-sm-8 col-8">
{% url "eligibility:confirm" as button_url %}
<a href="{{ button_url }}" class="btn btn-lg btn-primary" role="button">{% translate "Continue" %}</a>
</div>
</div>
{% endblock call-to-action %}
16 changes: 5 additions & 11 deletions benefits/enrollment/api.py
Expand Up @@ -65,7 +65,7 @@ def __init__(self, response):
class GroupResponse:
"""Benefits Enrollment Customer Group API response."""

def __init__(self, response, requested_id, payload=None):
def __init__(self, response, requested_id, group_id, payload=None):
if payload is None:
try:
payload = response.json()
Expand All @@ -74,18 +74,12 @@ def __init__(self, response, requested_id, payload=None):
else:
try:
# Group API uses an error response (500) to indicate that the customer already exists in the group (!!!)
# The error message should contain the customer ID we sent via payload and start with "Duplicate"
# The error message should contain the customer ID and group ID we sent via payload
error = response.json()["errors"][0]
customer_id = payload[0]
detail = error["detail"]

failure = (
customer_id is None
or detail is None
or customer_id not in detail
or customer_id in detail
and not detail.startswith("Duplicate")
)
failure = customer_id is None or detail is None or not (customer_id in detail and group_id in detail)

if failure:
raise ApiError("Invalid response format")
Expand Down Expand Up @@ -269,10 +263,10 @@ def enroll(self, customer_token, group_id):

if r.status_code in (200, 201):
logger.info("Customer enrolled in group")
return GroupResponse(r, customer.id)
return GroupResponse(r, customer.id, group_id)
elif r.status_code == 500:
logger.info("Customer already exists in group")
return GroupResponse(r, customer.id, payload=payload)
return GroupResponse(r, customer.id, group_id, payload=payload)
else:
r.raise_for_status()
except requests.ConnectionError:
Expand Down
12 changes: 5 additions & 7 deletions benefits/enrollment/templates/enrollment/retry.html
Expand Up @@ -26,14 +26,12 @@ <h1 class="h2 text-center">
<div class="col-lg-8">{% include "core/includes/agency-links.html" %}</div>
</div>

{% if retry_button %}
<div class="row pt-8 justify-content-center">
<div class="col-lg-3 col-8">
{% translate "Try again" as button_text %}
{% include "core/includes/button--origin.html" with button_text=button_text %}
</div>
<div class="row pt-8 justify-content-center">
<div class="col-lg-3 col-8">
{% translate "Try again" as button_text %}
{% include "core/includes/button--origin.html" with button_text=button_text %}
</div>
{% endif %}
</div>

</div>
{% endblock main-content %}

0 comments on commit a88dff6

Please sign in to comment.