The Forgejo Actions CI `test` job has never passed — all 24 runs show
failure. Two root causes: the Forgejo `podman` runner's service
container networking doesn't reliably expose the PostgreSQL hostname,
and the CI pipeline doesn't provision RabbitMQ, causing
`fedora_messaging.api.publish()` to raise `ConnectionException`.
Since the codebase uses zero PostgreSQL-specific features, the test
database backend can safely be switched to SQLite in-memory. This
eliminates all external service dependencies for tests.
Changes to test infrastructure:
- Override `DATABASES` in `tsting.py` to use SQLite in-memory
- Add Celery memory broker settings to prevent Redis connections
- Add `CRISPY_ALLOWED_TEMPLATE_PACKS` for `bootstrap5` compatibility
- Set dummy `ADMIN_USERNAME`/`ADMIN_PASSWORD` for FAS `AccountSystem`
- Create `conftest.py` with autouse fixtures to mock `publish()`,
`AccountSystem.people_query()`, and provide a stub `STATIC_ROOT`
Changes to CI pipeline:
- Remove `postgres:15` and `redis:7` service containers
- Remove `gcc`/`libpq-dev` system dependency step
Bug fixes surfaced by the new test environment:
- Replace stale `import ckeditor.fields` in migration 0007 with
`models.TextField` (old `django-ckeditor` removed in Phase 5)
- Pass `link_rel=None` to `nh3.clean()` to fix `ValueError` when `'rel'`
is in `allowed_attributes` (nh3 >= 0.2.18 API change)
Closes#281.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
`AGENTS.md` was stale — still listed Phases 3–5 as upcoming, referenced
Docker Compose and deleted config files, and omitted Bootstrap 5.3 and
CKEditor 5 from the stack description. Updated to reflect all completed
phases through Phase 5, current stack, Podman Compose instructions, and
environment-variable-based configuration.
`README.md` was last updated in 2019 and referenced Pagure, old setup
instructions, and the GSoC 2018 onboarding flow. Rewrote it with the
current stack, a modernization roadmap showing completed and upcoming
phases, a Podman-based quick start guide, and current community links
(Forgejo, Matrix).
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Moved `assets/bootstrap/js/bootstrap.bundle.min.js` to `assets/js/` and
deleted the now-empty `assets/bootstrap/` directory. All frontend assets
now live under `assets/css/`, `assets/js/`, `assets/fonts/`, and
`assets/webfonts/` — no more nested vendor directories.
Cleaned `assets/css/custom.css`:
- Replaced a gradient with four identical color stops with a plain
`background: var(--primary-color)` (the gradient was a no-op)
- Removed dead `.google` share button styles (no Google share button
exists in any template)
Updated stale references:
- `templates/follow.html`: Updated X (formerly Twitter) share URL from
deprecated `intent/tweet` to `intent/post` endpoint
- `templates/base.html`: Updated footer issue tracker links from
Pagure to Forgejo (`forge.fedoraproject.org`)
- `AGENTS.md`: Marked Phases 3–5 as completed, updated stack
description, replaced config file docs with env var docs, updated
Docker references to Podman
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Bootstrap 5 does not require jQuery and the CKEditor 5 migration removed
the last jQuery-dependent inline script. The only remaining consumer was
`fas_details.js` (87 lines of jQuery AJAX and DOM manipulation for the
FAS username lookup).
Rewrote `fas_details.js` using vanilla JavaScript:
- `$.ajax()` → `fetch()` with Promise-based error handling
- `$('#id').val()` → `document.getElementById('id').value`
- `$('#el').after(...)` → `el.insertAdjacentHTML('afterend', ...)`
- `$().fadeIn().delay().fadeOut()` → `setTimeout` with `el.remove()`
- Added a `catch` handler for network errors (jQuery version silently
swallowed fetch failures)
Deleted `assets/js/vendor/jquery-3.3.1.min.js` (87 KB). Removed the
jQuery script tag from `base.html`. Changed both remaining script tags
to use `defer` (removed `async` from Bootstrap bundle — `async` can
cause race conditions with scripts that depend on Bootstrap JS).
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
CKEditor 4 reached end-of-life in June 2023. The `django-ckeditor`
package (6.x) bundles CKEditor 4 and is no longer maintained. Replaced
with `django-ckeditor-5` (0.2.20) which wraps CKEditor 5.
The migration is intentionally minimal — Happiness Packets messages need
basic formatting (bold, italic, links, lists, blockquote) and no more.
Image upload and the smiley plugin are removed. The toolbar is
explicitly restricted to prevent scope creep in user-generated content.
Changes:
- `pyproject.toml`: `django-ckeditor` → `django-ckeditor-5`
- `settings/base.py`: `CKEDITOR_CONFIGS` → `CKEDITOR_5_CONFIGS` with
minimal toolbar; replaced `ckeditor` with `django_ckeditor_5` in
`INSTALLED_APPS`; added `CKEDITOR_5_FILE_STORAGE` setting
- `models.py`: `RichTextField()` →
`CKEditor5Field(config_name='default')`
- `urls.py`: Added `ckeditor5/` URL pattern; guarded `debug_toolbar`
import with `try`/`except` (same pattern as `dev.py`)
- `message_send_form.html`: Removed CKEditor 4 manual script tags and
jQuery image-resize workaround; CKEditor 5 injects its own assets via
`{{ form.media }}`
- New migration 0008: `AlterField from RichTextField` to
`CKEditor5Field` (no data migration — column type stays text, existing
HTML content renders unchanged)
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Bootstrap 4 reached end-of-life in 2024 and its JS requires jQuery.
Bootstrap 5 drops the jQuery dependency, uses modern `data-bs-*`
attributes, and aligns with the `crispy-bootstrap5` template pack
already configured.
Replaced `assets/css/bundle.css` (Bootstrap 4.3.1 + Fedora theme +
Font Awesome, 3,688 lines) with the standard Bootstrap 5.3.6 minified
CSS. The Fedora color utilities, border widths, and font size helpers
that were appended to the old bundle are now in a separate
`assets/css/fedora-theme.css` using CSS custom properties. The Font
Awesome icon definitions duplicated in `bundle.css` are already provided
by `assets/css/all.css` and did not need to be ported.
Replaced `assets/bootstrap/js/bootstrap.bundle.min.js` (4.3.1) with the
Bootstrap 5.3.6 bundle (includes Popper).
Template updates across `base.html`, `_pagination.html`, `archive.html`,
and `search.html`:
- `data-toggle` → `data-bs-toggle`
- `data-target` → `data-bs-target`
- `ml-auto` → `ms-auto`
- `font-weight-bold` → `fw-bold`
- `sr-only` → `visually-hidden`
- `form-inline` → `d-flex`
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Every page load was leaking visitor IPs to Google (fonts.googleapis.com)
and the Fedora CDN (apps.fedoraproject.org). This is a privacy concern
for a Fedora community application and creates a dependency on external
services that may not be maintained.
Downloaded Montserrat (400, 700) and Open Sans (400, 700) as WOFF2 files
from Google Fonts (both are SIL Open Font License) and serve locally
from `assets/fonts/`. Created `assets/css/fonts.css` with `@font-face`
declarations using `font-display: swap` for optimal loading.
Removed four external CDN references from `base.html`:
- Google Fonts CSS (Montserrat + Open Sans)
- Fedora CDN `fedora-bootstrap-1.1.1/fedora-bootstrap.css`
- Fedora CDN `fedora-bootstrap-fonts/open-sans.css`
- Fedora CDN `fedora-bootstrap-fonts/font-awesome.css`
The Fedora CDN's Font Awesome CSS was already superseded by the local
`assets/css/all.css` (Font Awesome 5.1.0). The `fedora-bootstrap.css`
provided a `navigation-bar` class that has no visible effect — the
containing div already has `bg-fedora-blue` and border utilities from
`bundle.css`.
Also reorganized `<head>` to follow standard ordering: CSS before JS.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
The `assets/bootstrap/css/` directory contained Bootstrap 3.1.1 CSS
files from 2014 that were never loaded by any template — the live CSS is
`assets/css/bundle.css` (Bootstrap 4.3.1 + Fedora theme). Similarly,
`bootstrap.js` and `bootstrap.min.js` were Bootstrap 3.1.1 JS files
never referenced anywhere; the active JS bundle is
`bootstrap.bundle.min.js` (Bootstrap 4.3.1). The Glyphicons font files
were also unused — Font Awesome replaced them.
Also added `crispy_bootstrap5` to INSTALLED_APPS. The package was
already a dependency in pyproject.toml and `CRISPY_TEMPLATE_PACK` was
set to `'bootstrap5'`, but the app was never registered, so crispyforms
could not find the Bootstrap 5 template pack.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Two CI fixes:
- Test job: Add `--no-root` to `poetry install`. Poetry 2.x tries to
install the current project as a package, which fails because this is
a Django app with no `packages` config. `--no-root` installs only
dependencies, which is what CI needs.
- Lint job: Add `F405` to ruff's ignore list. Django settings files use
`from .base import *` by convention, which triggers false positives
for every symbol defined in the parent module. Ignoring F405 is the
standard approach for Django projects.
Also fixed all 11 remaining `lint` errors:
- Removed unused imports (logging, django, AuthError, conf,
ValidationError)
- Removed unused variable assignments (`user`, `msg`, `ex`)
- Replaced `== True` comparison with truthy check
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
The Forgejo Actions `checkout@v4` is a JavaScript action that requires
Node.js in the container. `python:3.13-slim` doesn't include it, causing
both lint and test jobs to fail with `executable file 'node' not found
in $PATH`.
Fix: install `nodejs` via `apt` as the first step in each job. The `run`
directive uses the container's shell (not `node`), so it can bootstrap
`node` before the checkout action executes.
Also removed the "Create stub config files" step from the test job. The
Phase 4 settings refactor eliminated all file-based config reading
(`config.yml`, `client_secrets.json`, `fas-admin-details.json`) in favor
of environment variables, and `config.yml.example` was deleted. This
step would fail on checkout since the source file no longer exists.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Without a named volume, RabbitMQ recreates its Mnesia database on every
container restart, losing queue state and requiring the vhost and user
to be re-provisioned. Adding `rabbitmq_data` as a named volume matches
the pattern already used for PostgreSQL (`pgdata`).
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Three small fixes for deprecation warnings and API changes:
- `models.py`: Add raw string prefix (`r'...'`) to regex patterns in
`strip_email()`. Python 3.12 deprecated unrecognized escape sequences
like `\w` and `\+` in regular strings; Python 3.14 now emits
`SyntaxWarning` for these.
- `test_models.py`: Change `factory.DjangoModelFactory` to
`factory.django.DjangoModelFactory`. factory-boy 3.x moved Django
integration to a submodule. The old top-level import raises
`AttributeError`.
- `dev.`py: Guard `debug_toolbar` activation with `try`/`except`
`ImportError` instead of assuming it is always installed. The
production container does not include dev dependencies, so importing
dev settings there (e.g., for management commands) would crash.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
The UBI 9 Python image runs as non-root (UID 1001). Poetry export wrote
`requirements.txt` to `/app` which works in the builder stage but is
fragile — the working directory inherits root-owned permissions from
`COPY`. Writing to `/tmp` is the correct pattern for ephemeral build
artifacts in non-root container images.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
fedora-messaging 3.4.1 imported `pkg_resources` from setuptools at
module load time. Modern `setuptools` (v72+) removed `pkg_resources`
entirely, breaking both local development on Python 3.14 and the multi-
stage container build where COPY overwrote the system `setuptools`.
fedora-messaging 3.9.0 replaced `pkg_resources` with
`importlib.metadata` and `tomli`, eliminating the dependency. This also
allowed removing the `setuptools` workaround from `pyproject.toml` and
the `dnf reinstall` hack from the Containerfile — neither is needed now.
Unlocking the upgrade required adding `<3.15` upper bound to the Python
version constraint. Poetry's resolver validates dependency compatibility
across the full declared Python range, and fedora-messaging 3.5.0+
declares `Requires-Python: <4.0.0`. Our unbounded `>=3.12` implied
compatibility with arbitrarily future Python versions, causing Poetry to
reject all fedora-messaging releases that declared an upper bound. The
`<3.15` constraint honestly reflects the versions we've tested against
and will need a bump when Python 3.15 arrives.
Side effects: `pytz` removed (no longer a fedora-messaging dependency),
`tomli` added (new fedora-messaging dependency for TOML parsing).
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Replace the three config files read at import time (`config.yml`,
`client_secrets.json`, `fas-admin-details.json`) with environment
variables. This was the single biggest barrier to running the app in
containers — Django settings would crash on import if these files did
not exist on disk.
Settings changes (`base.py`):
- Remove `yaml` import and `config.yml` reading entirely
- `ADMINS` set to empty list (Django admin email notifications unused)
- OIDC endpoints configurable via env vars (defaulting to Fedora staging
at `iddev.fedorainfracloud.org`)
- `OIDC_RP_IDP_SIGN_KEY` moved to env var (was hardcoded RSA key)
- New `OIDC_SUPERUSER_USERNAMES` setting (comma-separated env var)
replaces the `config.yml` `auth.admins` list
- `REDIS_HOST` and `REDIS_PORT` configurable via env vars
- Consistent multi-line formatting for all `os.environ.get` calls that
include default values
Settings changes (`dev.py`):
- Remove `client_secrets.json` and `fas-admin-details.json` file reads
(`base.py` already reads OIDC and FAS credentials from env vars)
- Database connection configurable via `DB_HOST`, `DB_NAME`,
`DB_USERNAME`, `DB_PASSWORD` env vars (defaults match
`podman-compose.yml`)
- Remove commented-out Gmail SMTP config
- Remove `import json` (no longer needed)
Auth changes (`auth.py`):
- Remove `yaml` import and `config.yml` reading
- Use `settings.OIDC_SUPERUSER_USERNAMES` instead of
`cfg['auth']['admins']`
- `provider_logout` reads `OIDC_OP_LOGOUT_URL` from env
- Modernize `super(`) calls and bare `except` clause
Container changes:
- `Containerfile`: Install `poetry-plugin-export` (required in Poetry
2.x) and use `poetry export` to generate `requirements.txt` for
`pip install`
- Commit `poetry.lock` for reproducible builds
Also:
- Remove `pyyaml` from `pyproject.toml` (no longer needed)
- Delete `generate_client_secrets.sh` and `config.yml.example`
- Add `.env` to `.gitignore`
- Expand `.env.example` with all new env vars
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
I used the wrong label, and I should have known better anyways since I
would be wanting Podman over Docker any day of the week… ;-)
ref: forge/forge#480 (comment)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
The Containerfile uses the UBI 9 Python 3.12 base image
(`registry.access.redhat.com/ubi9/python-312`), which ships Python
3.12.12. Poetry enforces the python version constraint in
`pyproject.toml` strictly, causing `poetry install` to fail during the
container build with "The currently activated Python version 3.12.12 is
not supported by the project (>=3.14)."
Relax the constraint to `>=3.12` so the project builds on both the UBI 9
image (Python 3.12) and future UBI images with Python 3.14. The codebase
is compatible with both versions — Django 5.1 requires Python 3.10+ and
we use no 3.14-specific features. The constraint can be tightened again
when Red Hat ships a UBI Python 3.14 image.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Replace the broken Docker setup (Python 3.6 Alpine, `pipenv`, hardcoded
credentials) with a modern Podman-based development environment using
Red Hat Universal Base Images for OpenShift compatibility.
`Containerfile` (replaces `Dockerfile`):
- Multi-stage build: builder stage installs Poetry and dependencies,
runtime stage copies only the installed packages for a smaller image
- Base image: UBI 9 Python 3.12 (OpenShift-certified)
- Runs as non-root `USER 1001` (required by OpenShift SCC)
- Gunicorn as the application server instead of Django's runserver
- No longer calls `generate_client_secrets.sh` during build
`podman-compose.yml` (replaces `docker-compose.yml`):
- PostgreSQL 17, Redis 7, RabbitMQ 3 with health checks
- `depends_on` with `service_healthy` conditions instead of links
- Named volume (`pgdata`) for PostgreSQL persistence
- SELinux `:z` labels on bind mounts for Fedora hosts
- Gunicorn with `--reload` for development hot-reload
Also adds:
- `.env.example` — template for local development secrets
- `.containerignore` — excludes .git, secrets, and build artifacts
from the container image
Closes#222.
Closes#265.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
The `AGENTS.md` file still described the pre-modernization state of the
project (Django 2.0, Docker Compose, Pipenv, flake8, Bootstrap 3,
bleach). Update it to accurately reflect the current architecture after
Phases 0 to 2.5:
- Django 5.1 / Python 3.14 / Poetry
- `ruff` for linting, `nh3` for sanitization, Bootstrap 5 crispy pack
- Redis cache (replacing Memcached), Forgejo Actions CI
- Poetry commands instead of `docker-compose exec`
Add a Modernization Vision section that documents the completed and
upcoming phases so contributors (human or AI) understand the broader
context of what's being built and why. This replaces implicit knowledge
that was only in the plan file.
Also adds Git Conventions section documenting the branch naming, commit
message format, issue closing keywords, and AI disclosure practices used
on this project.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Establish automated CI to validate every subsequent change in the
modernization effort. The pipeline runs on all pushes and pull requests
with two jobs:
- lint: Runs ruff against the codebase
- test: Installs Poetry dependencies, creates stub config files
(`config.yml`, `client_secrets.json`, `fas-admin-details.json`) needed
by the Django settings, and runs `pytest` against a PostgreSQL 15 and
Redis 7 service container
Uses `python:3.13-slim` as the container image since Python 3.14 images
may not yet be available on all runner configurations. The stub config
files are necessary because `dev.py` reads `client_secrets.json` and
`fas-admin-details.json` at import time — this will be cleaned up in
`Phase 4 (settings refactoring).
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Replace Pipenv with Poetry for dependency management. Poetry provides
deterministic dependency resolution via `poetry.lock`, clean separation
of dependency groups (production, dev, docs), and a standard PEP 517
build backend (`poetry-core`) that also works with plain `pip`.
Migration details:
- Create `pyproject.toml` with all dependencies from `Pipfile`,
organized into `[tool.poetry.dependencies]` (production),
`[tool.poetry.group.dev.dependencies]` (testing/linting), and
`[tool.poetry.group.docs.dependencies]` (Sphinx)
- Move pytest config from `setup.cfg` `[tool:pytest]` to
`pyproject.toml` `[tool.pytest.ini_options]`
- Move `ruff` config from `setup.cfg` `[ruff]` to `pyproject.toml`
`[tool.ruff]`
- Delete `Pipfile`, `Pipfile.lock`, and `setup.cfg`
Security fix:
- Replace `yaml.full_load()` with `yaml.safe_load()` in `base.py` and
`auth.py`. `full_load` can deserialize arbitrary Python objects from
YAML (including `!!python/tuple`), which is a code execution risk.
Updated `config.yml.example` to use plain YAML lists instead of
`!!python/tuple` tags.
Sets project version to 1.0.0 (semver) to mark the modernized codebase
as a fresh starting point.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Remove 12 packages that are either unmaintained, redundant with the
Python stdlib, or superseded by modern alternatives:
Removed entirely:
- `Unipath` (2012, unmaintained) → `pathlib` (stdlib since Python 3.4)
- `pytz` (pinned to 2015 data) → `zoneinfo` (stdlib since Python 3.9,
used by Django 5.x internally)
- `dogslow` (2012, slow request logger) → removed from settings and
middleware; production observability planned for Phase 10
- `ipython` (dev convenience, not a project dependency)
- `urllib3` (pinned to 2019 with CVEs; transitive dep of requests, pip
resolves it automatically)
- `email-normalize` (never imported anywhere in the codebase)
- `python-memcached` (Memcached client, replaced by Redis in Step 1c)
- `mock` (dev dep, redundant with unittest.mock since Python 3)
- `django-coverage` (dev dep, redundant with pytest-cov)
Replaced:
- `flake8` + `pep8` + `mccabe` + `pyflakes` (all pinned 2015–2016) →
`ruff` (single fast linter/formatter, added to dev deps)
Updated:
- `python-dateutil` ==2.5.0 → >=2.8
- `pyyaml` ==5.1 → >=6.0 (CVE fixes, Python 3.10+ compat)
`Pathlib` migration touched: `base.py` (`PROJECT_DIR` and all path
settings), `dev.py`, `ci.py` (`SELENIUM_SCREENSHOT_DIR`), `tasks.py`
(logo file path).
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Final step in the upgrade path from Django 2.0. Django 5.0+ requires
Python 3.10 or later, so the Pipfile target moves from 3.6 to 3.14.
Code changes required by Django 5.0:
- Update `assertFormError` calls in `test_views.py` (4 occurrences) to
the new signature introduced in Django 4.1: pass the form object
directly instead of `(response, 'form')`. The old signature was
removed in Django 5.0.
Replace `bleach` with `nh3` for HTML sanitization in `forms.py`:
- Bleach is officially deprecated (EOL January 2023) and its
maintainers recommend `nh3` as the replacement.
- `nh3` is a Python binding to the Rust ammonia library — faster and
more secure than `bleach`'s Python-based `html5lib` parsing.
- Inline CSS styles are no longer allowed (`nh3` strips all styles by
design as a security measure). The old `bleach` config permitted
`color`, `font-weight`, and sizing properties. Messages will use the
app's CSS classes instead of author-specified inline styles.
- The allowed tags and attributes are now defined as explicit sets
rather than extending `bleach`'s `ALLOWED_TAGS` default.
Dependency updates:
- `Django` >=5.1 (from ==4.2.18)
- `mozilla-django-oidc` >=4.0 (Django 5.x compat)
- `gunicorn` >=22.0 (from ==19.4.1)
- `bleach` → `nh3` >=0.2.15
- Python target 3.6 → 3.14
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Third step in the upgrade path. Django 4.2 LTS is the bridge between the
3.x and 5.x series, supported through April 2026. This step has the most
breaking changes of any in the upgrade chain.
Settings changes:
- Remove `USE_L10N` (localized formatting is always-on in Django 4.0+)
- Switch `CRISPY_TEMPLATE_PACK` from 'bootstrap3' to 'bootstrap5' since
`django-crispy-forms` 2.0 dropped built-in template packs; the new
`crispy-bootstrap5` package provides Bootstrap 5 form rendering
- Replace Memcached cache backend with Django 4.0's native RedisCache in
`deployment.py`, using a dedicated `REDIS_URL` env var (defaulting to
`redis://localhost:6379/1`, separate from Celery's `/0` database)
Dependency updates:
- `django-extensions` >=2.2 → >=3.2 (Django 4.x compat)
- `django-crispy-forms` >=1.8 → >=2.0 + `crispy-bootstrap5` >=2024.2
- `django-model-utils` >=3.2 → >=4.3
- `celery` >=4.4 → >=5.3 (major version bump, API compatible via
`namespace='CELERY'` config pattern already in use)
- `psycopg2` → `psycopg2-binary` >=2.9 (simpler installation)
- Remove `django-braces` (not imported anywhere; `LoginRequiredMixin`
and other mixins have been in Django core since 1.9)
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Second step in the upgrade path. Django 3.2 LTS was supported through
April 2024 and is the last version to support Python 3.6–3.9. This is
the largest API gap in the upgrade chain — several deprecated patterns
from the Django 1.x/2.x era were removed in 3.0.
Template changes:
- Replace `{% ifequal %}/{% endifequal %}` with `{% if x == y %}`/
`{% endif %}` in `base.html` (3 occurrences). The `ifequal` tag was
deprecated in Django 3.1 and removed in Django 5.0.
Dependency updates for Django 3.2 compatibility:
- `django-haystack` 2.8.1 → >=3.2 (3.x required for Django 3.x)
- `django-ckeditor` 5.7.0 → >=6.0 (CKEditor 4 support updates)
- `django-celery-email` 2.0.1 → >=3.0 (Django 3.x compat)
- `bleach` >=3.1.0 → >=5.0 (security fixes, API stability)
- `factory-boy` 2.9.2 → >=3.2 (Django 3.x compat, no API changes
affecting our test factories)
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
First step in the incremental upgrade path from Django 2.0 to 5.x.
Django 2.0 reached end-of-life in April 2018 and has unpatched security
vulnerabilities. Django 2.2 LTS was supported through April 2022 and
provides a stable intermediate target with minimal breaking changes.
Dependency updates for Django 2.2 compatibility:
- `django-extensions` 1.6.1 → >=2.2 (2.x required for Django 2.2)
- `django-crispy-forms` 1.7.2 → >=1.8 (form rendering changes)
- `django-model-utils` 2.4 → >=3.2 (TimeStampedModel updates)
- `mozilla-django-oidc` 1.2.2 → >=2.0 (Django 2.2 support)
- `celery` 4.2.1 → >=4.4 (last 4.x series before 5.0)
- `psycopg2` 2.7.5 → >=2.8 (PostgreSQL driver updates)
Settings changes:
- Add `DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'` to preserve
the existing integer primary key behavior. Without this, Django 3.2+
would generate unwanted migrations to convert all PKs to BigAutoField.
- Fix `deployment.py` database backend from the deprecated alias
'postgresql_psycopg2' to 'postgresql' (deprecated since Django 1.9,
removed in later versions). `dev.py` already used the correct name.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Remove `syntax: glob` from .gitignore — this is a Mercurial .hgignore
directive that has no effect in git. The project was likely on Mercurial
at some point before migrating to git via Pagure.
Remove `six` from the Pipfile. `six` is a Python 2/3 compatibility layer
that is unnecessary when targeting Python 3 only. It was listed as a
dependency of `django-extensions`, but `django-extensions` dropped its
`six` dependency years ago and `six` is not directly imported anywhere
in this codebase.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Remove `from __future__ import unicode_literals` and `absolute_import`
from all 20 files that had them. These are no-ops on Python 3 and were
left over from when the upstream Happiness Packets project supported
Python 2.
Fix three code issues found during the housekeeping audit:
- `admin.py`: Rename the second `MessageAdmin` class (registered for
`BlacklistedEmail`) to `BlacklistedEmailAdmin`. The duplicate name
shadowed the first class in the module namespace.
- `utils/mixins.py`: Delete entirely. It imports `axes.decorators` from
`django-axes`, which is not in the Pipfile and not installed. The
`AxesControlledMixin` it defines is not used anywhere. The file would
raise ImportError if anything tried to import it.
- `utils/misc.py`: Remove the unused copy of `send_html_mail`. The
active copy lives in `tasks.py` (which `models.py` imports) and
correctly opens the logo file in binary mode ('rb'). The `misc.py`
copy used text mode, which would fail on Python 3 for binary data.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
Facebook's JavaScript SDK initialization (hardcoded App ID
240221016763634 that we don't control) and Google's Platform API script
were loaded on every page but never used by any application feature. The
Google+ interactive post sharing code in follow.html was commented out
since Google+ shut down in April 2019. Remove all three, along
with the `facebook.html` template.
The vendored JS directory contained 13 unused libraries totaling over
1MB: `leaflet/proj4` (mapping), `zxcvbn` (password strength estimation),
`signaturepad`, `flashcanvas` (Flash polyfill), `json2` (IE7 JSON
polyfill), a duplicate jQuery 1.10.1 (project uses 3.3.1),
`bootstrap-datepicker`, and dependent-selects. None were referenced by
any template or Python file. Similarly, `bootstrap-ie7.css` and
`datepicker.css` were unused.
The X/Twitter intent link is preserved in `follow.html` — it's a simple
URL that works without any SDK. Updated the URL from `twitter.com` to
`x.com` and the button text from "Tweet" to "Post" to reflect the
platform's current branding.
Closes#34.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
The gitignore entry for the Django YAML configuration file was
`config.yml` without a leading slash, which matches any file named
`config.yml` anywhere in the repository tree. This caused git to
silently ignore `.forgejo/issue_template/config.yml` — the Forgejo issue
template configuration — preventing it from being tracked.
Prefix the pattern with `/` to restrict it to the root-level Django
config file only, which is the file that actually contains sensitive
admin credentials and must stay untracked.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
The `.forgejo/issue_template/` directory was bootstrapped from two
sources: `config.yml` was imported from another Fedora Forge project and
`default.md` was imported from a different git forge. The `config.yml`
turned out to be that project's Django admin configuration rather than
a Forgejo issue config, and the `default.md` used Markdown-based
templating instead of Forgejo's interactive YAML form syntax.
Replace both files with proper Forgejo issue templates:
- `config.yml`: Forgejo issue config that enables blank issues and links
to the project's ReadTheDocs documentation.
- `default.yml`: Converts the original Markdown template (Summary,
Background, Details, Outcome) into a YAML-defined interactive form.
The structured form fields guide contributors through each section
rather than relying on Markdown headings that are easily deleted or
skipped.
The YAML form syntax is documented at:
https://forgejo.org/docs/latest/user/issue-pull-request-templates/
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
This project has been dormant since August 2021 — nearly five years. The
goal going forward is to make small, incremental changes to bring Fedora
Happiness Packets back into active service within Fedora's
infrastructure as an OpenShift-native containerized application.
As a first step, add an `AGENTS.md` file that captures the architectural
knowledge an AI coding assistant (or any new contributor) needs to be
productive in this codebase without reading every file. The document
covers the Docker Compose development workflow, test/lint commands, the
message lifecycle and its three-party privacy model, the settings
inheritance chain, and the external integration points (Fedora OIDC,
FAS, fedora-messaging, Celery, Haystack).
This is structured as a general-purpose instructions file rather than a
tool-specific one (e.g., CLAUDE.md) so that any AI agent or LLM can
benefit from it regardless of tooling.
Assisted-by: Claude Opus 4.6 (1M context)
Signed-off-by: Justin Wheeler <jwheel@fedoraproject.org>
This is not sustainable and not recommended. But in practice, this is
the same as we were doing before. I wonder if it's better to have a prod
and dev Dockerfile with different Django settings and Pipenv flags.
This commit refactors the Dockerfile to use fewer layers when building
the image. It also re-arranges the order of how things are run to
benefit some steps like installing Python dependencies.
Ultimately, this commit leverages Pipenv for managing and installing
dependencies within the project. This is one additional change to
improving awareness of dependencies and ensuring development,
production, and staging will always use the same set of dependencies.
This commit removes the multiple requirements.txt files used to install
and manage dependencies and opts in favor of the Pipfile managed by
Pipenv:
https://github.com/pypa/pipfilehttps://pipenv.org/
The purpose of this change is to maintain DRY principles. This makes our
dependencies easier to manage by managing them in one place and only
dividing them by standard dependencies or development dependencies.
Future changes after this commit will include documentation improvements
and updates to the Dockerfile to install dependencies in the Pipfile
format.
This is a first step in migrating all project dependencies to Pipenv.
This commit specifically adds the docs dependencies into a new Pipfile
specified at the root of the project.
Closes#21.
This commit integrates the final SVG created by @terezahl in design#606.
There were a few cosmetic differences from the previous rendered PNG.