Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: agency logos configurable via Admin #2514

Merged
merged 11 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ DJANGO_SUPERUSER_EMAIL=benefits-admin@calitp.org
DJANGO_SUPERUSER_PASSWORD=superuser12345!

DJANGO_DB_RESET=true
DJANGO_DB_DIR=.
DJANGO_STORAGE_DIR=.
DJANGO_DB_FILE=django.db
DJANGO_DB_FIXTURES="benefits/core/migrations/local_fixtures.json"

Expand Down
7 changes: 7 additions & 0 deletions appcontainer/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ http {
add_header Cache-Control public;
}

# path for uploaded files
location /media/ {
alias /home/calitp/app/data/uploads/;
expires 1y;
add_header Cache-Control public;
}

location / {
# checks for static file, if not found proxy to app
try_files $uri @proxy_to_app;
Expand Down
12 changes: 11 additions & 1 deletion benefits/core/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def unique_values(original_list):


def _agency_context(agency: models.TransitAgency):
return {
agency_context = {
"eligibility_index_url": agency.eligibility_index_url,
"help_templates": unique_values([f.help_template for f in agency.enrollment_flows.all() if f.help_template]),
"info_url": agency.info_url,
Expand All @@ -25,6 +25,16 @@ def _agency_context(agency: models.TransitAgency):
"slug": agency.slug,
}

if agency.logo_large and agency.logo_small:
agency_context.update(
{
"logo_small_url": agency.logo_small.url,
"logo_large_url": agency.logo_large.url,
}
)

return agency_context


def agency(request):
"""Context processor adds some information about the active agency to the request context."""
Expand Down
36 changes: 36 additions & 0 deletions benefits/core/migrations/0031_transitagency_logo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 5.1.2 on 2024-11-14 18:05

import benefits.core.models
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0030_enrollmentevent_extra_claims"),
]

operations = [
migrations.AddField(
model_name="transitagency",
name="logo_large",
field=models.ImageField(
blank=True,
default=None,
help_text="The large version of the transit agency's logo.",
null=True,
upload_to=benefits.core.models.agency_logo_large,
),
),
migrations.AddField(
model_name="transitagency",
name="logo_small",
field=models.ImageField(
blank=True,
default=None,
help_text="The small version of the transit agency's logo.",
null=True,
upload_to=benefits.core.models.agency_logo_small,
),
),
]
4 changes: 3 additions & 1 deletion benefits/core/migrations/local_fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@
"transit_processor_client_id": "",
"transit_processor_client_secret_name": "cst-transit-processor-client-secret",
"staff_group": 2,
"customer_service_group": 2
"customer_service_group": 2,
"logo_large": "agencies/cst-lg.png",
"logo_small": "agencies/cst-sm.png"
}
},
{
Expand Down
28 changes: 28 additions & 0 deletions benefits/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from functools import cached_property
import importlib
import logging
import os
import uuid

from django.conf import settings
Expand Down Expand Up @@ -126,6 +127,19 @@ def __str__(self):
return self.name


def _agency_logo(instance, filename, size):
base, ext = os.path.splitext(filename)
return f"agencies/{instance.slug}-{size}" + ext


def agency_logo_small(instance, filename):
return _agency_logo(instance, filename, "sm")


def agency_logo_large(instance, filename):
return _agency_logo(instance, filename, "lg")


class TransitAgency(models.Model):
"""An agency offering transit service."""

Expand Down Expand Up @@ -191,6 +205,20 @@ class TransitAgency(models.Model):
help_text="The group of users who are allowed to do in-person eligibility verification and enrollment.",
related_name="+",
)
logo_large = models.ImageField(
default=None,
null=True,
blank=True,
upload_to=agency_logo_large,
help_text="The large version of the transit agency's logo.",
)
logo_small = models.ImageField(
default=None,
null=True,
blank=True,
upload_to=agency_logo_small,
help_text="The small version of the transit agency's logo.",
)

def __str__(self):
return self.long_name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ <h3 id="{{ aria_labelledby_id }}" class="modal-title h1 p-0 mb-4 pb-lg-2s text-c
<a href="{{ agency.eligibility_index_url }}" class="card m-0 d-inline-block">
<div class="card-body d-flex flex-row-reverse flex-lg-column justify-content-center align-items-center">
<img class="sm d-lg-none ms-auto"
src="{% get_static_prefix %}img/agencies/{{ agency.slug }}-sm.svg"
src="{{ agency.logo_small_url }}"
width="52"
height="36"
alt="{% blocktranslate with agency=agency.short_name %}{{ agency }} logo{% endblocktranslate %}">
<img class="lg d-none d-lg-block"
src="{% get_static_prefix %}img/agencies/{{ agency.slug }}-lg.svg"
src="{{ agency.logo_large_url }}"
width="148"
height="72"
alt="{% blocktranslate with agency=agency.short_name %}{{ agency }} logo{% endblocktranslate %}">
Expand Down
15 changes: 12 additions & 3 deletions benefits/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ def RUNTIME_ENVIRONMENT():

WSGI_APPLICATION = "benefits.wsgi.application"

DATABASE_DIR = os.environ.get("DJANGO_DB_DIR", BASE_DIR)
STORAGE_DIR = os.environ.get("DJANGO_STORAGE_DIR", BASE_DIR)
thekaveman marked this conversation as resolved.
Show resolved Hide resolved
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(DATABASE_DIR, os.environ.get("DJANGO_DB_FILE", "django.db")),
"NAME": os.path.join(STORAGE_DIR, os.environ.get("DJANGO_DB_FILE", "django.db")),
}
}

Expand Down Expand Up @@ -234,14 +234,23 @@ def RUNTIME_ENVIRONMENT():
STATICFILES_DIRS = [os.path.join(BASE_DIR, "benefits", "static")]
# use Manifest Static Files Storage by default
STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": os.environ.get(
"DJANGO_STATICFILES_STORAGE", "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
)
}
},
}
STATIC_ROOT = os.path.join(BASE_DIR, "static")

# User-uploaded files

MEDIA_ROOT = os.path.join(STORAGE_DIR, "uploads/")

MEDIA_URL = "/media/"

# Logging configuration
LOG_LEVEL = os.environ.get("DJANGO_LOG_LEVEL", "DEBUG" if DEBUG else "WARNING")
LOGGING = {
Expand Down
3 changes: 0 additions & 3 deletions benefits/static/img/agencies/cst-lg.svg

This file was deleted.

3 changes: 0 additions & 3 deletions benefits/static/img/agencies/cst-sm.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/mst-lg.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/mst-sm.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/nevco-lg.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/nevco-sm.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/sacrt-lg.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/sacrt-sm.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/sbmtd-lg.svg

This file was deleted.

9 changes: 0 additions & 9 deletions benefits/static/img/agencies/sbmtd-sm.svg

This file was deleted.

5 changes: 5 additions & 0 deletions benefits/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.contrib import admin
from django.http import HttpResponse
from django.urls import include, path
from django.conf.urls.static import static

logger = logging.getLogger(__name__)

Expand All @@ -37,6 +38,10 @@ def trigger_error(request):

urlpatterns.append(path("error/", trigger_error))

# serve user-uploaded media files
# https://docs.djangoproject.com/en/5.1/howto/static-files/#serving-files-uploaded-by-a-user-during-development
urlpatterns.extend(static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT))

# simple route to read a pre-defined "secret"
# this "secret" does not contain sensitive information
# and is only configured in the dev environment for testing/debugging
Expand Down
2 changes: 1 addition & 1 deletion bin/reset_db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ DB_RESET="${DJANGO_DB_RESET:-true}"

if [[ $DB_RESET = true ]]; then
# construct the path to the database file from environment or default
DB_DIR="${DJANGO_DB_DIR:-.}"
DB_DIR="${DJANGO_STORAGE_DIR:-.}"
DB_FILE="${DJANGO_DB_FILE:-django.db}"
DB_PATH="${DB_DIR}/${DB_FILE}"

Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ If blank or an invalid key, analytics events aren't captured (though may still b

A list of strings representing the host/domain names that this Django site can serve.

### `DJANGO_DB_DIR`
### `DJANGO_STORAGE_DIR`

!!! warning "Deployment configuration"

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies = [
"requests==2.32.3",
"sentry-sdk==2.18.0",
"six==1.16.0",
"pillow==11.0.0",
"django-multiselectfield==0.1.13",
]

Expand Down
2 changes: 1 addition & 1 deletion terraform/app_service.tf
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ resource "azurerm_linux_web_app" "main" {

# Django settings
"DJANGO_ALLOWED_HOSTS" = "${local.secret_prefix}django-allowed-hosts)",
"DJANGO_DB_DIR" = "${local.secret_prefix}django-db-dir)",
"DJANGO_STORAGE_DIR" = "${local.secret_prefix}django-storage-dir)",
"DJANGO_DEBUG" = local.is_prod ? null : "${local.secret_prefix}django-debug)",
"DJANGO_LOG_LEVEL" = "${local.secret_prefix}django-log-level)",

Expand Down
22 changes: 21 additions & 1 deletion tests/pytest/core/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@

import pytest

from benefits.core.models import SecretNameField, EnrollmentFlow, TransitAgency, EnrollmentEvent, EnrollmentMethods
from benefits.core.models import (
SecretNameField,
EnrollmentFlow,
TransitAgency,
EnrollmentEvent,
EnrollmentMethods,
agency_logo_small,
agency_logo_large,
)
import benefits.secrets


Expand Down Expand Up @@ -413,6 +421,18 @@ def test_TransitAgency_for_user_in_group_not_linked_to_any_agency():
assert TransitAgency.for_user(user) is None


@pytest.mark.django_db
def test_agency_logo_small(model_TransitAgency):

assert agency_logo_small(model_TransitAgency, "local_filename.png") == "agencies/test-sm.png"


@pytest.mark.django_db
def test_agency_logo_large(model_TransitAgency):

assert agency_logo_large(model_TransitAgency, "local_filename.png") == "agencies/test-lg.png"


@pytest.mark.django_db
def test_EnrollmentEvent_create(model_TransitAgency, model_EnrollmentFlow):
ts = timezone.now()
Expand Down
3 changes: 3 additions & 0 deletions uploads/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!*/
!agencies/cst-*.png
Binary file added uploads/agencies/cst-lg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added uploads/agencies/cst-sm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading