FossilRepo
Gate chat behind FEATURE_CHAT constance flag (default off)
Commit
a53acf34c1c6f6f05c635bcc2d5af21b6cea597ede0701f8bf857360b68189a5
Parent
1bffb234fe2f0f0…
4 files changed
+3
+3
+8
+6
+3
| --- config/settings.py | ||
| +++ config/settings.py | ||
| @@ -254,18 +254,21 @@ | ||
| 254 | 254 | "GITLAB_OAUTH_CLIENT_SECRET": ("", "GitLab OAuth App Client Secret"), |
| 255 | 255 | # Cloudflare Turnstile (optional bot protection on login) |
| 256 | 256 | "TURNSTILE_ENABLED": (False, "Enable Cloudflare Turnstile on the login page"), |
| 257 | 257 | "TURNSTILE_SITE_KEY": ("", "Cloudflare Turnstile site key (public)"), |
| 258 | 258 | "TURNSTILE_SECRET_KEY": ("", "Cloudflare Turnstile secret key (server-side verification)"), |
| 259 | + # Feature flags | |
| 260 | + "FEATURE_CHAT": (False, "Enable project chat rooms"), | |
| 259 | 261 | } |
| 260 | 262 | CONSTANCE_CONFIG_FIELDSETS = { |
| 261 | 263 | "General": ("SITE_NAME",), |
| 262 | 264 | "Fossil Storage": ("FOSSIL_DATA_DIR", "FOSSIL_STORE_IN_DB", "FOSSIL_S3_TRACKING", "FOSSIL_S3_BUCKET", "FOSSIL_BINARY_PATH"), |
| 263 | 265 | "Git Sync": ("GIT_SYNC_MODE", "GIT_SYNC_SCHEDULE", "GIT_MIRROR_DIR", "GIT_SSH_KEY_DIR"), |
| 264 | 266 | "GitHub OAuth": ("GITHUB_OAUTH_CLIENT_ID", "GITHUB_OAUTH_CLIENT_SECRET"), |
| 265 | 267 | "GitLab OAuth": ("GITLAB_OAUTH_CLIENT_ID", "GITLAB_OAUTH_CLIENT_SECRET"), |
| 266 | 268 | "Cloudflare Turnstile": ("TURNSTILE_ENABLED", "TURNSTILE_SITE_KEY", "TURNSTILE_SECRET_KEY"), |
| 269 | + "Features": ("FEATURE_CHAT",), | |
| 267 | 270 | } |
| 268 | 271 | |
| 269 | 272 | # --- Sentry --- |
| 270 | 273 | |
| 271 | 274 | SENTRY_DSN = env_str("SENTRY_DSN") |
| 272 | 275 |
| --- config/settings.py | |
| +++ config/settings.py | |
| @@ -254,18 +254,21 @@ | |
| 254 | "GITLAB_OAUTH_CLIENT_SECRET": ("", "GitLab OAuth App Client Secret"), |
| 255 | # Cloudflare Turnstile (optional bot protection on login) |
| 256 | "TURNSTILE_ENABLED": (False, "Enable Cloudflare Turnstile on the login page"), |
| 257 | "TURNSTILE_SITE_KEY": ("", "Cloudflare Turnstile site key (public)"), |
| 258 | "TURNSTILE_SECRET_KEY": ("", "Cloudflare Turnstile secret key (server-side verification)"), |
| 259 | } |
| 260 | CONSTANCE_CONFIG_FIELDSETS = { |
| 261 | "General": ("SITE_NAME",), |
| 262 | "Fossil Storage": ("FOSSIL_DATA_DIR", "FOSSIL_STORE_IN_DB", "FOSSIL_S3_TRACKING", "FOSSIL_S3_BUCKET", "FOSSIL_BINARY_PATH"), |
| 263 | "Git Sync": ("GIT_SYNC_MODE", "GIT_SYNC_SCHEDULE", "GIT_MIRROR_DIR", "GIT_SSH_KEY_DIR"), |
| 264 | "GitHub OAuth": ("GITHUB_OAUTH_CLIENT_ID", "GITHUB_OAUTH_CLIENT_SECRET"), |
| 265 | "GitLab OAuth": ("GITLAB_OAUTH_CLIENT_ID", "GITLAB_OAUTH_CLIENT_SECRET"), |
| 266 | "Cloudflare Turnstile": ("TURNSTILE_ENABLED", "TURNSTILE_SITE_KEY", "TURNSTILE_SECRET_KEY"), |
| 267 | } |
| 268 | |
| 269 | # --- Sentry --- |
| 270 | |
| 271 | SENTRY_DSN = env_str("SENTRY_DSN") |
| 272 |
| --- config/settings.py | |
| +++ config/settings.py | |
| @@ -254,18 +254,21 @@ | |
| 254 | "GITLAB_OAUTH_CLIENT_SECRET": ("", "GitLab OAuth App Client Secret"), |
| 255 | # Cloudflare Turnstile (optional bot protection on login) |
| 256 | "TURNSTILE_ENABLED": (False, "Enable Cloudflare Turnstile on the login page"), |
| 257 | "TURNSTILE_SITE_KEY": ("", "Cloudflare Turnstile site key (public)"), |
| 258 | "TURNSTILE_SECRET_KEY": ("", "Cloudflare Turnstile secret key (server-side verification)"), |
| 259 | # Feature flags |
| 260 | "FEATURE_CHAT": (False, "Enable project chat rooms"), |
| 261 | } |
| 262 | CONSTANCE_CONFIG_FIELDSETS = { |
| 263 | "General": ("SITE_NAME",), |
| 264 | "Fossil Storage": ("FOSSIL_DATA_DIR", "FOSSIL_STORE_IN_DB", "FOSSIL_S3_TRACKING", "FOSSIL_S3_BUCKET", "FOSSIL_BINARY_PATH"), |
| 265 | "Git Sync": ("GIT_SYNC_MODE", "GIT_SYNC_SCHEDULE", "GIT_MIRROR_DIR", "GIT_SSH_KEY_DIR"), |
| 266 | "GitHub OAuth": ("GITHUB_OAUTH_CLIENT_ID", "GITHUB_OAUTH_CLIENT_SECRET"), |
| 267 | "GitLab OAuth": ("GITLAB_OAUTH_CLIENT_ID", "GITLAB_OAUTH_CLIENT_SECRET"), |
| 268 | "Cloudflare Turnstile": ("TURNSTILE_ENABLED", "TURNSTILE_SITE_KEY", "TURNSTILE_SECRET_KEY"), |
| 269 | "Features": ("FEATURE_CHAT",), |
| 270 | } |
| 271 | |
| 272 | # --- Sentry --- |
| 273 | |
| 274 | SENTRY_DSN = env_str("SENTRY_DSN") |
| 275 |
| --- core/context_processors.py | ||
| +++ core/context_processors.py | ||
| @@ -1,5 +1,7 @@ | ||
| 1 | +from constance import config | |
| 2 | + | |
| 1 | 3 | from pages.models import Page |
| 2 | 4 | from projects.models import Project, ProjectGroup |
| 3 | 5 | |
| 4 | 6 | |
| 5 | 7 | def sidebar(request): |
| @@ -38,6 +40,7 @@ | ||
| 38 | 40 | "sidebar_grouped": grouped_projects, |
| 39 | 41 | "sidebar_ungrouped": ungrouped_projects, |
| 40 | 42 | "sidebar_pages": pages, # Keep for backwards compat |
| 41 | 43 | "sidebar_product_docs": product_docs, |
| 42 | 44 | "sidebar_kb_pages": kb_pages, |
| 45 | + "feature_chat": config.FEATURE_CHAT, | |
| 43 | 46 | } |
| 44 | 47 |
| --- core/context_processors.py | |
| +++ core/context_processors.py | |
| @@ -1,5 +1,7 @@ | |
| 1 | from pages.models import Page |
| 2 | from projects.models import Project, ProjectGroup |
| 3 | |
| 4 | |
| 5 | def sidebar(request): |
| @@ -38,6 +40,7 @@ | |
| 38 | "sidebar_grouped": grouped_projects, |
| 39 | "sidebar_ungrouped": ungrouped_projects, |
| 40 | "sidebar_pages": pages, # Keep for backwards compat |
| 41 | "sidebar_product_docs": product_docs, |
| 42 | "sidebar_kb_pages": kb_pages, |
| 43 | } |
| 44 |
| --- core/context_processors.py | |
| +++ core/context_processors.py | |
| @@ -1,5 +1,7 @@ | |
| 1 | from constance import config |
| 2 | |
| 3 | from pages.models import Page |
| 4 | from projects.models import Project, ProjectGroup |
| 5 | |
| 6 | |
| 7 | def sidebar(request): |
| @@ -38,6 +40,7 @@ | |
| 40 | "sidebar_grouped": grouped_projects, |
| 41 | "sidebar_ungrouped": ungrouped_projects, |
| 42 | "sidebar_pages": pages, # Keep for backwards compat |
| 43 | "sidebar_product_docs": product_docs, |
| 44 | "sidebar_kb_pages": kb_pages, |
| 45 | "feature_chat": config.FEATURE_CHAT, |
| 46 | } |
| 47 |
+8
| --- fossil/views.py | ||
| +++ fossil/views.py | ||
| @@ -4482,10 +4482,14 @@ | ||
| 4482 | 4482 | # --- Chat --- |
| 4483 | 4483 | |
| 4484 | 4484 | |
| 4485 | 4485 | @login_required |
| 4486 | 4486 | def chat_room(request, slug): |
| 4487 | + from constance import config | |
| 4488 | + | |
| 4489 | + if not config.FEATURE_CHAT: | |
| 4490 | + raise Http404 | |
| 4487 | 4491 | project, fossil_repo, reader = _get_repo_and_reader(slug, request) |
| 4488 | 4492 | from fossil.chat import ChatMessage |
| 4489 | 4493 | |
| 4490 | 4494 | messages = ChatMessage.objects.filter(repository=fossil_repo).select_related("user").order_by("-created_at")[:50] |
| 4491 | 4495 | messages = list(reversed(messages)) |
| @@ -4501,10 +4505,14 @@ | ||
| 4501 | 4505 | ) |
| 4502 | 4506 | |
| 4503 | 4507 | |
| 4504 | 4508 | @login_required |
| 4505 | 4509 | def chat_send(request, slug): |
| 4510 | + from constance import config | |
| 4511 | + | |
| 4512 | + if not config.FEATURE_CHAT: | |
| 4513 | + raise Http404 | |
| 4506 | 4514 | from fossil.chat import ChatMessage |
| 4507 | 4515 | |
| 4508 | 4516 | if request.method == "POST": |
| 4509 | 4517 | project, fossil_repo, reader = _get_repo_and_reader(slug, request, "write") |
| 4510 | 4518 | body = request.POST.get("body", "").strip() |
| 4511 | 4519 |
| --- fossil/views.py | |
| +++ fossil/views.py | |
| @@ -4482,10 +4482,14 @@ | |
| 4482 | # --- Chat --- |
| 4483 | |
| 4484 | |
| 4485 | @login_required |
| 4486 | def chat_room(request, slug): |
| 4487 | project, fossil_repo, reader = _get_repo_and_reader(slug, request) |
| 4488 | from fossil.chat import ChatMessage |
| 4489 | |
| 4490 | messages = ChatMessage.objects.filter(repository=fossil_repo).select_related("user").order_by("-created_at")[:50] |
| 4491 | messages = list(reversed(messages)) |
| @@ -4501,10 +4505,14 @@ | |
| 4501 | ) |
| 4502 | |
| 4503 | |
| 4504 | @login_required |
| 4505 | def chat_send(request, slug): |
| 4506 | from fossil.chat import ChatMessage |
| 4507 | |
| 4508 | if request.method == "POST": |
| 4509 | project, fossil_repo, reader = _get_repo_and_reader(slug, request, "write") |
| 4510 | body = request.POST.get("body", "").strip() |
| 4511 |
| --- fossil/views.py | |
| +++ fossil/views.py | |
| @@ -4482,10 +4482,14 @@ | |
| 4482 | # --- Chat --- |
| 4483 | |
| 4484 | |
| 4485 | @login_required |
| 4486 | def chat_room(request, slug): |
| 4487 | from constance import config |
| 4488 | |
| 4489 | if not config.FEATURE_CHAT: |
| 4490 | raise Http404 |
| 4491 | project, fossil_repo, reader = _get_repo_and_reader(slug, request) |
| 4492 | from fossil.chat import ChatMessage |
| 4493 | |
| 4494 | messages = ChatMessage.objects.filter(repository=fossil_repo).select_related("user").order_by("-created_at")[:50] |
| 4495 | messages = list(reversed(messages)) |
| @@ -4501,10 +4505,14 @@ | |
| 4505 | ) |
| 4506 | |
| 4507 | |
| 4508 | @login_required |
| 4509 | def chat_send(request, slug): |
| 4510 | from constance import config |
| 4511 | |
| 4512 | if not config.FEATURE_CHAT: |
| 4513 | raise Http404 |
| 4514 | from fossil.chat import ChatMessage |
| 4515 | |
| 4516 | if request.method == "POST": |
| 4517 | project, fossil_repo, reader = _get_repo_and_reader(slug, request, "write") |
| 4518 | body = request.POST.get("body", "").strip() |
| 4519 |
| --- templates/fossil/_project_nav.html | ||
| +++ templates/fossil/_project_nav.html | ||
| @@ -25,10 +25,16 @@ | ||
| 25 | 25 | </a> |
| 26 | 26 | <a href="{% url 'fossil:forum' slug=project.slug %}" |
| 27 | 27 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'forum' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> |
| 28 | 28 | Forum |
| 29 | 29 | </a> |
| 30 | + {% if feature_chat %} | |
| 31 | + <a href="{% url 'fossil:chat' slug=project.slug %}" | |
| 32 | + class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'chat' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> | |
| 33 | + Chat | |
| 34 | + </a> | |
| 35 | + {% endif %} | |
| 30 | 36 | <a href="{% url 'fossil:releases' slug=project.slug %}" |
| 31 | 37 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'releases' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> |
| 32 | 38 | Releases |
| 33 | 39 | </a> |
| 34 | 40 | <a href="{% url 'fossil:unversioned' slug=project.slug %}" |
| 35 | 41 |
| --- templates/fossil/_project_nav.html | |
| +++ templates/fossil/_project_nav.html | |
| @@ -25,10 +25,16 @@ | |
| 25 | </a> |
| 26 | <a href="{% url 'fossil:forum' slug=project.slug %}" |
| 27 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'forum' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> |
| 28 | Forum |
| 29 | </a> |
| 30 | <a href="{% url 'fossil:releases' slug=project.slug %}" |
| 31 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'releases' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> |
| 32 | Releases |
| 33 | </a> |
| 34 | <a href="{% url 'fossil:unversioned' slug=project.slug %}" |
| 35 |
| --- templates/fossil/_project_nav.html | |
| +++ templates/fossil/_project_nav.html | |
| @@ -25,10 +25,16 @@ | |
| 25 | </a> |
| 26 | <a href="{% url 'fossil:forum' slug=project.slug %}" |
| 27 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'forum' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> |
| 28 | Forum |
| 29 | </a> |
| 30 | {% if feature_chat %} |
| 31 | <a href="{% url 'fossil:chat' slug=project.slug %}" |
| 32 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'chat' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> |
| 33 | Chat |
| 34 | </a> |
| 35 | {% endif %} |
| 36 | <a href="{% url 'fossil:releases' slug=project.slug %}" |
| 37 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'releases' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 transition-colors{% endif %}"> |
| 38 | Releases |
| 39 | </a> |
| 40 | <a href="{% url 'fossil:unversioned' slug=project.slug %}" |
| 41 |