diff --git a/ljg/core/auth.py b/ljg/core/auth.py index 4ad8b71..d56cbb1 100644 --- a/ljg/core/auth.py +++ b/ljg/core/auth.py @@ -1,6 +1,9 @@ from django.conf import settings from django.contrib.auth.models import Permission from django.db import transaction +from django.db.models import CharField +from django.db.models import Value as V +from django.db.models.functions import Concat from mozilla_django_oidc.auth import ( OIDCAuthenticationBackend as BaseOIDCAuthenticationBackend, ) @@ -13,8 +16,12 @@ def get_permissions(claims): if roles is None or settings.OIDC_RP_CLIENT_ID not in roles: return Permission.objects.none() - return Permission.objects.filter( - codename__in=claims.get("resource_access")[settings.OIDC_RP_CLIENT_ID]["roles"] + return Permission.objects.annotate( + fullname=Concat( + "content_type__app_label", V("."), "codename", output_field=CharField() + ) + ).filter( + fullname__in=claims.get("resource_access")[settings.OIDC_RP_CLIENT_ID]["roles"] ) diff --git a/ljg/core/templates/base.html b/ljg/core/templates/base.html index ebc699f..81b0262 100644 --- a/ljg/core/templates/base.html +++ b/ljg/core/templates/base.html @@ -1,4 +1,3 @@ -{% load i18n %} {% load static %} @@ -11,6 +10,8 @@ {% block body %} +{% block content %} +{% endblock %} {% endblock %} diff --git a/ljg/redirect/__init__.py b/ljg/redirect/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ljg/redirect/admin.py b/ljg/redirect/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/ljg/redirect/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/ljg/redirect/apps.py b/ljg/redirect/apps.py new file mode 100644 index 0000000..481dc61 --- /dev/null +++ b/ljg/redirect/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class RedirectConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "ljg.redirect" diff --git a/ljg/redirect/forms.py b/ljg/redirect/forms.py new file mode 100644 index 0000000..e348328 --- /dev/null +++ b/ljg/redirect/forms.py @@ -0,0 +1,9 @@ +from django import forms + +from .models import Redirect + + +class RedirectForm(forms.ModelForm): + class Meta: + model = Redirect + fields = ("target",) diff --git a/ljg/redirect/migrations/0001_initial.py b/ljg/redirect/migrations/0001_initial.py new file mode 100644 index 0000000..1691f7b --- /dev/null +++ b/ljg/redirect/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.4 on 2023-10-16 18:14 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Redirect", + fields=[ + ("name", models.SlugField(primary_key=True, serialize=False)), + ("target", models.URLField()), + ( + "owner", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/ljg/redirect/migrations/__init__.py b/ljg/redirect/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ljg/redirect/models.py b/ljg/redirect/models.py new file mode 100644 index 0000000..6479fb3 --- /dev/null +++ b/ljg/redirect/models.py @@ -0,0 +1,11 @@ +from django.contrib.auth.models import User +from django.db import models + + +class Redirect(models.Model): + name = models.SlugField(primary_key=True) + target = models.URLField() + owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + + def get_absolute_url(self): + return self.target diff --git a/ljg/redirect/templates/redirect/manage.html b/ljg/redirect/templates/redirect/manage.html new file mode 100644 index 0000000..3852547 --- /dev/null +++ b/ljg/redirect/templates/redirect/manage.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% load i18n %} + +{% block title %}{{ name }} – {{ APP_TITLE }}{% endblock %} + +{% block content %} +
+ {% csrf_token %} + {{ form }} + +
+{% endblock %} diff --git a/ljg/redirect/tests.py b/ljg/redirect/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ljg/redirect/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ljg/redirect/urls.py b/ljg/redirect/urls.py new file mode 100644 index 0000000..fce6686 --- /dev/null +++ b/ljg/redirect/urls.py @@ -0,0 +1,16 @@ +from django.urls import include, path + +from . import views + +app_name = "redirect" +urlpatterns = [ + path( + "/", + include( + [ + path("", views.go, name="go"), + path("manage", views.manage, name="manage"), + ] + ), + ), +] diff --git a/ljg/redirect/views.py b/ljg/redirect/views.py new file mode 100644 index 0000000..5ba5e7b --- /dev/null +++ b/ljg/redirect/views.py @@ -0,0 +1,66 @@ +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.http import Http404 +from django.shortcuts import redirect, render +from django.utils.translation import gettext as _ + +from .forms import RedirectForm +from .models import Redirect + + +def go(request, name): + try: + obj = Redirect.objects.get(name=name) + except Redirect.DoesNotExist: + if request.user.has_perm("redirect.add_redirect"): + return redirect("redirect:manage", name=name) + + raise Http404() + + return redirect(obj) + + +@login_required +def manage(request, name): + try: + obj = Redirect.objects.get(name=name) + except Redirect.DoesNotExist: + obj = None + + form = RedirectForm(instance=obj) + + if request.method == "POST": + form = RedirectForm(request.POST, instance=obj) + + if form.is_valid(): + action = "add" if obj is None else "change" + if request.user.has_perm(f"redirect.{action}_redirect"): + obj = form.save(commit=False) + + if action == "add": + obj.name = name + obj.owner = request.user + + obj.save() + + messages.success( + request, + _( + "Successfully %s redirect" + % ("added" if action == "add" else "changed") + ), + ) + else: + messages.error( + request, _(f"You do not have permission to {action} this redirect.") + ) + + return redirect("redirect:manage", name=name) + else: + return redirect("redirect:manage", name=name) + + return render( + request, + "redirect/manage.html", + {"form": form, "name": name, "new": obj is None}, + ) diff --git a/ljg/settings.py b/ljg/settings.py index 9c4609e..82d92f9 100644 --- a/ljg/settings.py +++ b/ljg/settings.py @@ -44,6 +44,7 @@ INSTALLED_APPS = [ "django.contrib.messages", "django.contrib.staticfiles", "ljg.core.apps.CoreConfig", + "ljg.redirect.apps.RedirectConfig", "mozilla_django_oidc", ] diff --git a/ljg/urls.py b/ljg/urls.py index 327ca2e..c837092 100644 --- a/ljg/urls.py +++ b/ljg/urls.py @@ -18,6 +18,7 @@ from django.contrib import admin from django.urls import include, path urlpatterns = [ + path("", include("ljg.redirect.urls")), path("admin/", admin.site.urls), path("oidc/", include("mozilla_django_oidc.urls")), ]