Skip to content

Commit

Permalink
Merge pull request #3018 from digitalfabrik/develop
Browse files Browse the repository at this point in the history
Release `2024.8.2`
  • Loading branch information
PeterNerlich authored Aug 29, 2024
2 parents ad8c5e8 + 5c4eb16 commit 567a1f2
Show file tree
Hide file tree
Showing 64 changed files with 1,585 additions and 194 deletions.
9 changes: 6 additions & 3 deletions integreat_cms/api/v3/chat/zammad_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,17 @@ def _transform_attachment(
# pylint: disable=method-hidden
def get_messages(self, chat: UserChat) -> dict[str, dict | list[dict]]:
"""
Get all messages for a given ticket
Get all non-internal messages for a given ticket
:param chat: UserChat instance for the relevant Zammad ticket
"""
raw_response = self._attempt_call(self.client.ticket.articles, chat.zammad_id)
if not isinstance(raw_response, list):
return self._parse_response(raw_response) # type: ignore[return-value]

response = self._parse_response(
self._attempt_call(self.client.ticket.articles, chat.zammad_id)
[article for article in raw_response if not article.get("internal")]
)

for message in response:
if "attachments" in message:
message["attachments"] = [
Expand Down
3 changes: 3 additions & 0 deletions integreat_cms/cms/constants/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@
"delete_user",
"grant_page_permissions",
"manage_translations",
"change_contact",
"delete_contact",
"view_contact",
]

#: The permissions of the cms team
Expand Down
9 changes: 9 additions & 0 deletions integreat_cms/cms/constants/weeks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@
(FOURTH, _("Fourth week")),
(LAST, _("Last week")),
]

#: A mapping from our week constants to the expected rrule values
WEEK_TO_RRULE_WEEK = {
FIRST: 1,
SECOND: 2,
THIRD: 3,
FOURTH: 4,
LAST: -1,
}
30 changes: 30 additions & 0 deletions integreat_cms/cms/fixtures/test_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -5779,5 +5779,35 @@
"poi": 4,
"meta_description": "Meta description of the test location"
}
},
{
"model": "cms.contact",
"pk": 1,
"fields": {
"title": "Integrationsbeauftragte",
"name": "Martina Musterfrau",
"poi": 6,
"email": "[email protected]",
"phone_number": "0123456789",
"website": "",
"archived": false,
"created_date": "2024-08-06T13:23:45.256Z",
"last_updated": "2024-08-06T13:23:45.256Z"
}
},
{
"model": "cms.contact",
"pk": 2,
"fields": {
"title": "Integrationsberaterin",
"name": "Martina Musterfrau",
"poi": 6,
"email": "[email protected]",
"phone_number": "0987654321",
"website": "www.random-page.com",
"archived": true,
"created_date": "2024-08-06T13:23:45.256Z",
"last_updated": "2024-08-06T13:23:45.256Z"
}
}
]
112 changes: 112 additions & 0 deletions integreat_cms/cms/migrations/0098_add_contact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import django.db.models.deletion
import django.utils.timezone
from django.apps.registry import Apps
from django.core.management.sql import emit_post_migrate_signal
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor

from integreat_cms.cms.constants import roles


# pylint: disable=unused-argument
def update_roles(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None:
"""
Add permissions for managing external calendars
:param apps: The configuration of installed applications
:param schema_editor: The database abstraction layer that creates actual SQL code
"""
Group = apps.get_model("auth", "Group")
Permission = apps.get_model("auth", "Permission")

# Emit post-migrate signal to make sure the Permission objects are created before they can be assigned
emit_post_migrate_signal(2, False, "default")

# Clear and update permissions according to new constants
for role_name in dict(roles.CHOICES):
group, _ = Group.objects.get_or_create(name=role_name)
# Clear permissions
group.permissions.clear()
# Set permissions
group.permissions.add(
*Permission.objects.filter(codename__in=roles.PERMISSIONS[role_name])
)


class Migration(migrations.Migration):
"""
Initial migration file for contact
"""

dependencies = [
("cms", "0097_alter_pushnotificationtranslation_text"),
]

operations = [
migrations.CreateModel(
name="Contact",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=200, verbose_name="title")),
("name", models.CharField(max_length=200, verbose_name="name")),
(
"email",
models.EmailField(
blank=True, max_length=254, verbose_name="email address"
),
),
(
"phone_number",
models.CharField(
blank=True, max_length=250, verbose_name="phone number"
),
),
(
"website",
models.URLField(blank=True, max_length=250, verbose_name="website"),
),
(
"archived",
models.BooleanField(
default=False,
help_text="Whether or not the location is read-only and hidden in the API.",
verbose_name="archived",
),
),
(
"last_updated",
models.DateTimeField(
auto_now=True, verbose_name="modification date"
),
),
(
"created_date",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="creation date"
),
),
(
"poi",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="cms.poi",
verbose_name="POI",
),
),
],
options={
"verbose_name": "contact",
"verbose_name_plural": "contacts",
"ordering": ["name"],
"default_permissions": ("change", "delete", "view"),
"default_related_name": "contact",
},
),
]
35 changes: 35 additions & 0 deletions integreat_cms/cms/migrations/0099_firebasestatistic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from django.db import migrations, models


class Migration(migrations.Migration):
"""
Create FirebaseStatistic model
"""

dependencies = [
("cms", "0098_add_contact"),
]

operations = [
migrations.CreateModel(
name="FirebaseStatistic",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateField()),
("region", models.CharField(max_length=100)),
("language_slug", models.CharField(max_length=2)),
("count", models.IntegerField()),
],
options={
"abstract": False,
},
),
]
3 changes: 3 additions & 0 deletions integreat_cms/cms/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@

from __future__ import annotations

from integreat_cms.cms.models.firebase.firebase_statistic import FirebaseStatistic

from .chat.attachment_map import AttachmentMap
from .chat.chat_message import ChatMessage
from .chat.user_chat import ABTester, UserChat
from .contact.contact import Contact
from .events.event import Event
from .events.event_translation import EventTranslation
from .events.recurrence_rule import RecurrenceRule
Expand Down
7 changes: 5 additions & 2 deletions integreat_cms/cms/models/abstract_content_translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,14 @@ def is_outdated(self) -> bool:
def is_up_to_date(self) -> bool:
"""
This property checks whether a translation is up to date.
A translation is considered up to date when it is not outdated and not being translated at the moment.
A translation is considered up to date when it is either explicitly set to up-to-date, or has been machine-translated.
:return: Flag which indicates whether a translation is up to date
"""
return self.translation_state == translation_status.UP_TO_DATE
return self.translation_state in [
translation_status.UP_TO_DATE,
translation_status.MACHINE_TRANSLATED,
]

@cached_property
def translation_state(self) -> str:
Expand Down
14 changes: 5 additions & 9 deletions integreat_cms/cms/models/abstract_tree_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from treebeard.ns_tree import NS_Node, NS_NodeManager

if TYPE_CHECKING:
from typing import Any
from typing import Any, Self

from treebeard.ns_tree import NS_NodeQuerySet

Expand Down Expand Up @@ -193,9 +193,7 @@ def next_region_sibling(self) -> AbstractTreeNode | None:
return siblings[idx + 1]
return None

def get_cached_ancestors(
self, include_self: bool = False
) -> list[AbstractTreeNode]:
def get_cached_ancestors(self, include_self: bool = False) -> list[Self]:
"""
Get the cached ancestors of a specific node
Expand All @@ -210,7 +208,7 @@ def get_cached_ancestors(
return self._cached_ancestors

@cached_property
def cached_parent(self) -> AbstractTreeNode | None:
def cached_parent(self) -> Self | None:
"""
Get the parent node of the current node object.
Caches the result in the object itself to help in loops.
Expand All @@ -221,9 +219,7 @@ def cached_parent(self) -> AbstractTreeNode | None:
return None
return self.get_cached_ancestors()[-1]

def get_cached_descendants(
self, include_self: bool = False
) -> list[AbstractTreeNode]:
def get_cached_descendants(self, include_self: bool = False) -> list[Self]:
"""
Get the cached descendants of a specific node
Expand All @@ -238,7 +234,7 @@ def get_cached_descendants(
return self._cached_descendants

@cached_property
def cached_children(self) -> list[AbstractTreeNode]:
def cached_children(self) -> list[Self]:
"""
Get all cached children
Expand Down
72 changes: 72 additions & 0 deletions integreat_cms/cms/models/contact/contact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from django.db import models
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _

from ..abstract_base_model import AbstractBaseModel
from ..pois.poi import POI
from ..regions.region import Region


class Contact(AbstractBaseModel):
"""
Data model representing a contact
"""

title = models.CharField(max_length=200, verbose_name=_("title"))
name = models.CharField(max_length=200, verbose_name=_("name"))
poi = models.ForeignKey(POI, on_delete=models.PROTECT, verbose_name=_("POI"))
email = models.EmailField(
blank=True,
verbose_name=_("email address"),
)
phone_number = models.CharField(
max_length=250, blank=True, verbose_name=_("phone number")
)
website = models.URLField(blank=True, max_length=250, verbose_name=_("website"))
archived = models.BooleanField(
default=False,
verbose_name=_("archived"),
help_text=_("Whether or not the location is read-only and hidden in the API."),
)
last_updated = models.DateTimeField(
auto_now=True,
verbose_name=_("modification date"),
)
created_date = models.DateTimeField(
default=timezone.now, verbose_name=_("creation date")
)

@cached_property
def region(self) -> Region:
"""
Returns the region this contact belongs to
:return: Region this contact belongs to
"""
return self.poi.region

def __str__(self) -> str:
"""
This overwrites the default Django :meth:`~django.db.models.Model.__str__` method which would return ``Contact object (id)``.
It is used in the Django admin backend and as label for ModelChoiceFields.
:return: A readable string representation of the contact
"""
return f"{self.title} {self.name}"

def get_repr(self) -> str:
"""
This overwrites the default Django ``__repr__()`` method which would return ``<Contact: Contact object (id)>``.
It is used for logging.
:return: The canonical string representation of the contact
"""
return f"<Contact (id: {self.id}, title: {self.title}, name: {self.name}, region: {self.region.slug})>"

class Meta:
verbose_name = _("contact")
default_related_name = "contact"
verbose_name_plural = _("contacts")
default_permissions = ("change", "delete", "view")
ordering = ["name"]
Loading

0 comments on commit 567a1f2

Please sign in to comment.