- Rate limits in the shared cache for comments, issues, uploads and invites; a limited HTMX reply keeps the draft. - Content-Security-Policy (self only, no inline script or style, bucket origin for images and frames) and Permissions-Policy on every page. htmx configured not to inject styles or eval. - Moderation: deactivating a user ends their sessions and keeps their content; deleted accounts show as "ghost"; reserved usernames; the admin won't delete an org's last owner. - Admin requires a TOTP code (django-otp), with add_admin_totp to enrol. - Email provider chosen by environment through django-anymail. - Playwright browser tests: axe WCAG 2.1 AA on every page in light and dark, no CSP violations, keyboard walkthrough, theme toggle. Explicit Canvas/CanvasText on :root fixes dark-mode contrast detection. - bin/start creates the data dir if missing; docs/operations.md runbook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
53 lines
2 KiB
Python
53 lines
2 KiB
Python
import allauth.urls
|
|
from allauth.account import urls as allauth_account_urls
|
|
from django.conf import settings
|
|
from django.contrib import admin
|
|
from django.urls import URLResolver, include, path
|
|
|
|
from intent.core import views
|
|
from intent.orgs.urls import invite_urlpatterns
|
|
from intent.projects.views import project_create
|
|
|
|
|
|
def _without_passwords(patterns):
|
|
"""allauth's URLs minus the password views: regular users sign in with a code only."""
|
|
return [p for p in patterns if not str(p.pattern).startswith("password/")]
|
|
|
|
|
|
account_urlpatterns = [
|
|
(
|
|
path("", include(_without_passwords(allauth_account_urls.urlpatterns)))
|
|
if isinstance(p, URLResolver) and p.urlconf_name is allauth_account_urls
|
|
else p
|
|
)
|
|
for p in allauth.urls.urlpatterns
|
|
]
|
|
|
|
if settings.ADMIN_REQUIRE_OTP:
|
|
from django_otp.admin import OTPAdminSite
|
|
|
|
# Same site instance and URL names; it now also requires a verified OTP device.
|
|
admin.site.__class__ = OTPAdminSite
|
|
admin.site.login_template = OTPAdminSite.login_template
|
|
|
|
urlpatterns = [
|
|
path("", views.home, name="home"),
|
|
path("admin/", admin.site.urls),
|
|
path("accounts/", include(account_urlpatterns)),
|
|
path("invites/", include(invite_urlpatterns)),
|
|
# Organizations own the rest of the URL space (see RESERVED_SLUGS in orgs and projects).
|
|
path("<slug:org_slug>/new/", project_create, name="project_create"),
|
|
path("<slug:org_slug>/", include("intent.orgs.urls")),
|
|
path("<slug:org_slug>/<slug:project_slug>/", include("intent.projects.urls")),
|
|
path(
|
|
"<slug:org_slug>/<slug:project_slug>/features/<str:feature_key>/files/",
|
|
include("intent.files.urls"),
|
|
),
|
|
path("<slug:org_slug>/<slug:project_slug>/features/", include("intent.features.urls")),
|
|
path("<slug:org_slug>/<slug:project_slug>/issues/", include("intent.issues.urls")),
|
|
path(
|
|
"<slug:org_slug>/<slug:project_slug>/implementations/",
|
|
include("intent.implementations.urls"),
|
|
),
|
|
path("<slug:org_slug>/<slug:project_slug>/", include("intent.comments.urls")),
|
|
]
|