diff --git a/gawa/blog/admin.py b/gawa/blog/admin.py
index d976c95..7caa42b 100644
--- a/gawa/blog/admin.py
+++ b/gawa/blog/admin.py
@@ -1,4 +1,5 @@
from django.contrib import admin
+from django.utils.translation import gettext as _
from .models import *
@admin.register(Category)
@@ -7,6 +8,11 @@ class CategoryAdmin(admin.ModelAdmin):
The admin model for Category
"""
+@admin.action(description=_("Regenerate searchable traits"))
+def regenerate(modeladmin, request, queryset):
+ for obj in queryset:
+ obj.regenerate()
+
@admin.register(BlogPost)
class BlogPostAdmin(admin.ModelAdmin):
"""
@@ -14,3 +20,5 @@ class BlogPostAdmin(admin.ModelAdmin):
"""
list_display = ["title_en", "subtitle_en", "title_de", "subtitle_de", "date", "category", "slug", "suburl", "public"]
date_hierarchy = "date"
+ ordering = ['title_de', 'title_en']
+ actions = [regenerate]
diff --git a/gawa/blog/migrations/0005_auto_20230604_0050.py b/gawa/blog/migrations/0005_auto_20230604_0050.py
new file mode 100644
index 0000000..f831cf9
--- /dev/null
+++ b/gawa/blog/migrations/0005_auto_20230604_0050.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.19 on 2023-06-03 22:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('blog', '0004_blogpost_slug'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='blogpost',
+ name='featured',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AlterField(
+ model_name='blogpost',
+ name='thumbnail',
+ field=models.ImageField(blank=True, upload_to='img/thumbnails'),
+ ),
+ ]
diff --git a/gawa/blog/migrations/0006_blogpost_markdown.py b/gawa/blog/migrations/0006_blogpost_markdown.py
new file mode 100644
index 0000000..833d6ea
--- /dev/null
+++ b/gawa/blog/migrations/0006_blogpost_markdown.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.19 on 2023-06-03 22:55
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('blog', '0005_auto_20230604_0050'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='blogpost',
+ name='markdown',
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/gawa/blog/migrations/0007_remove_blogpost_public.py b/gawa/blog/migrations/0007_remove_blogpost_public.py
new file mode 100644
index 0000000..220197b
--- /dev/null
+++ b/gawa/blog/migrations/0007_remove_blogpost_public.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.19 on 2023-06-03 23:13
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('blog', '0006_blogpost_markdown'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='blogpost',
+ name='public',
+ ),
+ ]
diff --git a/gawa/blog/models.py b/gawa/blog/models.py
index 0550fd3..b03d4d5 100644
--- a/gawa/blog/models.py
+++ b/gawa/blog/models.py
@@ -1,14 +1,27 @@
from django.db import models
-
+from django.utils.translation import gettext as _
from start.models import Searchable
+import logging
+logger = logging.getLogger(__name__)
+
class Category(models.Model):
"""
A category of blog posts
+
+ Name not translated because it would make i18n in urls and Searchables specifically a pain.
+ Maybe some day it would be cool if these were Searchable
"""
- name = models.CharField(max_length=50)
+ name= models.CharField(max_length=50)
slug = models.SlugField()
+ class Meta:
+ verbose_name = _("Category")
+ verbose_name_plural = _("Categories")
+
+ def __str__(self):
+ return f"{{<{self.__class__.__name__}>\"{self.name}\"}}"
+
class BlogPost(Searchable):
"""
Should contain a blogpost
@@ -16,5 +29,21 @@ class BlogPost(Searchable):
body = models.TextField()
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
thumbnail = models.ImageField(blank=True, upload_to="img/thumbnails")
- public = models.BooleanField(default=True)
+ featured = models.BooleanField(default=False)
+ markdown = models.BooleanField(default=False)
slug = models.SlugField()
+
+
+ def regenerate(self):
+ """
+ regenerate a object
+
+ Implements the abstract method of Searchable
+ """
+ logger.info(f"regenerating {self.__class__.__name__} object: {self}")
+ self.suburl = f"/blog/{self.category.name}/{self.slug}"
+ self.save()
+
+ class Meta:
+ verbose_name = _("blog post")
+ verbose_name_plural = _("blog posts")
diff --git a/gawa/blog/templates/blog/featured.html b/gawa/blog/templates/blog/featured.html
index f3de44c..0fd2484 100644
--- a/gawa/blog/templates/blog/featured.html
+++ b/gawa/blog/templates/blog/featured.html
@@ -2,6 +2,7 @@
{% trans "Featured" %}
+ {% for post in featured_posts %}
-
-
-
-
Card title
-
Some quick example text to build on the card title and make up the bulk of the card's content.
-
-
- - An item
- - A second item
- - A third item
-
-
-
-
-
-
-
Card title
-
Some quick example text to build on the card title and make up the bulk of the card's content.
-
-
- - An item
- - A second item
- - A third item
-
-
-
-
-
-
-
Card title
-
Some quick example text to build on the card title and make up the bulk of the card's content.
-
-
- - An item
- - A second item
- - A third item
-
-
-
-
-
-
-
-
-
Card title
-
Some quick example text to build on the card title and make up the bulk of the card's content.
-
-
- - An item
- - A second item
- - A third item
-
-
-
-
-
-
-
Card title
-
Some quick example text to build on the card title and make up the bulk of the card's content.
-
-
- - An item
- - A second item
- - A third item
-
-
-
-
-
-
-
Card title
-
Some quick example text to build on the card title and make up the bulk of the card's content.
-
-
- - An item
- - A second item
- - A third item
-
-
-
-
-
-
-
Card title
-
Some quick example text to build on the card title and make up the bulk of the card's content.
-
-
- - An item
- - A second item
- - A third item
-
-
-
+ {% endfor %}
diff --git a/gawa/blog/views.py b/gawa/blog/views.py
index baad3aa..f9090cb 100644
--- a/gawa/blog/views.py
+++ b/gawa/blog/views.py
@@ -6,7 +6,6 @@ from .models import BlogPost, Category
from start.views import SearchableView
import logging
-
logger = logging.getLogger(__name__)
class Index(TemplateView, SearchableView):
@@ -19,6 +18,12 @@ class Index(TemplateView, SearchableView):
template_name: str = "blog/index.html"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['featured_posts'] = BlogPost.objects.filter(featured=True, public=True)
+ logger.debug(f"loaded featured posts: {context['featured_posts']}")
+ return context
+
class Post(DetailView):
"""
Main page of a blog post
@@ -28,6 +33,12 @@ class Post(DetailView):
template_name = "blog/blogpost.html"
context_object_name = "post"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['featured_posts'] = BlogPost.objects.filter(featured=True)
+ logger.debug(f"loaded featured posts: {context['featured_posts']}")
+ return context
+
def get_object(self, queryset=None):
obj = get_object_or_404(
BlogPost,
@@ -61,6 +72,12 @@ class CategoryList(ListView):
template_name = "blog/categories.html"
context_object_name = "categories"
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['featured_posts'] = BlogPost.objects.filter(featured=True)
+ logger.debug(f"loaded featured posts: {context['featured_posts']}")
+ return context
+
class ArticleList(ListView):
"""
Scroll through a list of blog posts
@@ -72,3 +89,9 @@ class ArticleList(ListView):
model=BlogPost
template_name = "blog/posts.html"
context_object_name = "posts"
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['featured_posts'] = BlogPost.objects.filter(featured=True)
+ logger.debug(f"loaded featured posts: {context['featured_posts']}")
+ return context
diff --git a/gawa/migrate.sh b/gawa/migrate.sh
new file mode 100755
index 0000000..1926a10
--- /dev/null
+++ b/gawa/migrate.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+python manage.py makemigrations && python manage.py migrate
diff --git a/gawa/start/admin.py b/gawa/start/admin.py
index 4a31d70..7cb02d1 100644
--- a/gawa/start/admin.py
+++ b/gawa/start/admin.py
@@ -1,8 +1,15 @@
from django.contrib import admin
from django.db.models import CASCADE, AutoField, OneToOneField
from django.views.generic import View
+from django.utils.translation import gettext as _
from .models import *
+
+@admin.action(description=_("Regenerate searchable traits"))
+def regenerate(modeladmin, request, queryset):
+ for obj in queryset:
+ obj.regenerate()
+
@admin.register(Keyword)
class KeywordAdmin(admin.ModelAdmin):
"""
@@ -16,3 +23,5 @@ class StaticSiteAdmin(admin.ModelAdmin):
Admin Interface for StaticSite
"""
list_display = ["title_en", "subtitle_en", "title_de", "subtitle_de", "suburl"]
+ ordering = ['title_de', 'title_en']
+ actions = [regenerate]
diff --git a/gawa/start/apps.py b/gawa/start/apps.py
index 9f48da5..7ec3c85 100644
--- a/gawa/start/apps.py
+++ b/gawa/start/apps.py
@@ -1,6 +1,5 @@
from django.apps import AppConfig
-
class StartConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'start'
diff --git a/gawa/start/migrations/0003_searchable_public.py b/gawa/start/migrations/0003_searchable_public.py
new file mode 100644
index 0000000..a923f0c
--- /dev/null
+++ b/gawa/start/migrations/0003_searchable_public.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.19 on 2023-06-03 23:13
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('start', '0002_keyword_searchable_staticsite'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='searchable',
+ name='public',
+ field=models.BooleanField(default=True),
+ ),
+ ]
diff --git a/gawa/start/models.py b/gawa/start/models.py
index 3037556..cec0708 100644
--- a/gawa/start/models.py
+++ b/gawa/start/models.py
@@ -1,8 +1,8 @@
from django.db import models
from django.db.models.options import override
-#from .views import SearchableView
-# ^^^ raises Circular Import
+import logging
+logger = logging.getLogger(__name__)
class Keyword(models.Model):
"""
@@ -11,6 +11,9 @@ class Keyword(models.Model):
text_de = models.CharField(max_length=40)
text_en = models.CharField(max_length=40)
+ def __str__(self):
+ return f"{{<{self.__class__.__name__}>\"{self.text_en}\"}}"
+
class Searchable(models.Model):
"""
Abstract class for any model that should be searchable.
@@ -28,13 +31,25 @@ class Searchable(models.Model):
date = models.DateField(blank=True, null=True)
keywords = models.ManyToManyField(Keyword)
suburl = models.CharField(max_length=200, blank=True, null=True)
+ public = models.BooleanField(default=True)
@classmethod
def regenerate_all_entries(cls):
"""
regenerate all searchable items
"""
- raise NotImplementedError
+ logger.info(f"regenerating all {Searchable.__name__} entries")
+ for obj in cls.objects.all():
+ obj.regenerate()
+
+ def __str__(self):
+ return f"{{<{self.__class__.__name__}>\"{self.title_en}\"}}"
+
+ def regenerate(self):
+ """
+ regenerate a object
+ """
+ raise NotImplementedError("This model does not implement regenerate")
class StaticSite(Searchable):
"""
@@ -54,4 +69,4 @@ class StaticSite(Searchable):
# TODO automate searching for these
#all_views: list[SearchableView] = []
- raise NotImplementedError
+ raise NotImplementedError("This model does not implement regenerate_all_entries")
diff --git a/gawa/start/views.py b/gawa/start/views.py
index c2953df..a0fd0bc 100644
--- a/gawa/start/views.py
+++ b/gawa/start/views.py
@@ -85,6 +85,7 @@ class MainSearch(ListView):
Q(subtitle_de__icontains=search) | Q(subtitle_en__icontains=search) |
Q(desc_de__icontains=search) | Q(desc_en__icontains=search)
)
+ object_list = object_list.filter(public=True)
print(object_list)
return object_list
diff --git a/gawa/thumbnails/thuglifemathemann.png b/gawa/thumbnails/thuglifemathemann.png
deleted file mode 100644
index a6daad6..0000000
Binary files a/gawa/thumbnails/thuglifemathemann.png and /dev/null differ