From 8ed39690f147f379589832637f99243e686fef7f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 28 Jan 2025 11:00:15 +0100 Subject: [PATCH] add external links --- hub/services/admin.py | 10 +++- hub/services/migrations/0012_externallink.py | 46 +++++++++++++++++++ hub/services/models.py | 30 ++++++++++++ hub/services/templates/services/base.html | 1 + .../templates/services/service_detail.html | 12 +++++ 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 hub/services/migrations/0012_externallink.py diff --git a/hub/services/admin.py b/hub/services/admin.py index 1f46934..9fac200 100644 --- a/hub/services/admin.py +++ b/hub/services/admin.py @@ -8,6 +8,7 @@ from .models import ( Currency, Plan, PlanPrice, + ExternalLink, ) @@ -33,6 +34,13 @@ class PlanInline(admin.StackedInline): return formset +class ExternalLinkInline(admin.TabularInline): + model = ExternalLink + extra = 1 + fields = ("description", "url", "order") + ordering = ("order", "description") + + @admin.register(Category) class CategoryAdmin(admin.ModelAdmin): list_display = ("name", "slug", "parent", "order") @@ -73,7 +81,7 @@ class ServiceAdmin(admin.ModelAdmin): filter_horizontal = ("categories", "consulting_partners") search_fields = ("name", "description", "slug") prepopulated_fields = {"slug": ("name",)} - inlines = [PlanInline] + inlines = [PlanInline, ExternalLinkInline] def logo_preview(self, obj): if obj.logo: diff --git a/hub/services/migrations/0012_externallink.py b/hub/services/migrations/0012_externallink.py new file mode 100644 index 0000000..52f3138 --- /dev/null +++ b/hub/services/migrations/0012_externallink.py @@ -0,0 +1,46 @@ +# Generated by Django 5.1.5 on 2025-01-28 09:58 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("services", "0011_lead_plan"), + ] + + operations = [ + migrations.CreateModel( + name="ExternalLink", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("url", models.URLField()), + ("description", models.CharField(max_length=200)), + ("order", models.IntegerField(default=0)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "service", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="external_links", + to="services.service", + ), + ), + ], + options={ + "verbose_name": "External Link", + "verbose_name_plural": "External Links", + "ordering": ["order", "description"], + }, + ), + ] diff --git a/hub/services/models.py b/hub/services/models.py index 99e6f59..806d82c 100644 --- a/hub/services/models.py +++ b/hub/services/models.py @@ -205,3 +205,33 @@ class Lead(models.Model): def __str__(self): return f"{self.name} - {self.company} ({self.service})" + + +class ExternalLink(models.Model): + service = models.ForeignKey( + Service, on_delete=models.CASCADE, related_name="external_links" + ) + url = models.URLField() + description = models.CharField(max_length=200) + order = models.IntegerField(default=0) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + ordering = ["order", "description"] + verbose_name = "External Link" + verbose_name_plural = "External Links" + + def __str__(self): + return f"{self.description} ({self.url})" + + def clean(self): + from django.core.validators import URLValidator + from django.core.exceptions import ValidationError + + # Validate URL + validate = URLValidator() + try: + validate(self.url) + except ValidationError: + raise ValidationError({"url": "Enter a valid URL."}) diff --git a/hub/services/templates/services/base.html b/hub/services/templates/services/base.html index fc9e125..d37cc86 100644 --- a/hub/services/templates/services/base.html +++ b/hub/services/templates/services/base.html @@ -5,6 +5,7 @@ Servala - The Cloud Native Services Hub +