hacking
|
|
@ -31,6 +31,7 @@
|
|||
postInstall = oldAttrs.postInstall + ''
|
||||
rm -r $out/${pkgs.python3.sitePackages}/froide_govplan/templates
|
||||
ln -sf /var/lib/froide-govplan/templates $out/${pkgs.python3.sitePackages}/froide_govplan/templates
|
||||
cp -r froide_govplan/static $out/${pkgs.python3.sitePackages}/froide_govplan/
|
||||
'';
|
||||
});
|
||||
})
|
||||
|
|
@ -45,8 +46,13 @@
|
|||
cores = 4;
|
||||
};
|
||||
|
||||
disabledModules = [ "services/web-apps/froide-govplan.nix" ];
|
||||
|
||||
imports = [ ./froide-govplan.nix ];
|
||||
|
||||
services.froide-govplan = {
|
||||
enable = true;
|
||||
package = pkgs.froide-govplan;
|
||||
settings = {
|
||||
DEBUG = lib.mkForce true;
|
||||
CSRF_TRUSTED_ORIGINS = [ "http://localhost:8080" ];
|
||||
|
|
|
|||
242
froide-govplan.nix
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
|
||||
cfg = config.services.froide-govplan;
|
||||
pythonFmt = pkgs.formats.pythonVars { };
|
||||
settingsFile = pythonFmt.generate "extra_settings.py" cfg.settings;
|
||||
|
||||
pkg = cfg.package.overridePythonAttrs (old: {
|
||||
src = ./.;
|
||||
postInstall =
|
||||
old.postInstall
|
||||
+ ''
|
||||
ln -s ${settingsFile} $out/${pkg.python.sitePackages}/froide_govplan/project/extra_settings.py
|
||||
|
||||
rm -r $out/${pkgs.python3.sitePackages}/froide_govplan/templates
|
||||
ln -sf /var/lib/froide-govplan/templates $out/${pkgs.python3.sitePackages}/froide_govplan/templates
|
||||
cp -r froide_govplan/static $out/${pkgs.python3.sitePackages}/froide_govplan/
|
||||
'';
|
||||
});
|
||||
|
||||
froide-govplan = pkgs.writeShellApplication {
|
||||
name = "froide-govplan";
|
||||
runtimeInputs = [ pkgs.coreutils ];
|
||||
text = ''
|
||||
SUDO="exec"
|
||||
if [[ "$USER" != govplan ]]; then
|
||||
SUDO="exec /run/wrappers/bin/sudo -u govplan"
|
||||
fi
|
||||
$SUDO env ${lib.getExe pkg} "$@"
|
||||
'';
|
||||
};
|
||||
|
||||
# Service hardening
|
||||
defaultServiceConfig = {
|
||||
# Secure the services
|
||||
ReadWritePaths = [ cfg.dataDir ];
|
||||
CacheDirectory = "froide-govplan";
|
||||
CapabilityBoundingSet = "";
|
||||
# ProtectClock adds DeviceAllow=char-rtc r
|
||||
DeviceAllow = "";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateMounts = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProtectClock = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectControlGroups = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged @setuid @keyring"
|
||||
];
|
||||
UMask = "0066";
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
options.services.froide-govplan = {
|
||||
|
||||
enable = lib.mkEnableOption "Gouvernment planer web app Govplan";
|
||||
|
||||
package = lib.mkPackageOption pkgs "froide-govplan" { };
|
||||
|
||||
hostName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "localhost";
|
||||
description = "FQDN for the froide-govplan instance.";
|
||||
};
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/var/lib/froide-govplan";
|
||||
description = "Directory to store the Froide-Govplan server data.";
|
||||
};
|
||||
|
||||
secretKeyFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to a file containing the secret key.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
description = ''
|
||||
Configuration options to set in `extra_settings.py`.
|
||||
'';
|
||||
|
||||
default = { };
|
||||
|
||||
type = lib.types.submodule {
|
||||
freeformType = pythonFmt.type;
|
||||
|
||||
options = {
|
||||
ALLOWED_HOSTS = lib.mkOption {
|
||||
type = with lib.types; listOf str;
|
||||
default = [ "*" ];
|
||||
description = ''
|
||||
A list of valid fully-qualified domain names (FQDNs) and/or IP
|
||||
addresses that can be used to reach the Froide-Govplan service.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
services.froide-govplan = {
|
||||
settings = {
|
||||
STATIC_ROOT = "${cfg.dataDir}/static";
|
||||
DEBUG = false;
|
||||
DATABASES.default = {
|
||||
ENGINE = "django.contrib.gis.db.backends.postgis";
|
||||
NAME = "govplan";
|
||||
USER = "govplan";
|
||||
HOST = "/run/postgresql";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "govplan" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "govplan";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
extensions = ps: with ps; [ postgis ];
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = lib.mkDefault true;
|
||||
virtualHosts."${cfg.hostName}".locations = {
|
||||
"/".extraConfig = "proxy_pass http://unix:/run/froide-govplan/froide-govplan.socket;";
|
||||
"/static/".alias = "${cfg.dataDir}/static/";
|
||||
};
|
||||
proxyTimeout = lib.mkDefault "120s";
|
||||
};
|
||||
|
||||
systemd = {
|
||||
services = {
|
||||
|
||||
postgresql.serviceConfig.ExecStartPost =
|
||||
let
|
||||
sqlFile = pkgs.writeText "immich-pgvectors-setup.sql" ''
|
||||
CREATE EXTENSION IF NOT EXISTS postgis;
|
||||
'';
|
||||
in
|
||||
[
|
||||
''
|
||||
${lib.getExe' config.services.postgresql.package "psql"} -d govplan -f "${sqlFile}"
|
||||
''
|
||||
];
|
||||
|
||||
froide-govplan = {
|
||||
description = "Gouvernment planer Govplan";
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
StateDirectory = lib.mkIf (cfg.dataDir == "/var/lib/froide-govplan") "froide-govplan";
|
||||
User = "govplan";
|
||||
Group = "govplan";
|
||||
};
|
||||
after = [
|
||||
"postgresql.service"
|
||||
"network.target"
|
||||
"systemd-tmpfiles-setup.service"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment =
|
||||
{
|
||||
PYTHONPATH = pkg.pythonPath;
|
||||
GDAL_LIBRARY_PATH = "${pkgs.gdal}/lib/libgdal.so";
|
||||
GEOS_LIBRARY_PATH = "${pkgs.geos}/lib/libgeos_c.so";
|
||||
}
|
||||
// lib.optionalAttrs (cfg.secretKeyFile != null) {
|
||||
SECRET_KEY_FILE = cfg.secretKeyFile;
|
||||
};
|
||||
preStart = ''
|
||||
# Auto-migrate on first run or if the package has changed
|
||||
versionFile="${cfg.dataDir}/src-version"
|
||||
version=$(cat "$versionFile" 2>/dev/null || echo 0)
|
||||
|
||||
if [[ $version != ${pkg.version} ]]; then
|
||||
${lib.getExe pkg} migrate --no-input
|
||||
${lib.getExe pkg} collectstatic --no-input --clear
|
||||
echo ${pkg.version} > "$versionFile"
|
||||
fi
|
||||
'';
|
||||
script = ''
|
||||
${pkg.python.pkgs.uvicorn}/bin/uvicorn --uds /run/froide-govplan/froide-govplan.socket \
|
||||
--app-dir ${pkg}/${pkg.python.sitePackages}/froide_govplan \
|
||||
project.asgi:application
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [ "d /run/froide-govplan - govplan govplan - -" ];
|
||||
|
||||
environment.systemPackages = [ froide-govplan ];
|
||||
|
||||
users.users.govplan = {
|
||||
home = "${cfg.dataDir}";
|
||||
isSystemUser = true;
|
||||
group = "govplan";
|
||||
};
|
||||
users.groups.govplan = { };
|
||||
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ onny ];
|
||||
|
||||
}
|
||||
6
froide_govplan/static/froide_govplan/css/bootstrap.min.css
vendored
Normal file
8
froide_govplan/static/froide_govplan/css/docsearch.css
Normal file
5
froide_govplan/static/froide_govplan/css/font-awesome.css
vendored
Normal file
BIN
froide_govplan/static/froide_govplan/images/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
froide_govplan/static/froide_govplan/images/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
froide_govplan/static/froide_govplan/images/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
froide_govplan/static/froide_govplan/images/favicon.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
froide_govplan/static/froide_govplan/images/g3.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 403 KiB After Width: | Height: | Size: 403 KiB |
32
froide_govplan/static/froide_govplan/images/logo.svg
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="640.000000pt" height="640.000000pt" viewBox="0 0 640.000000 640.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.16, written by Peter Selinger 2001-2019
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,640.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M990 5042 c0 -10 668 -1325 1170 -2302 103 -201 249 -486 325 -635
|
||||
76 -148 192 -377 259 -507 l121 -238 132 0 132 0 44 83 c25 45 109 208 187
|
||||
362 78 154 176 344 216 421 41 78 74 144 74 146 0 3 -60 8 -132 11 -140 5
|
||||
-238 28 -371 83 -327 137 -587 446 -678 805 -27 108 -37 337 -19 447 16 98 53
|
||||
227 84 292 l25 51 -247 489 -247 489 -538 3 c-295 2 -537 2 -537 0z"/>
|
||||
<path d="M3850 4880 c-44 -88 -80 -162 -80 -165 0 -3 15 -5 33 -5 117 0 387
|
||||
-109 517 -209 66 -50 205 -189 251 -250 l26 -35 210 412 210 412 -544 0 -543
|
||||
0 -80 -160z"/>
|
||||
<path d="M3431 4609 c-74 -13 -218 -62 -293 -100 -273 -138 -477 -392 -557
|
||||
-692 -149 -557 191 -1143 755 -1304 92 -26 112 -28 274 -28 161 0 183 3 275
|
||||
29 100 28 241 88 293 124 l27 20 92 -87 c91 -86 92 -88 81 -117 -6 -17 -8 -43
|
||||
-4 -59 11 -42 724 -757 783 -785 62 -29 136 -27 202 6 101 51 148 159 117 268
|
||||
-16 53 -31 72 -210 259 -304 316 -528 535 -557 542 -15 4 -40 5 -55 3 -23 -2
|
||||
-35 4 -58 32 -16 19 -56 63 -89 96 l-59 62 45 63 c243 344 254 817 26 1187
|
||||
-99 161 -283 324 -457 404 -141 64 -222 81 -407 84 -93 1 -194 -2 -224 -7z
|
||||
m397 -325 c251 -72 427 -242 515 -498 28 -84 31 -102 31 -226 1 -157 -13 -221
|
||||
-74 -345 -48 -96 -107 -170 -198 -247 -144 -123 -292 -177 -488 -178 -208 0
|
||||
-389 75 -539 225 -151 151 -220 321 -219 535 1 126 17 203 64 306 88 194 271
|
||||
359 475 429 111 38 297 37 433 -1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
7
froide_govplan/static/froide_govplan/js/bootstrap.bundle.min.js
vendored
Normal file
80
froide_govplan/static/froide_govplan/js/color-modes.js
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*!
|
||||
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors
|
||||
* Licensed under the Creative Commons Attribution 3.0 Unported License.
|
||||
*/
|
||||
|
||||
(() => {
|
||||
'use strict'
|
||||
|
||||
const getStoredTheme = () => localStorage.getItem('theme')
|
||||
const setStoredTheme = theme => localStorage.setItem('theme', theme)
|
||||
|
||||
const getPreferredTheme = () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme) {
|
||||
return storedTheme
|
||||
}
|
||||
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
const setTheme = theme => {
|
||||
if (theme === 'auto') {
|
||||
document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(getPreferredTheme())
|
||||
|
||||
const showActiveTheme = (theme, focus = false) => {
|
||||
const themeSwitcher = document.querySelector('#bd-theme')
|
||||
|
||||
if (!themeSwitcher) {
|
||||
return
|
||||
}
|
||||
|
||||
const themeSwitcherText = document.querySelector('#bd-theme-text')
|
||||
const activeThemeIcon = document.querySelector('.theme-icon-active use')
|
||||
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
|
||||
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
|
||||
|
||||
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
|
||||
element.classList.remove('active')
|
||||
element.setAttribute('aria-pressed', 'false')
|
||||
})
|
||||
|
||||
btnToActive.classList.add('active')
|
||||
btnToActive.setAttribute('aria-pressed', 'true')
|
||||
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
|
||||
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
|
||||
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
|
||||
|
||||
if (focus) {
|
||||
themeSwitcher.focus()
|
||||
}
|
||||
}
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme !== 'light' && storedTheme !== 'dark') {
|
||||
setTheme(getPreferredTheme())
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
showActiveTheme(getPreferredTheme())
|
||||
|
||||
document.querySelectorAll('[data-bs-theme-value]')
|
||||
.forEach(toggle => {
|
||||
toggle.addEventListener('click', () => {
|
||||
const theme = toggle.getAttribute('data-bs-theme-value')
|
||||
setStoredTheme(theme)
|
||||
setTheme(theme)
|
||||
showActiveTheme(theme, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})()
|
||||
2
froide_govplan/static/froide_govplan/js/jquery-3.6.4.min.js
vendored
Normal file
|
Before Width: | Height: | Size: 134 KiB |
|
|
@ -7,30 +7,32 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>{% block title %}{% page_attribute "page_title" %} - {{ SITE_NAME }}{% endblock %}</title>
|
||||
|
||||
<script src="https://getbootstrap.com/docs/5.3/assets/js/color-modes.js"></script>
|
||||
<script src="{% static 'froide_govplan/js/color-modes.js' %}"></script>
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
|
||||
<meta name="generator" content="Hugo 0.122.0">
|
||||
|
||||
<link rel="canonical" href="https://getbootstrap.com/docs/5.3/examples/starter-template/">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docsearch/css@3">
|
||||
<link rel="stylesheet" href="{% static 'froide_govplan/css/docsearch.css' %}">
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="apple-touch-icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
|
||||
<link rel="icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
|
||||
<link rel="manifest" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/manifest.json">
|
||||
<link rel="mask-icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/safari-pinned-tab.svg" color="#712cf9">
|
||||
<link rel="icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/favicon.ico">
|
||||
<meta name="theme-color" content="#712cf9">
|
||||
<!-- Favicons -->
|
||||
<link rel="apple-touch-icon" href="{% static 'froide_govplan/images/apple-touch-icon.png' %}" sizes="180x180">
|
||||
<link rel="icon" href="{% static 'froide_govplan/images/favicon-32x32.png' %}" sizes="32x32" type="image/png">
|
||||
<link rel="icon" href="{% static 'froide_govplan/images/favicon-16x16.png' %}" sizes="16x16" type="image/png">
|
||||
<link rel="manifest" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/manifest.json">
|
||||
<link rel="mask-icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/safari-pinned-tab.svg" color="#712cf9">
|
||||
<link rel="icon" href="https://getbootstrap.com/docs/5.3/assets/img/favicons/favicon.ico">
|
||||
<meta name="theme-color" content="#712cf9">
|
||||
|
||||
|
||||
<script defer data-domain="verwaltungstracker.de" src="https://analytics.project-insanity.org/js/script.js"></script>
|
||||
|
||||
{% block header_font %}{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
|
||||
<link href="{% static 'froide_govplan/css/bootstrap.min.css' %}" rel="stylesheet" crossorigin="anonymous">
|
||||
<link href="{% static 'froide_govplan/css/font-awesome.css' %}" rel="stylesheet">
|
||||
<style>
|
||||
.bd-placeholder-img {
|
||||
font-size: 1.125rem;
|
||||
|
|
@ -139,9 +141,8 @@
|
|||
{% block extra_footer %}{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||
<script defer data-domain="verwaltungstracker.de" src="https://analytics.project-insanity.org/js/script.js"></script>
|
||||
<script src="{% static 'froide_govplan/js/bootstrap.bundle.min.js' %}" crossorigin="anonymous"></script>
|
||||
<script src="{% static 'froide_govplan/js/jquery-3.6.4.min.js' %}"></script>
|
||||
<script lang="javascript">
|
||||
const Ze = t => {
|
||||
const e = t.dataset.confirm;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
{% load cms_tags %}
|
||||
{% load djangocms_alias_tags %}
|
||||
{% load menu_tags %}
|
||||
{% load static %}
|
||||
{% block body %}
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
|
||||
|
|
@ -81,9 +82,10 @@
|
|||
<div class="col-lg-10 mx-auto p-4 py-md-5">
|
||||
<header class="d-flex align-items-center pb-3 mb-5 border-bottom">
|
||||
<a href="/" class="d-flex align-items-center text-body-emphasis text-decoration-none text-reset">
|
||||
<svg class="bi me-2" width="40" height="32">
|
||||
<!-- <svg class="bi me-2" width="40" height="32">
|
||||
<use xlink:href="#bootstrap" />
|
||||
</svg>
|
||||
</svg> -->
|
||||
<img src="{% static 'froide_govplan/images/apple-touch-icon.png' %}" class="bi me-2" height="32">
|
||||
<span class="fs-4">VerwaltungsTracker</span>
|
||||
</a>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -161,6 +161,10 @@ USE_TZ = True
|
|||
|
||||
STATIC_URL = "static/"
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
BASE_DIR / "static",
|
||||
]
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||
|
||||
|
|
|
|||