diff --git a/flake.lock b/flake.lock index 198ad88..471ca20 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1748162331, - "narHash": "sha256-rqc2RKYTxP3tbjA+PB3VMRQNnjesrT0pEofXQTrMsS8=", + "lastModified": 1758070117, + "narHash": "sha256-uLwwHFCZnT1c3N3biVe/0hCkag2GSrf9+M56+Okf+WY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7c43f080a7f28b2774f3b3f43234ca11661bf334", + "rev": "e9b7f2ff62b35f711568b1f0866243c7c302028d", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 04a699a..cfad560 100644 --- a/flake.nix +++ b/flake.nix @@ -3,83 +3,97 @@ inputs.nixpkgs.url = "nixpkgs/nixos-25.05"; - outputs = { self, nixpkgs, ... }@inputs: - let - pkgs = nixpkgs.legacyPackages.x86_64-linux; - start = - pkgs.writeShellScriptBin "start" '' - set -e - export NIXPKGS_ALLOW_INSECURE=1 - export QEMU_NET_OPTS="hostfwd=tcp::8080-:80" - ${pkgs.nixos-shell}/bin/nixos-shell --flake . - ''; - in { - nixosConfigurations.vm = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - specialArgs.inputs = inputs; - pkgs = import nixpkgs { - overlays = [ - (self: super: { - froide-govplan = super.froide-govplan.overrideAttrs (oldAttrs: rec { - src = ./.; - 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/ - ''; - }); - - pythonPackagesExtensions = super.pythonPackagesExtensions ++ [ - ( - python-final: python-prev: { - moto = python-prev.moto.overridePythonAttrs (oldAttrs: { doCheck = false; }); - } - ) - ]; - + outputs = + { self, nixpkgs, ... }@inputs: + let + pkgs = nixpkgs.legacyPackages.x86_64-linux; + start = pkgs.writeShellScriptBin "start" '' + set -e + export NIXPKGS_ALLOW_INSECURE=1 + export QEMU_NET_OPTS="hostfwd=tcp::8080-:80" + ${pkgs.nixos-shell}/bin/nixos-shell --flake . + ''; + in + { + nixosConfigurations.vm = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs.inputs = inputs; + pkgs = import nixpkgs { + overlays = [ + (self: super: { + froide-govplan = super.froide-govplan.overrideAttrs (oldAttrs: rec { + src = ./.; + 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/ + ''; + }); + pythonPackagesExtensions = super.pythonPackagesExtensions ++ [ + (python-final: python-prev: { + moto = python-prev.moto.overridePythonAttrs (oldAttrs: { + doCheck = false; + }); + }) + ]; }) + ]; + }; + modules = [ + ( + { + lib, + config, + pkgs, + ... + }: + { + + virtualisation = { + memorySize = 8000; + diskSize = 4096; + 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" ]; + }; + }; + + nixos-shell.mounts.extraMounts = { + "/var/lib/froide-govplan/templates" = { + target = /home/onny/projects/verwaltungstracker/froide_govplan/templates; + cache = "none"; + }; + }; + + system.stateVersion = "25.05"; + services.getty.autologinUser = "root"; + } + ) ]; }; - modules = [ - ({ lib, config, pkgs, ... }: { - virtualisation = { - memorySize = 8000; - diskSize = 4096; - cores = 4; - }; + devShells.x86_64-linux.default = pkgs.mkShell { + packages = [pkgs.python3Packages.mastodon-py ] ++ pkgs.froide-govplan.dependencies; + shellHook = '' + export GDAL_LIBRARY_PATH="${pkgs.gdal}/lib/libgdal.so" + export GEOS_LIBRARY_PATH="${pkgs.geos}/lib/libgeos_c.so" + ''; + }; - disabledModules = [ "services/web-apps/froide-govplan.nix" ]; + packages = { inherit start; }; + defaultPackage.x86_64-linux = start; - imports = [ ./froide-govplan.nix ]; - - services.froide-govplan = { - enable = true; - package = pkgs.froide-govplan; - settings = { - DEBUG = lib.mkForce true; - CSRF_TRUSTED_ORIGINS = [ "http://localhost:8080" ]; - }; - }; - - nixos-shell.mounts.extraMounts = { - "/var/lib/froide-govplan/templates" = { - target = /home/onny/projects/froide-govplan/froide_govplan/templates; - cache = "none"; - }; - }; - - system.stateVersion = "25.05"; - services.getty.autologinUser = "root"; - }) - ]; }; - - packages = { inherit start; }; - defaultPackage.x86_64-linux = start; - - }; } - diff --git a/froide_govplan/admin.py b/froide_govplan/admin.py index 3e3f951..10aae4f 100644 --- a/froide_govplan/admin.py +++ b/froide_govplan/admin.py @@ -22,6 +22,7 @@ from .models import ( GovernmentPlanFollower, GovernmentPlanSection, GovernmentPlanUpdate, + FOIRequest, ) User = auth.get_user_model() @@ -345,12 +346,22 @@ class GovernmentPlanSectionAdmin(SortableAdminMixin, admin.ModelAdmin): ) +class FOIRequestAdmin(admin.ModelAdmin): + list_display = ("title", "government_plan", "url", "created_at") + list_filter = ("government_plan",) + search_fields = ("title", "government_plan__title") + date_hierarchy = "created_at" + + admin.site.register(Government, GovernmentAdmin) admin.site.register(GovernmentPlan, GovernmentPlanAdmin) admin.site.register(GovernmentPlanUpdate, GovernmentPlanUpdateAdmin) admin.site.register(GovernmentPlanSection, GovernmentPlanSectionAdmin) admin.site.register(GovernmentPlanFollower, FollowerAdmin) +admin.site.register(FOIRequest, FOIRequestAdmin) + govplan_admin_site = GovPlanAdminSite(name="govplanadmin") +govplan_admin_site.register(FOIRequest, FOIRequestAdmin) govplan_admin_site.register(GovernmentPlan, GovernmentPlanAdmin) govplan_admin_site.register(GovernmentPlanUpdate, GovernmentPlanUpdateAdmin) diff --git a/froide_govplan/migrations/0015_alter_categorizedgovernmentplan_id_and_more.py b/froide_govplan/migrations/0015_alter_categorizedgovernmentplan_id_and_more.py new file mode 100644 index 0000000..8af508c --- /dev/null +++ b/froide_govplan/migrations/0015_alter_categorizedgovernmentplan_id_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 5.1.12 on 2025-09-18 20:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('froide_govplan', '0014_remove_governmentplansection_content_placeholder'), + ] + + operations = [ + migrations.AlterField( + model_name='categorizedgovernmentplan', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='government', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='governmentplan', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='governmentplanfollower', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='governmentplansection', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='governmentplanupdate', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + ] diff --git a/froide_govplan/migrations/0016_foirequest.py b/froide_govplan/migrations/0016_foirequest.py new file mode 100644 index 0000000..729782d --- /dev/null +++ b/froide_govplan/migrations/0016_foirequest.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.12 on 2025-09-19 12:36 + +import django.db.models.deletion +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('froide_govplan', '0015_alter_categorizedgovernmentplan_id_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='FOIRequest', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=1024, verbose_name='title')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='created at')), + ('government_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='foi_requests', to='froide_govplan.governmentplan', verbose_name='government plan')), + ], + options={ + 'verbose_name': 'FOI request', + 'verbose_name_plural': 'FOI requests', + 'ordering': ('-created_at',), + 'get_latest_by': 'created_at', + }, + ), + ] diff --git a/froide_govplan/migrations/0017_foirequest_url.py b/froide_govplan/migrations/0017_foirequest_url.py new file mode 100644 index 0000000..5a77424 --- /dev/null +++ b/froide_govplan/migrations/0017_foirequest_url.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.12 on 2025-09-19 12:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('froide_govplan', '0016_foirequest'), + ] + + operations = [ + migrations.AddField( + model_name='foirequest', + name='url', + field=models.CharField(blank=True, max_length=1024, verbose_name='URL'), + ), + ] diff --git a/froide_govplan/models.py b/froide_govplan/models.py index 14043e5..63ca94f 100644 --- a/froide_govplan/models.py +++ b/froide_govplan/models.py @@ -321,23 +321,29 @@ class GovernmentPlan(models.Model): return "govplan:plan@{}".format(self.pk) def get_related_foirequests(self): - if FoiRequest is None: - return [] - if not self.responsible_publicbody: - return [] - if hasattr(self, "_related_foirequests"): - return self._related_foirequests + return FOIRequest.objects.filter(government_plan=self).order_by('-created_at') - self._related_foirequests = ( - FoiRequest.objects.filter( - visibility=FoiRequest.VISIBILITY.VISIBLE_TO_PUBLIC, - public_body=self.responsible_publicbody, - ) - .filter(tags__name=conf.GOVPLAN_NAME) - .filter(reference=self.get_foirequest_reference()) - .order_by("-created_at") - ) - return self._related_foirequests + + +class FOIRequest(models.Model): + title = models.CharField(max_length=1024, verbose_name=_("title")) + government_plan = models.ForeignKey( + 'GovernmentPlan', + on_delete=models.CASCADE, + related_name='foi_requests', + verbose_name=_("government plan"), + ) + url = models.CharField(max_length=1024, blank=True, verbose_name=_("URL")) + created_at = models.DateTimeField(default=timezone.now, verbose_name=_("created at")) + + class Meta: + ordering = ("-created_at",) + get_latest_by = "created_at" + verbose_name = _("FOI request") + verbose_name_plural = _("FOI requests") + + def __str__(self): + return f"{self.title} - {self.government_plan.title}" class GovernmentPlanUpdate(models.Model): diff --git a/froide_govplan/signals.py b/froide_govplan/signals.py index fb32d09..550024d 100644 --- a/froide_govplan/signals.py +++ b/froide_govplan/signals.py @@ -27,7 +27,7 @@ def send_mastodon_toot_update(sender, instance, created, **kwargs): f"{instance.title}: {strip_html_tags(instance.content)}\n\n" f"🔗 Primärquelle: {instance.url}\n" f"📋 Verwaltungstracker-Eintrag: {instance.plan.get_absolute_domain_url()}\n\n" - f"#karlsruhe" + f"#karlsruhe #kommunalpolitik" )) @receiver(post_save, sender=GovernmentPlan) @@ -37,5 +37,5 @@ def send_mastodon_toot_plan(sender, instance, created, **kwargs): f"📢 Neues Verwaltungsvorhaben '{instance.title}' wurde aufgenommen.\n\n" f"🔗 Primärquelle: {instance.reference}\n" f"📋 Verwaltungstracker-Eintrag: {instance.get_absolute_domain_url()}\n\n" - f"#karlsruhe" + f"#karlsruhe #kommunalpolitik" )) diff --git a/froide_govplan/static/froide_govplan/images/g3.png b/froide_govplan/static/froide_govplan/images/g3.png deleted file mode 100644 index e62bf7b..0000000 Binary files a/froide_govplan/static/froide_govplan/images/g3.png and /dev/null differ diff --git a/froide_govplan/static/froide_govplan/images/logo.png b/froide_govplan/static/froide_govplan/images/logo.png deleted file mode 100644 index e3a6b02..0000000 Binary files a/froide_govplan/static/froide_govplan/images/logo.png and /dev/null differ diff --git a/froide_govplan/static/froide_govplan/images/logo.svg b/froide_govplan/static/froide_govplan/images/logo.svg index 908a004..eba6fa6 100644 --- a/froide_govplan/static/froide_govplan/images/logo.svg +++ b/froide_govplan/static/froide_govplan/images/logo.svg @@ -1,32 +1,58 @@ - - - - + + + + + + + Created by potrace 1.16, written by Peter Selinger 2001-2019 - - - - - + + + + + diff --git a/froide_govplan/static/froide_govplan/images/magnify_pyramid.webp b/froide_govplan/static/froide_govplan/images/magnify_pyramid.webp index 2369601..764b2d8 100644 Binary files a/froide_govplan/static/froide_govplan/images/magnify_pyramid.webp and b/froide_govplan/static/froide_govplan/images/magnify_pyramid.webp differ diff --git a/froide_govplan/static/froide_govplan/images/mastodon-footer.svg b/froide_govplan/static/froide_govplan/images/mastodon-footer.svg deleted file mode 100644 index d27f75d..0000000 --- a/froide_govplan/static/froide_govplan/images/mastodon-footer.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/froide_govplan/templates/froide_govplan/about.html b/froide_govplan/templates/froide_govplan/about.html index 0abca8f..aae2c71 100644 --- a/froide_govplan/templates/froide_govplan/about.html +++ b/froide_govplan/templates/froide_govplan/about.html @@ -7,6 +7,29 @@ {% endblock meta %} {% block app_body %} -

Hello World!

+

Für eine transparente Kommunalverwaltung!

+ +

+ Mit unserem Projekt VerwaltungsTracker.de möchten wir Transparenz + in die Vorhaben der Kommunalverwaltungen bringen. + Für Karlsruhe haben wir über 60 überprüfbare Projekte identifiziert + die wir für eine gerechte sozial-ökologische Zukunft unserer Stadt + für sinnvoll erachten. +

+ +

+ In verschiedenen Kategorien sammeln wir die Vorhaben, verlinken + die Quellen aus der Lokalpresse oder Gemeinderatsdokumenten und + listen chronologisch aktuelle Entwicklungen auf der jeweiligen + Unterseite. +

+ +

+ Du hast ein wichtiges Vorhaben, welches hierher gehört? Dann + schicke uns eine Mail an + onny@project-insanity.org. Zu einem Vorhaben gibt es eine neue + Entwicklung? Dann nutze das Formular auf der Vorhaben-Seite zum Melden + neuer Entwicklungen. +

{% endblock app_body %} diff --git a/froide_govplan/templates/froide_govplan/base.html b/froide_govplan/templates/froide_govplan/base.html index 7ec6ef4..5816ccc 100644 --- a/froide_govplan/templates/froide_govplan/base.html +++ b/froide_govplan/templates/froide_govplan/base.html @@ -5,6 +5,12 @@ {% load static %} {% block body %} + + @@ -71,7 +77,7 @@
- + VerwaltungsTracker