-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(models): split into multiple files
Take all models defined in benefits/core/models.py and split into files to group models by domain: * benefits/core/models/common.py: common fields/models, helper functions * benefits/core/models/claims.py: ClaimProvider model * benefits/core/models/enrollment.py: EnrollmentFlow, EnrollmentEvent models * benefits/core/models/transit.py: TransitProvider, TransitAgency models Maintain existing imports via top-level benefits/core/models/__init__.py
- Loading branch information
1 parent
9817033
commit dcde528
Showing
12 changed files
with
796 additions
and
711 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,36 @@ | ||
# Generated by Django 5.1.4 on 2025-01-03 01:59 | ||
|
||
import benefits.core.models.common | ||
import benefits.secrets | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("core", "0032_optionalfields"), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name="pemdata", | ||
name="label", | ||
field=models.TextField(help_text="Human description of the PEM data"), | ||
), | ||
migrations.AlterField( | ||
model_name="pemdata", | ||
name="remote_url", | ||
field=models.TextField(blank=True, default="", help_text="Public URL hosting the utf-8 encoded PEM text"), | ||
), | ||
migrations.AlterField( | ||
model_name="pemdata", | ||
name="text_secret_name", | ||
field=benefits.core.models.common.SecretNameField( | ||
blank=True, | ||
default="", | ||
help_text="The name of a secret with data in utf-8 encoded PEM text format", | ||
max_length=127, | ||
validators=[benefits.secrets.SecretNameValidator()], | ||
), | ||
), | ||
] |
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,18 @@ | ||
from .common import template_path, SecretNameField, PemData | ||
from .claims import ClaimsProvider | ||
from .transit import agency_logo_large, agency_logo_small, TransitProcessor, TransitAgency | ||
from .enrollment import EnrollmentMethods, EnrollmentFlow, EnrollmentEvent | ||
|
||
__all__ = [ | ||
"template_path", | ||
"SecretNameField", | ||
"PemData", | ||
"ClaimsProvider", | ||
"agency_logo_large", | ||
"agency_logo_small", | ||
"TransitProcessor", | ||
"TransitAgency", | ||
"EnrollmentMethods", | ||
"EnrollmentFlow", | ||
"EnrollmentEvent", | ||
] |
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,29 @@ | ||
from django.db import models | ||
|
||
from .common import SecretNameField | ||
|
||
|
||
class ClaimsProvider(models.Model): | ||
"""An entity that provides claims for eligibility verification.""" | ||
|
||
id = models.AutoField(primary_key=True) | ||
sign_out_button_template = models.TextField(default="", blank=True, help_text="Template that renders sign-out button") | ||
sign_out_link_template = models.TextField(default="", blank=True, help_text="Template that renders sign-out link") | ||
client_name = models.TextField(help_text="Unique identifier used to register this claims provider with Authlib registry") | ||
client_id_secret_name = SecretNameField( | ||
help_text="The name of the secret containing the client ID for this claims provider" | ||
) | ||
authority = models.TextField(help_text="The fully qualified HTTPS domain name for an OAuth authority server") | ||
scheme = models.TextField(help_text="The authentication scheme to use") | ||
|
||
@property | ||
def supports_sign_out(self): | ||
return bool(self.sign_out_button_template) or bool(self.sign_out_link_template) | ||
|
||
@property | ||
def client_id(self): | ||
secret_name_field = self._meta.get_field("client_id_secret_name") | ||
return secret_name_field.secret_value(self) | ||
|
||
def __str__(self) -> str: | ||
return self.client_name |
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,91 @@ | ||
from functools import cached_property | ||
import logging | ||
from pathlib import Path | ||
|
||
from django import template | ||
from django.conf import settings | ||
from django.db import models | ||
|
||
import requests | ||
|
||
from benefits.secrets import NAME_VALIDATOR, get_secret_by_name | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def template_path(template_name: str) -> Path: | ||
"""Get a `pathlib.Path` for the named template, or None if it can't be found. | ||
A `template_name` is the app-local name, e.g. `enrollment/success.html`. | ||
Adapted from https://stackoverflow.com/a/75863472. | ||
""" | ||
if template_name: | ||
for engine in template.engines.all(): | ||
for loader in engine.engine.template_loaders: | ||
for origin in loader.get_template_sources(template_name): | ||
path = Path(origin.name) | ||
if path.exists() and path.is_file(): | ||
return path | ||
return None | ||
|
||
|
||
class SecretNameField(models.SlugField): | ||
"""Field that stores the name of a secret held in a secret store. | ||
The secret value itself MUST NEVER be stored in this field. | ||
""" | ||
|
||
description = """Field that stores the name of a secret held in a secret store. | ||
Secret names must be between 1-127 alphanumeric ASCII characters or hyphen characters. | ||
The secret value itself MUST NEVER be stored in this field. | ||
""" | ||
|
||
def __init__(self, *args, **kwargs): | ||
kwargs["validators"] = [NAME_VALIDATOR] | ||
# although the validator also checks for a max length of 127 | ||
# this setting enforces the length at the database column level as well | ||
kwargs["max_length"] = 127 | ||
# the default is False, but this is more explicit | ||
kwargs["allow_unicode"] = False | ||
super().__init__(*args, **kwargs) | ||
|
||
def secret_value(self, instance): | ||
"""Get the secret value from the secret store.""" | ||
secret_name = getattr(instance, self.attname) | ||
return get_secret_by_name(secret_name) | ||
|
||
|
||
class PemData(models.Model): | ||
"""API Certificate or Key in PEM format.""" | ||
|
||
id = models.AutoField(primary_key=True) | ||
label = models.TextField(help_text="Human description of the PEM data") | ||
text_secret_name = SecretNameField( | ||
default="", blank=True, help_text="The name of a secret with data in utf-8 encoded PEM text format" | ||
) | ||
remote_url = models.TextField(default="", blank=True, help_text="Public URL hosting the utf-8 encoded PEM text") | ||
|
||
def __str__(self): | ||
return self.label | ||
|
||
@cached_property | ||
def data(self): | ||
""" | ||
Attempts to get data from `remote_url` or `text_secret_name`, with the latter taking precendence if both are defined. | ||
""" | ||
remote_data = None | ||
secret_data = None | ||
|
||
if self.remote_url: | ||
remote_data = requests.get(self.remote_url, timeout=settings.REQUESTS_TIMEOUT).text | ||
if self.text_secret_name: | ||
try: | ||
secret_field = self._meta.get_field("text_secret_name") | ||
secret_data = secret_field.secret_value(self) | ||
except Exception: | ||
secret_data = None | ||
|
||
return secret_data if secret_data is not None else remote_data |
Oops, something went wrong.