fix djangocms blog models

This commit is contained in:
bruks 2026-10-04 12:26:48 +01:00
commit 8caca66b66
12 changed files with 640 additions and 45 deletions

3
.gitignore vendored
View file

@ -47,3 +47,6 @@ secret-key
2024-*
2025-*
2023-*
files/

View file

@ -1,21 +0,0 @@
import factory
from django.contrib.sites.models import Site
from datacenterlight.cms_models import CMSIntegration
class SiteFactory(factory.django.DjangoModelFactory):
class Meta:
model = Site
django_get_or_create = ("domain",)
domain = factory.Sequence(lambda n: f"example{n}.test")
name = factory.LazyAttribute(lambda obj: obj.domain)
class CMSIntegrationFactory(factory.django.DjangoModelFactory):
class Meta:
model = CMSIntegration
name = factory.Sequence(lambda n: f"integration-{n}")
domain = factory.SubFactory(SiteFactory)

View file

@ -22,7 +22,7 @@ from datacenterlight.views import (
show_error,
)
from utils.forms import BillingAddressFormSignup
from .factories import CMSIntegrationFactory
from factories import CMSIntegrationFactory
class SessionRequestMixin:

View file

@ -14,17 +14,17 @@
{% endfor %}
<hr>
<h2 class="intro-text text-center">
{% static_placeholder "digital_glarus_contact_title" %}
{% placeholder "digital_glarus_contact_title" %}
</h2>
<hr>
</div>
<div class="col-md-8">
<p>
{% static_placeholder "digital_glarus_contact_location" %}
{% placeholder "digital_glarus_contact_location" %}
</p>
</div>
<div class="col-md-4">
{% static_placeholder "digital_glarus_contact_information" %}
{% placeholder "digital_glarus_contact_information" %}
<div class="clearfix">&nbsp;</div>
</div>
<div class="clearfix"></div>
@ -36,10 +36,10 @@
<div class="col-lg-12">
<hr>
<h2 class="intro-text text-center">
{% static_placeholder "digital_glarus_contact_form_title" %}
{% placeholder "digital_glarus_contact_form_title" %}
</h2>
<hr>
<p>{% static_placeholder "digital_glarus_contact_form_text" %}</p>
<p>{% placeholder "digital_glarus_contact_form_text" %}</p>
<form action="{% url 'digitalglarus:contact' %}" method="post" >
{% csrf_token %}
<div class="row">

View file

@ -10,13 +10,13 @@
<div class="col-lg-12">
<hr>
<h2 class="text-center">
{% static_placeholder "digital_glarus_supporters_title" %}
{% placeholder "digital_glarus_supporters_title" %}
</h2>
<hr>
</div>
<div class="col-md-12">
<div class="text-center">
{% static_placeholder "digital_glarus_supporters_info" %}
{% placeholder "digital_glarus_supporters_info" %}
</div>
</div>
<div class="col-md-12">
@ -27,7 +27,7 @@
</div>
{% endfor %}
<hr>
<a class="btn btn-default" href="{% url 'digitalglarus:support' %}" role="button">{% static_placeholder "digital_glarus_supporters_become_supporter" %}</a>
<a class="btn btn-default" href="{% url 'digitalglarus:support' %}" role="button">{% placeholder "digital_glarus_supporters_become_supporter" %}</a>
</div>
</div>

476
digitalglarus/tests.py Normal file
View file

@ -0,0 +1,476 @@
from datetime import date
from unittest.mock import patch
from django.contrib.auth import get_user_model
from django.test import RequestFactory, TestCase
from django.urls import reverse
from digitalglarus.forms import (
BookingDateForm
)
from utils.forms import ContactUsForm
from digitalglarus.models import (
BookingPrice,
MembershipType,
Supporter,
)
from digitalglarus.views import (
IndexView,
SupportusView,
LoginView,
SignupView,
PasswordResetView,
PasswordResetConfirmView,
HistoryView,
MembershipPricingView,
MembershipActivatedView,
ContactView,
BookingSelectDatesView,
)
from factories import (
SupporterFactory,
BookingPriceFactory,
CustomUserFactory,
PostFactory,
)
User = get_user_model()
class IndexViewTests(TestCase):
def test_get_renders_template(self):
response = self.client.get(
reverse("digitalglarus:landing")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/index.html",
)
class SupportusViewTests(TestCase):
@patch("digitalglarus.views.Post.objects.filter")
def test_get_renders_template(self, mock_filter):
mock_filter.return_value.translated.return_value = []
response = self.client.get(
reverse("digitalglarus:supportus")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/supportus.html",
)
self.assertIn("post_list", response.context)
@patch("digitalglarus.views.Post.objects.filter")
def test_context_contains_posts(self, mock_filter):
posts = ["post1", "post2"]
mock_filter.return_value.translated.return_value = posts
request = RequestFactory().get(
reverse("digitalglarus:supportus")
)
view = SupportusView()
view.setup(request)
context = view.get_context_data()
self.assertEqual(
context["post_list"],
posts,
)
class HistoryViewTests(TestCase):
def test_get_renders_template(self):
SupporterFactory()
response = self.client.get(
reverse("digitalglarus:history")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/history.html",
)
self.assertIn(
"supporters",
response.context,
)
def test_context_contains_supporters(self):
supporter = SupporterFactory()
request = RequestFactory().get(
reverse("digitalglarus:history")
)
view = HistoryView()
view.setup(request)
context = view.get_context_data()
self.assertIn(
supporter,
context["supporters"],
)
class LoginViewTests(TestCase):
def test_get_renders_template(self):
response = self.client.get(
reverse("digitalglarus:login")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/login.html",
)
def test_get_success_url_without_membership_orders(self):
request = RequestFactory().get(
reverse("digitalglarus:login")
)
request.user = CustomUserFactory.create()
view = LoginView()
view.setup(request)
result = view.get_success_url()
self.assertEqual(
result,
reverse("digitalglarus:membership_pricing"),
)
class SignupViewTests(TestCase):
def test_get_renders_template(self):
response = self.client.get(
reverse("digitalglarus:signup")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/signup.html",
)
def test_success_url(self):
view = SignupView()
self.assertEqual(
str(view.success_url),
reverse("digitalglarus:login"),
)
class PasswordResetViewTests(TestCase):
def test_get_renders_template(self):
response = self.client.get(
reverse("digitalglarus:reset_password")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/reset_password.html",
)
class PasswordResetConfirmViewTests(TestCase):
def test_template_name(self):
view = PasswordResetConfirmView()
self.assertEqual(
view.template_name,
"digitalglarus/confirm_reset_password.html",
)
def test_success_url(self):
view = PasswordResetConfirmView()
self.assertEqual(
str(view.success_url),
reverse("digitalglarus:login"),
)
class MembershipPricingViewTests(TestCase):
@patch(
"digitalglarus.views.MembershipType.objects.last"
)
def test_get_renders_template(self, mock_last):
membership_type = object()
mock_last.return_value = membership_type
response = self.client.get(
reverse("digitalglarus:membership_pricing")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/membership_pricing.html",
)
self.assertEqual(
response.context["membership_type"],
membership_type,
)
class MembershipActivatedViewTests(TestCase):
def test_get_renders_template(self):
session = self.client.session
session["membership_price"] = 100
session["membership_dates"] = "01/01/2026 - 01/31/2026"
session.save()
response = self.client.get(
reverse("digitalglarus:membership_activated")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/membership_activated.html",
)
self.assertEqual(
response.context["membership_price"],
100,
)
self.assertEqual(
response.context["membership_dates"],
"01/01/2026 - 01/31/2026",
)
class ContactViewTests(TestCase):
def test_get_renders_template(self):
response = self.client.get(
reverse("digitalglarus:contact")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"contact.html",
)
def test_get_uses_contact_form(self):
response = self.client.get(
reverse("digitalglarus:contact")
)
self.assertIsInstance(
response.context["form"],
ContactUsForm,
)
def test_form_valid_redirects_to_contact(self):
view = ContactView()
request = RequestFactory().post(
reverse("digitalglarus:contact")
)
view.setup(request)
form = ContactUsForm()
with patch.object(
ContactUsForm,
"is_valid",
return_value=True,
):
response = view.form_valid(form)
self.assertEqual(
response.status_code,
302,
)
self.assertEqual(
response.url,
reverse("digitalglarus:contact"),
)
class BookingSelectDatesViewTests(TestCase):
def test_get_requires_login(self):
response = self.client.get(
reverse("digitalglarus:booking")
)
self.assertEqual(response.status_code, 302)
def test_success_url(self):
view = BookingSelectDatesView()
self.assertEqual(
str(view.success_url),
reverse("digitalglarus:booking_payment"),
)
def test_get_form_kwargs_contains_user(self):
user = CustomUserFactory.create(
email="test@example.com",
password="password123",
)
request = RequestFactory().get(
reverse("digitalglarus:booking")
)
request.user = user
view = BookingSelectDatesView()
view.setup(request)
with patch(
"digitalglarus.views.FormView.get_form_kwargs",
return_value={},
):
kwargs = view.get_form_kwargs()
self.assertEqual(
kwargs["user"],
user,
)
class OldFunctionViewTests(TestCase):
@patch("digitalglarus.views.Post.objects.translated")
def test_blog_renders_template(self, mock_translated):
mock_translated.return_value = []
response = self.client.get(
reverse("digitalglarus:blog")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"glarus_blog/post_list.html",
)
self.assertIn(
"post_list",
response.context,
)
def test_blog_detail_renders_template(self):
post = PostFactory.create()
response = self.client.get(
reverse(
"digitalglarus:blog-detail",
kwargs={"slug": post.slug},
)
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"glarus_blog/post_detail.html",
)
self.assertIn(
"post",
response.context,
)
def test_blog_detail_returns_404_when_post_does_not_exist(self):
with patch(
"digitalglarus.views.Post.objects.translated"
) as mock_translated:
mock_translated.return_value.first.return_value = None
response = self.client.get(
reverse(
"digitalglarus:blog-detail",
kwargs={"slug": "missing-post"},
)
)
self.assertEqual(response.status_code, 404)
def test_support_renders_template(self):
response = self.client.get(
reverse("digitalglarus:support")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"digitalglarus/supportus.html",
)
def test_supporters_renders_template(self):
SupporterFactory()
response = self.client.get(
reverse("digitalglarus:supporters")
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response,
"supporters.html",
)
self.assertIn(
"supporters",
response.context,
)
class BookingPaymentViewTests(TestCase):
def test_get_without_booking_data_redirects_to_booking(self):
response = self.client.get(
reverse("digitalglarus:booking_payment")
)
self.assertRedirects(
response,
reverse("digitalglarus:booking"),
fetch_redirect_response=False,
)
class MembershipDeactivateViewTests(TestCase):
def test_get_requires_login(self):
response = self.client.get(
reverse("digitalglarus:membership_deactivate")
)
self.assertEqual(response.status_code, 302)

View file

@ -64,11 +64,9 @@ class LoginView(LoginViewMixin):
def get_success_url(self):
# redirect to membership orders list if user has at least one.
if self.request.user \
and MembershipOrder.objects.filter(customer__user=self.request.user):
membership_order = MembershipOrder.objects.filter(customer__user=self.request.user)
if self.request.user and membership_order:
return reverse_lazy('digitalglarus:membership_orders_list')
return reverse_lazy('digitalglarus:membership_pricing')

View file

@ -1,4 +1,4 @@
# Generated by Django 6.1.1 on 2026-10-02 08:25
# Generated by Django 6.1.1 on 2026-10-04 11:16
from django.db import migrations, models

View file

@ -4,6 +4,7 @@ from aldryn_apphooks_config.fields import AppHookConfigField
from aldryn_apphooks_config.managers.parler import AppHookConfigTranslatableManager
from cms.models import CMSPlugin
from cms.models.fields import PlaceholderField, PlaceholderRelationField
from cms.utils.placeholder import get_placeholder_from_slot
from django.conf import settings as dj_settings
from django.contrib.auth import get_user_model
from django.contrib.sites.shortcuts import get_current_site
@ -268,9 +269,33 @@ class Post(KnockerModel, BlogMetaMixin, TranslatableModel):
post_text=HTMLField(_("text"), default="", blank=True, configuration="BLOG_POST_TEXT_CKEDITOR"),
meta={"unique_together": (("language_code", "slug"),)},
)
media = PlaceholderRelationField("media", related_name="media")
content = PlaceholderRelationField("post_content", related_name="post_content")
liveblog = PlaceholderRelationField("live_blog", related_name="live_blog")
placeholders = PlaceholderRelationField()
@cached_property
def media(self):
return get_placeholder_from_slot(
self.placeholders,
"media",
)
@cached_property
def content(self):
return get_placeholder_from_slot(
self.placeholders,
"post_content",
)
@cached_property
def liveblog(self):
return get_placeholder_from_slot(
self.placeholders,
"live_blog",
)
enable_liveblog = models.BooleanField(
verbose_name=_("enable liveblog on post"),
default=False,
)
enable_liveblog = models.BooleanField(verbose_name=_("enable liveblog on post"), default=False)
objects = GenericDateTaggedManager()

101
factories.py Normal file
View file

@ -0,0 +1,101 @@
import factory
from django.contrib.sites.models import Site
from django.conf import settings
from datacenterlight.cms_models import CMSIntegration
from digitalglarus.models import BookingPrice, Supporter
from membership.models import CustomUser
from djangocms_blog.models import Post
class SiteFactory(factory.django.DjangoModelFactory):
class Meta:
model = Site
django_get_or_create = ("domain",)
domain = factory.Sequence(lambda n: f"example{n}.test")
name = factory.LazyAttribute(lambda obj: obj.domain)
class CMSIntegrationFactory(factory.django.DjangoModelFactory):
class Meta:
model = CMSIntegration
name = factory.Sequence(lambda n: f"integration-{n}")
domain = factory.SubFactory(SiteFactory)
class SupporterFactory(factory.django.DjangoModelFactory):
class Meta:
model = Supporter
name = factory.Sequence(lambda n: f"Supporter {n}")
class BookingPriceFactory(factory.django.DjangoModelFactory):
class Meta:
model = BookingPrice
price_per_day = 10
special_month_price = 100
class CustomUserFactory(factory.django.DjangoModelFactory):
class Meta:
model = CustomUser
site = factory.LazyFunction(lambda: Site.objects.get(pk=1))
name = factory.Sequence(lambda n: f"Test User {n}")
email = factory.Sequence(lambda n: f"user{n}@example.com")
username = factory.Sequence(lambda n: f"user{n}")
validated = 1
in_ldap = False
is_admin = False
@factory.post_generation
def password(self, create, extracted, **kwargs):
if not create:
return
password = extracted or "testpassword123"
self.set_password(password)
self.save(update_fields=["password"])
class PostFactory(factory.django.DjangoModelFactory):
class Meta:
model = Post
author = factory.SubFactory(CustomUserFactory)
publish = True
include_in_rss = True
enable_comments = False
enable_liveblog = False
@classmethod
def _create(cls, model_class, *args, **kwargs):
language_code = kwargs.pop(
"language_code",
settings.LANGUAGE_CODE,
)
title = kwargs.pop("title", "Test Post")
slug = kwargs.pop("slug", "test-post")
post = model_class(*args, **kwargs)
post.set_current_language(language_code)
post.title = title
post.slug = slug
post.subtitle = ""
post.abstract = ""
post.meta_description = ""
post.meta_keywords = ""
post.meta_title = ""
post.post_text = ""
post.save()
return post

View file

@ -13,6 +13,7 @@ from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import cache_control
from django.views.generic import FormView, CreateView
from django.utils.decorators import method_decorator
from datacenterlight.utils import get_cms_integration
from hosting.forms import UserHostingKeyForm
@ -51,28 +52,40 @@ class LoginViewMixin(FormView):
success_url = None
def get_success_url(self):
next_url = self.request.POST.get('next', self.success_url)
next_url = self.request.POST.get("next", self.success_url)
if not next_url:
return self.success_url
return next_url
def form_valid(self, form):
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
auth_user = authenticate(email=email, password=password)
if auth_user:
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
return HttpResponseRedirect(self.get_success_url())
@cache_control(no_cache=True, must_revalidate=True, no_store=True)
@method_decorator(
cache_control(
no_cache=True,
must_revalidate=True,
no_store=True,
)
)
def get(self, request, *args, **kwargs):
if self.request.user.is_authenticated:
return HttpResponseRedirect(self.get_success_url())
return super(LoginViewMixin, self).get(request, *args, **kwargs)
return super(LoginViewMixin, self).get(
request,
*args,
**kwargs
)
class ResendActivationLinkViewMixin(FormView):

View file

@ -8,7 +8,7 @@ try:
except ImportError:
def python_2_unicode_compatible(cls):
return cls
from django.utils.translation import pgettext_lazy as _
from django.utils.translation import gettext_lazy as _
from .settings import stored_messages_settings