Commit graph

207 commits

Author SHA1 Message Date
51d6014997
💚 ci: Switch test suite to SQLite, remove service container deps
All checks were successful
CI / lint (pull_request) Successful in 22s
CI / test (pull_request) Successful in 50s
CI / lint (push) Successful in 16s
CI / test (push) Successful in 40s
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>
2026-06-20 18:34:22 -04:00
6e69255965
📝 docs: Update AGENTS.md and README.md for current project state
Some checks failed
CI / lint (push) Successful in 17s
CI / test (push) Failing after 48s
`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>
2026-05-11 06:21:43 -04:00
ba84784baa
🧹 frontend: Final cleanup — reorganize assets, update stale references
Some checks failed
CI / lint (pull_request) Successful in 14s
CI / test (pull_request) Failing after 48s
CI / lint (push) Successful in 21s
CI / test (push) Failing after 49s
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>
2026-05-10 13:45:01 -04:00
6a98ddb9de
🔥 frontend: Remove jQuery, rewrite FAS lookup in vanilla JS
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>
2026-05-10 13:03:35 -04:00
3a0e6a840a
⬆️ frontend: Migrate CKEditor 4 → CKEditor 5
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>
2026-05-10 12:47:01 -04:00
29207a4ba1
⬆️ frontend: Upgrade Bootstrap 4.3.1 → 5.3.6
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>
2026-05-10 18:27:10 +02:00
c5715ae692
🔒 frontend: Self-host fonts, remove all external CDN dependencies
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>
2026-05-10 18:01:21 +02:00
6313178b56
🔥 frontend: Remove dead Bootstrap 3 assets, register crispy_bootstrap5
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>
2026-05-10 17:39:32 +02:00
28706cd176
💚 ci: Fix lint and test job failures
Some checks failed
CI / lint (pull_request) Successful in 14s
CI / test (pull_request) Failing after 1m20s
CI / lint (push) Successful in 14s
CI / test (push) Failing after 1m21s
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>
2026-05-10 16:58:30 +02:00
c17fb59eb8
💚 ci: Install Node.js for checkout action, remove stale config step
Some checks failed
CI / lint (push) Failing after 15s
CI / test (push) Failing after 41s
CI / lint (pull_request) Failing after 14s
CI / test (pull_request) Failing after 43s
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>
2026-05-10 16:39:07 +02:00
7c062eb0ce
🔧 containers: Add persistent volume for RabbitMQ data
Some checks failed
CI / lint (push) Failing after 13s
CI / test (push) Failing after 11s
CI / lint (pull_request) Failing after 4s
CI / test (pull_request) Failing after 6s
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>
2026-05-10 16:05:15 +02:00
39b241cb55
🐛 compat(models): Fix Python 3.14 and library compatibility issues
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>
2026-05-10 16:03:12 +02:00
8eb262bfb4
🐛 Containerfile: Write requirements to /tmp in builder stage
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>
2026-05-10 16:00:40 +02:00
9180c400e2
⬆️ deps: Upgrade fedora-messaging 3.4.1 → 3.9.0
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>
2026-05-10 15:58:03 +02:00
be5135a6b6
🔧 settings: Refactor to 12-factor env vars, eliminate config files
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>
2026-03-31 11:30:42 -04:00
32a8f0b190
💚 ci: Change runner label from docker to podman
Some checks failed
CI / lint (push) Failing after 12s
CI / test (push) Failing after 13s
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>
2026-03-31 11:28:07 -04:00
2f80857147
🐛 deps: Relax Python version constraint from >=3.14 to >=3.12
Some checks failed
CI / lint (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
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>
2026-03-29 13:34:20 -04:00
565f7757bf
🔧 containers: Replace Docker with Podman and UBI-based Containerfile
Some checks failed
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / lint (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
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>
2026-03-29 02:26:18 -04:00
500b0d7d94
📝 docs(AGENTS.md): Update modernized project state
Some checks failed
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / lint (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
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>
2026-03-29 02:09:41 -04:00
33910b0145
🔧 ci: Add Forgejo Actions pipeline for linting and testing
Some checks failed
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / lint (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
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>
2026-03-29 01:57:56 -04:00
c977855527
📦 deps: Migrate from Pipfile/Pipenv to Poetry with pyproject.toml v1.0.0
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>
2026-03-29 01:43:07 -04:00
1fc7afc2e4
🔥 deps: Replace deprecated packages with stdlib and modern alternatives
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>
2026-03-29 01:12:20 -04:00
184175e174
⬆️ django: Upgrade Django 4.2.18 → 5.1 and target Python 3.14
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>
2026-03-29 00:53:00 -04:00
150a80062c
⬆️ django: Upgrade Django 3.2.25 → 4.2.18 LTS
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>
2026-03-29 00:43:48 -04:00
96c3c7cbea
⬆️ django: Upgrade Django 2.2.28 → 3.2.25 LTS
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>
2026-03-29 00:25:29 -04:00
6c00d9716d
⬆️ django: Upgrade Django 2.0.13 → 2.2.28 LTS
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>
2026-03-29 00:16:43 -04:00
32f273f72a
🔧 config: Remove Mercurial syntax from .gitignore and six from Pipfile
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>
2026-03-28 23:56:21 -04:00
23e44eab74
🔥 messaging/utils: Remove dead code and Python 2 compatibility
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>
2026-03-28 23:54:10 -04:00
34d82e4243
🔥 frontend: Remove dead social media and unused assets (closes #34)
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>
2026-03-28 23:51:08 -04:00
Alisha Mohanty
3a36c9ee21
🎨 assets/templates: Make frontend consistent with Fedora apps
1. Add Fedora Bootstrap
 2. Shift sidebar to top navigation bar
 3. Change the color theme
2026-03-28 14:12:24 -04:00
09547fa35d
🙈 gitignore: Anchor config.yml pattern to repository root
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>
2026-03-28 14:06:58 -04:00
bb38062638
🔧 forgejo: Add issue templates with interactive YAML forms
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>
2026-03-28 14:02:04 -04:00
Michael Scherer
da555b9132
Remove fedmenu
Fedmenu is deprecated, no need to keep it
2026-03-28 13:47:33 -04:00
91ecd5b433
📝 docs(AGENTS.md): Initial commit with guidance for AI assistants
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>
2026-03-28 13:45:39 -04:00
Michael S
39e04fe4b7 Remove mention of Freenode 2021-08-24 13:24:38 +00:00
8c91df5567
Add pytest-mock to devel dependencies
Signed-off-by: Justin W. Flory <git@jwf.io>
2020-02-12 14:45:15 -05:00
1e392ec1e8
Dockerfile: Install development dependencies
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.
2020-02-12 14:45:15 -05:00
cf4df9e94f
Refactor Dockerfile, use pipenv for Python packages
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.
2020-02-12 14:45:15 -05:00
f1fdd40cab
Migrate all project dependencies to Pipfile
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/pipfile
    https://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.
2020-02-12 14:45:15 -05:00
d146cd9abd
dependencies: Migrate docs deps to root directory
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.
2020-02-12 14:44:47 -05:00
b804bb3f84
Update logo to use final SVG approved by Fedora Design Team
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.
2020-02-12 14:38:17 -05:00
Justin W. Flory
3ada7e4349 Merge #259 Add configuration files for local deployment on minishift 2020-02-12 19:31:22 +00:00
evanhearne
4632cf5ce6 redesigned search page 2020-02-12 19:28:23 +00:00
Aniketh Reddimi
ba447efdc9 Update templates/base.html 2019-12-16 09:41:16 +00:00
Aniketh Reddimi
f9a0b6219b Update templates/follow.html 2019-12-16 09:38:30 +00:00
09e6527974 Add configuration files for local deployment on minishift 2019-08-18 00:42:17 +05:30
Alisha Mohanty
d95a06c432 Test FASid search functionality using Mocking
1. Add pytest-mock dependency 2. Write tests for fasidCheck for all possible cases
2019-08-03 12:34:04 +00:00
Alisha Mohanty
81cf85c118 Write clean and maintanable code for fasidCheck 2019-08-03 12:34:03 +00:00
20d44f4c71 Add custom logout function 2019-07-24 10:12:31 +05:30
Alisha Mohanty
ec612038ca Migrate testcases to Pytest, Pass failing Tests, Add unittest for check_recipient_is_sender, Modify clean method(forms.py), Add test for pagination 2019-07-23 22:59:38 +05:30