FossilRepo
Add FEATURE_RELEASES, FEATURE_SYNC, FEATURE_FILES flags (all default off)
Commit
f4111a3d4c048ff0f2d445261a41d15688e2b8987a19878195debc9cacc0c23b
Parent
a53acf34c1c6f6f…
4 files changed
+4
-1
+3
+12
+6
+4
-1
| --- config/settings.py | ||
| +++ config/settings.py | ||
| @@ -256,19 +256,22 @@ | ||
| 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 | 259 | # Feature flags |
| 260 | 260 | "FEATURE_CHAT": (False, "Enable project chat rooms"), |
| 261 | + "FEATURE_RELEASES": (False, "Enable releases (tags + downloadable assets)"), | |
| 262 | + "FEATURE_SYNC": (False, "Enable Git sync / mirror configuration"), | |
| 263 | + "FEATURE_FILES": (False, "Enable unversioned file storage per project"), | |
| 261 | 264 | } |
| 262 | 265 | CONSTANCE_CONFIG_FIELDSETS = { |
| 263 | 266 | "General": ("SITE_NAME",), |
| 264 | 267 | "Fossil Storage": ("FOSSIL_DATA_DIR", "FOSSIL_STORE_IN_DB", "FOSSIL_S3_TRACKING", "FOSSIL_S3_BUCKET", "FOSSIL_BINARY_PATH"), |
| 265 | 268 | "Git Sync": ("GIT_SYNC_MODE", "GIT_SYNC_SCHEDULE", "GIT_MIRROR_DIR", "GIT_SSH_KEY_DIR"), |
| 266 | 269 | "GitHub OAuth": ("GITHUB_OAUTH_CLIENT_ID", "GITHUB_OAUTH_CLIENT_SECRET"), |
| 267 | 270 | "GitLab OAuth": ("GITLAB_OAUTH_CLIENT_ID", "GITLAB_OAUTH_CLIENT_SECRET"), |
| 268 | 271 | "Cloudflare Turnstile": ("TURNSTILE_ENABLED", "TURNSTILE_SITE_KEY", "TURNSTILE_SECRET_KEY"), |
| 269 | - "Features": ("FEATURE_CHAT",), | |
| 272 | + "Features": ("FEATURE_CHAT", "FEATURE_RELEASES", "FEATURE_SYNC", "FEATURE_FILES"), | |
| 270 | 273 | } |
| 271 | 274 | |
| 272 | 275 | # --- Sentry --- |
| 273 | 276 | |
| 274 | 277 | SENTRY_DSN = env_str("SENTRY_DSN") |
| 275 | 278 |
| --- config/settings.py | |
| +++ config/settings.py | |
| @@ -256,19 +256,22 @@ | |
| 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 |
| --- config/settings.py | |
| +++ config/settings.py | |
| @@ -256,19 +256,22 @@ | |
| 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 | "FEATURE_RELEASES": (False, "Enable releases (tags + downloadable assets)"), |
| 262 | "FEATURE_SYNC": (False, "Enable Git sync / mirror configuration"), |
| 263 | "FEATURE_FILES": (False, "Enable unversioned file storage per project"), |
| 264 | } |
| 265 | CONSTANCE_CONFIG_FIELDSETS = { |
| 266 | "General": ("SITE_NAME",), |
| 267 | "Fossil Storage": ("FOSSIL_DATA_DIR", "FOSSIL_STORE_IN_DB", "FOSSIL_S3_TRACKING", "FOSSIL_S3_BUCKET", "FOSSIL_BINARY_PATH"), |
| 268 | "Git Sync": ("GIT_SYNC_MODE", "GIT_SYNC_SCHEDULE", "GIT_MIRROR_DIR", "GIT_SSH_KEY_DIR"), |
| 269 | "GitHub OAuth": ("GITHUB_OAUTH_CLIENT_ID", "GITHUB_OAUTH_CLIENT_SECRET"), |
| 270 | "GitLab OAuth": ("GITLAB_OAUTH_CLIENT_ID", "GITLAB_OAUTH_CLIENT_SECRET"), |
| 271 | "Cloudflare Turnstile": ("TURNSTILE_ENABLED", "TURNSTILE_SITE_KEY", "TURNSTILE_SECRET_KEY"), |
| 272 | "Features": ("FEATURE_CHAT", "FEATURE_RELEASES", "FEATURE_SYNC", "FEATURE_FILES"), |
| 273 | } |
| 274 | |
| 275 | # --- Sentry --- |
| 276 | |
| 277 | SENTRY_DSN = env_str("SENTRY_DSN") |
| 278 |
| --- core/context_processors.py | ||
| +++ core/context_processors.py | ||
| @@ -41,6 +41,9 @@ | ||
| 41 | 41 | "sidebar_ungrouped": ungrouped_projects, |
| 42 | 42 | "sidebar_pages": pages, # Keep for backwards compat |
| 43 | 43 | "sidebar_product_docs": product_docs, |
| 44 | 44 | "sidebar_kb_pages": kb_pages, |
| 45 | 45 | "feature_chat": config.FEATURE_CHAT, |
| 46 | + "feature_releases": config.FEATURE_RELEASES, | |
| 47 | + "feature_sync": config.FEATURE_SYNC, | |
| 48 | + "feature_files": config.FEATURE_FILES, | |
| 46 | 49 | } |
| 47 | 50 |
| --- core/context_processors.py | |
| +++ core/context_processors.py | |
| @@ -41,6 +41,9 @@ | |
| 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 |
| --- core/context_processors.py | |
| +++ core/context_processors.py | |
| @@ -41,6 +41,9 @@ | |
| 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 | "feature_releases": config.FEATURE_RELEASES, |
| 47 | "feature_sync": config.FEATURE_SYNC, |
| 48 | "feature_files": config.FEATURE_FILES, |
| 49 | } |
| 50 |
+12
| --- fossil/views.py | ||
| +++ fossil/views.py | ||
| @@ -1499,10 +1499,14 @@ | ||
| 1499 | 1499 | |
| 1500 | 1500 | |
| 1501 | 1501 | @login_required |
| 1502 | 1502 | def sync_pull(request, slug): |
| 1503 | 1503 | """Sync configuration and pull from upstream remote.""" |
| 1504 | + from constance import config | |
| 1505 | + | |
| 1506 | + if not config.FEATURE_SYNC: | |
| 1507 | + raise Http404 | |
| 1504 | 1508 | project, fossil_repo, reader = _get_repo_and_reader(slug, request, "write") |
| 1505 | 1509 | |
| 1506 | 1510 | from fossil.cli import FossilCLI |
| 1507 | 1511 | |
| 1508 | 1512 | cli = FossilCLI() |
| @@ -2263,10 +2267,14 @@ | ||
| 2263 | 2267 | |
| 2264 | 2268 | # --- Unversioned Content --- |
| 2265 | 2269 | |
| 2266 | 2270 | |
| 2267 | 2271 | def unversioned_list(request, slug): |
| 2272 | + from constance import config | |
| 2273 | + | |
| 2274 | + if not config.FEATURE_FILES: | |
| 2275 | + raise Http404 | |
| 2268 | 2276 | from projects.access import can_admin_project |
| 2269 | 2277 | |
| 2270 | 2278 | project, fossil_repo, reader = _get_repo_and_reader(slug, request) |
| 2271 | 2279 | |
| 2272 | 2280 | with reader: |
| @@ -3059,10 +3067,14 @@ | ||
| 3059 | 3067 | fossil_repo = get_object_or_404(FossilRepository, project=project, deleted_at__isnull=True) |
| 3060 | 3068 | return project, fossil_repo |
| 3061 | 3069 | |
| 3062 | 3070 | |
| 3063 | 3071 | def release_list(request, slug): |
| 3072 | + from constance import config | |
| 3073 | + | |
| 3074 | + if not config.FEATURE_RELEASES: | |
| 3075 | + raise Http404 | |
| 3064 | 3076 | from projects.access import can_write_project |
| 3065 | 3077 | |
| 3066 | 3078 | project, fossil_repo = _get_project_and_repo(slug, request, "read") |
| 3067 | 3079 | |
| 3068 | 3080 | from fossil.releases import Release |
| 3069 | 3081 |
| --- fossil/views.py | |
| +++ fossil/views.py | |
| @@ -1499,10 +1499,14 @@ | |
| 1499 | |
| 1500 | |
| 1501 | @login_required |
| 1502 | def sync_pull(request, slug): |
| 1503 | """Sync configuration and pull from upstream remote.""" |
| 1504 | project, fossil_repo, reader = _get_repo_and_reader(slug, request, "write") |
| 1505 | |
| 1506 | from fossil.cli import FossilCLI |
| 1507 | |
| 1508 | cli = FossilCLI() |
| @@ -2263,10 +2267,14 @@ | |
| 2263 | |
| 2264 | # --- Unversioned Content --- |
| 2265 | |
| 2266 | |
| 2267 | def unversioned_list(request, slug): |
| 2268 | from projects.access import can_admin_project |
| 2269 | |
| 2270 | project, fossil_repo, reader = _get_repo_and_reader(slug, request) |
| 2271 | |
| 2272 | with reader: |
| @@ -3059,10 +3067,14 @@ | |
| 3059 | fossil_repo = get_object_or_404(FossilRepository, project=project, deleted_at__isnull=True) |
| 3060 | return project, fossil_repo |
| 3061 | |
| 3062 | |
| 3063 | def release_list(request, slug): |
| 3064 | from projects.access import can_write_project |
| 3065 | |
| 3066 | project, fossil_repo = _get_project_and_repo(slug, request, "read") |
| 3067 | |
| 3068 | from fossil.releases import Release |
| 3069 |
| --- fossil/views.py | |
| +++ fossil/views.py | |
| @@ -1499,10 +1499,14 @@ | |
| 1499 | |
| 1500 | |
| 1501 | @login_required |
| 1502 | def sync_pull(request, slug): |
| 1503 | """Sync configuration and pull from upstream remote.""" |
| 1504 | from constance import config |
| 1505 | |
| 1506 | if not config.FEATURE_SYNC: |
| 1507 | raise Http404 |
| 1508 | project, fossil_repo, reader = _get_repo_and_reader(slug, request, "write") |
| 1509 | |
| 1510 | from fossil.cli import FossilCLI |
| 1511 | |
| 1512 | cli = FossilCLI() |
| @@ -2263,10 +2267,14 @@ | |
| 2267 | |
| 2268 | # --- Unversioned Content --- |
| 2269 | |
| 2270 | |
| 2271 | def unversioned_list(request, slug): |
| 2272 | from constance import config |
| 2273 | |
| 2274 | if not config.FEATURE_FILES: |
| 2275 | raise Http404 |
| 2276 | from projects.access import can_admin_project |
| 2277 | |
| 2278 | project, fossil_repo, reader = _get_repo_and_reader(slug, request) |
| 2279 | |
| 2280 | with reader: |
| @@ -3059,10 +3067,14 @@ | |
| 3067 | fossil_repo = get_object_or_404(FossilRepository, project=project, deleted_at__isnull=True) |
| 3068 | return project, fossil_repo |
| 3069 | |
| 3070 | |
| 3071 | def release_list(request, slug): |
| 3072 | from constance import config |
| 3073 | |
| 3074 | if not config.FEATURE_RELEASES: |
| 3075 | raise Http404 |
| 3076 | from projects.access import can_write_project |
| 3077 | |
| 3078 | project, fossil_repo = _get_project_and_repo(slug, request, "read") |
| 3079 | |
| 3080 | from fossil.releases import Release |
| 3081 |
| --- templates/fossil/_project_nav.html | ||
| +++ templates/fossil/_project_nav.html | ||
| @@ -31,23 +31,29 @@ | ||
| 31 | 31 | <a href="{% url 'fossil:chat' slug=project.slug %}" |
| 32 | 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 | 33 | Chat |
| 34 | 34 | </a> |
| 35 | 35 | {% endif %} |
| 36 | + {% if feature_releases %} | |
| 36 | 37 | <a href="{% url 'fossil:releases' slug=project.slug %}" |
| 37 | 38 | 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 | 39 | Releases |
| 39 | 40 | </a> |
| 41 | + {% endif %} | |
| 42 | + {% if feature_files %} | |
| 40 | 43 | <a href="{% url 'fossil:unversioned' slug=project.slug %}" |
| 41 | 44 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'files' %}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 %}"> |
| 42 | 45 | Files |
| 43 | 46 | </a> |
| 47 | + {% endif %} | |
| 44 | 48 | {% if perms.projects.change_project %} |
| 49 | + {% if feature_sync %} | |
| 45 | 50 | <a href="{% url 'fossil:sync' slug=project.slug %}" |
| 46 | 51 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'sync' %}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 %}"> |
| 47 | 52 | {% if fossil_repo.remote_url %}Sync{% else %}Setup Sync{% endif %} |
| 48 | 53 | </a> |
| 54 | + {% endif %} | |
| 49 | 55 | <a href="{% url 'fossil:repo_settings' slug=project.slug %}" |
| 50 | 56 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'settings' %}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 %}"> |
| 51 | 57 | Settings |
| 52 | 58 | </a> |
| 53 | 59 | <a href="{% url 'fossil:explorer' slug=project.slug %}" |
| 54 | 60 |
| --- templates/fossil/_project_nav.html | |
| +++ templates/fossil/_project_nav.html | |
| @@ -31,23 +31,29 @@ | |
| 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 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'files' %}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 %}"> |
| 42 | Files |
| 43 | </a> |
| 44 | {% if perms.projects.change_project %} |
| 45 | <a href="{% url 'fossil:sync' slug=project.slug %}" |
| 46 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'sync' %}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 %}"> |
| 47 | {% if fossil_repo.remote_url %}Sync{% else %}Setup Sync{% endif %} |
| 48 | </a> |
| 49 | <a href="{% url 'fossil:repo_settings' slug=project.slug %}" |
| 50 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'settings' %}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 %}"> |
| 51 | Settings |
| 52 | </a> |
| 53 | <a href="{% url 'fossil:explorer' slug=project.slug %}" |
| 54 |
| --- templates/fossil/_project_nav.html | |
| +++ templates/fossil/_project_nav.html | |
| @@ -31,23 +31,29 @@ | |
| 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 | {% if feature_releases %} |
| 37 | <a href="{% url 'fossil:releases' slug=project.slug %}" |
| 38 | 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 %}"> |
| 39 | Releases |
| 40 | </a> |
| 41 | {% endif %} |
| 42 | {% if feature_files %} |
| 43 | <a href="{% url 'fossil:unversioned' slug=project.slug %}" |
| 44 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'files' %}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 %}"> |
| 45 | Files |
| 46 | </a> |
| 47 | {% endif %} |
| 48 | {% if perms.projects.change_project %} |
| 49 | {% if feature_sync %} |
| 50 | <a href="{% url 'fossil:sync' slug=project.slug %}" |
| 51 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'sync' %}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 %}"> |
| 52 | {% if fossil_repo.remote_url %}Sync{% else %}Setup Sync{% endif %} |
| 53 | </a> |
| 54 | {% endif %} |
| 55 | <a href="{% url 'fossil:repo_settings' slug=project.slug %}" |
| 56 | class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'settings' %}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 %}"> |
| 57 | Settings |
| 58 | </a> |
| 59 | <a href="{% url 'fossil:explorer' slug=project.slug %}" |
| 60 |