Skip to content

Commit

Permalink
✨ split up FoiMessage and FoiMessageDraft
Browse files Browse the repository at this point in the history
  • Loading branch information
krmax44 committed Dec 13, 2024
1 parent 00f8952 commit 8431713
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 72 deletions.
22 changes: 19 additions & 3 deletions froide/foirequest/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from froide.account.models import UserTag
from froide.comments.models import FroideComment
from froide.foirequest.models.message import FoiMessageDraft
from froide.guide.models import Action
from froide.guide.utils import assign_guidance_action
from froide.helper.admin_utils import (
Expand Down Expand Up @@ -521,8 +522,7 @@ class MessageTagsFilter(MultiFilterMixin, TaggitListFilter):
@admin.register(FoiMessage)
class FoiMessageAdmin(admin.ModelAdmin):
save_on_top = True
list_display = (
"is_draft",
list_display = [
"subject",
"timestamp",
"message_page",
Expand All @@ -532,7 +532,7 @@ class FoiMessageAdmin(admin.ModelAdmin):
"registered_mail_date",
"kind",
"get_deliverystatus_display",
)
]
list_filter = (
"kind",
"is_response",
Expand Down Expand Up @@ -752,6 +752,22 @@ def add_comment(
)


@admin.register(FoiMessageDraft)
class FoiMessageDraftAdmin(FoiMessageAdmin):
list_display = ("pk", "request_page", "timestamp", "kind", "user")

def request_page(self, obj):
return format_html(
'<a href="{}">{}</a>', obj.request.get_absolute_short_url(), _("on site")
)

def user(self, obj):
return obj.request.user

def get_queryset(self, request):
return super().get_queryset(request).prefetch_related("deliverystatus")


@admin.register(MessageTag)
class MessageTagAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("name",)}
Expand Down
54 changes: 48 additions & 6 deletions froide/foirequest/api_views/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

from django_filters import rest_framework as filters
from rest_framework import permissions, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import mixins

from froide.foirequest.models.message import FoiMessageDraft

from ..auth import (
get_read_foimessage_queryset,
Expand All @@ -11,21 +16,48 @@
OnlyEditableWhenDraftPermission,
WriteFoiRequestPermission,
)
from ..serializers import FoiMessageSerializer, optimize_message_queryset
from ..serializers import (
FoiMessageDraftSerializer,
FoiMessageSerializer,
optimize_message_queryset,
)

User = get_user_model()


class FoiMessageFilter(filters.FilterSet):
class Meta:
model = FoiMessage
fields = ("request", "kind", "is_response", "is_draft")
fields = ("request", "kind", "is_response")


class FoiMessageDraftFilter(filters.FilterSet):
class Meta:
model = FoiMessageDraft
fields = ("request",)


class FoiMessageViewSet(viewsets.ModelViewSet):
class FoiMessageViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = FoiMessageSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = FoiMessageFilter

def get_queryset(self):
qs = get_read_foimessage_queryset(self.request).order_by()
return self.optimize_query(qs)

def optimize_query(self, qs):
return optimize_message_queryset(self.request, qs)


class FoiMessageDraftViewSet(
FoiMessageViewSet,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
):
serializer_class = FoiMessageDraftSerializer
filterset_class = FoiMessageDraftFilter
required_scopes = ["make:message"]
permission_classes = [
permissions.IsAuthenticatedOrReadOnly,
Expand All @@ -34,8 +66,18 @@ class FoiMessageViewSet(viewsets.ModelViewSet):
]

def get_queryset(self):
qs = get_read_foimessage_queryset(self.request).order_by()
qs = get_read_foimessage_queryset(
self.request, queryset=FoiMessageDraft.objects.all()
).order_by()
return self.optimize_query(qs)

def optimize_query(self, qs):
return optimize_message_queryset(self.request, qs)
@action(detail=True, methods=["post"])
def publish(self, request, pk=None):
message = self.get_object()
message.is_draft = False
message.save()

serializer = FoiMessageSerializer(
message, context=self.get_serializer_context()
)
return Response(serializer.data)
8 changes: 7 additions & 1 deletion froide/foirequest/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ def ready(self):
from froide.api import api_router
from froide.foirequest import signals # noqa
from froide.foirequest.api_views.attachment import FoiAttachmentViewSet
from froide.foirequest.api_views.message import FoiMessageViewSet
from froide.foirequest.api_views.message import (
FoiMessageViewSet,
FoiMessageDraftViewSet,
)
from froide.foirequest.api_views.request import FoiRequestViewSet
from froide.helper.search import search_registry
from froide.team import team_changed
Expand All @@ -48,6 +51,9 @@ def ready(self):
account_confirmed.connect(send_request_when_account_confirmed)

api_router.register(r"request", FoiRequestViewSet, basename="request")
api_router.register(
r"message/draft", FoiMessageDraftViewSet, basename="message-draft"
)
api_router.register(r"message", FoiMessageViewSet, basename="message")
api_router.register(r"attachment", FoiAttachmentViewSet, basename="attachment")

Expand Down
9 changes: 8 additions & 1 deletion froide/foirequest/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from .attachment import FoiAttachment
from .deferred import DeferredMessage
from .draft import RequestDraft
from .message import DeliveryStatus, FoiMessage, MessageTag, TaggedMessage
from .message import (
DeliveryStatus,
FoiMessage,
FoiMessageDraft,
MessageTag,
TaggedMessage,
)
from .project import FoiProject
from .request import FoiRequest, TaggedFoiRequest
from .suggestion import PublicBodySuggestion
Expand All @@ -12,6 +18,7 @@
"FoiRequest",
"TaggedFoiRequest",
"FoiMessage",
"FoiMessageDraft",
"FoiAttachment",
"FoiEvent",
"DeferredMessage",
Expand Down
23 changes: 21 additions & 2 deletions froide/foirequest/models/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,18 @@ def get_throttle_filter(self, queryset, user, extra_filters=None):
qs = qs.filter(**extra_filters)
return qs, "timestamp"

def get_drafts(self, drafts=True):
return super().get_queryset().filter(is_draft=drafts)
def get_queryset(self):
return super().get_queryset().filter(is_draft=False)


class FoiMessageDraftManager(FoiMessageManager):
def get_queryset(self):
# need to call models.Manager, since FoiMessageManager removes drafts
return super(models.Manager, self).get_queryset().filter(is_draft=True)

def create(self, **kwargs):
kwargs.setdefault("is_draft", True)
return super().create(**kwargs)


class MessageTag(TagBase):
Expand Down Expand Up @@ -746,6 +756,15 @@ def set_cached_rendered_content(self, authenticated_read, content):
FoiMessage.objects.filter(id=self.id).update(**update)


class FoiMessageDraft(FoiMessage):
objects = FoiMessageDraftManager()

class Meta:
proxy = True
verbose_name = _("Freedom of Information Message Draft")
verbose_name_plural = _("Freedom of Information Message Drafts")


class Delivery(models.TextChoices):
STATUS_UNKNOWN = ("unknown", _("unknown"))
STATUS_SENDING = ("sending", _("sending"))
Expand Down
44 changes: 38 additions & 6 deletions froide/foirequest/serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.db.models import Prefetch
from django.template.defaultfilters import default
from django.utils import timezone
from django.utils.translation import gettext as _

Expand All @@ -7,7 +8,11 @@

from froide.document.api_views import DocumentSerializer
from froide.foirequest.forms.message import TransferUploadForm
from froide.foirequest.models.message import MESSAGE_KIND_USER_ALLOWED, MessageKind
from froide.foirequest.models.message import (
MESSAGE_KIND_USER_ALLOWED,
FoiMessageDraft,
MessageKind,
)
from froide.helper.text_diff import get_differences
from froide.publicbody.models import PublicBody
from froide.publicbody.serializers import (
Expand Down Expand Up @@ -175,6 +180,26 @@ def get_queryset(self):
return get_write_foirequest_queryset(request)


class FoiMessageRelatedField(serializers.HyperlinkedRelatedField):
def __init__(self, **kwargs):
super().__init__("api:message-detail", **kwargs)

def get_url(self, obj, view_name, request, format):
# Unsaved objects will not yet have a valid URL.
if hasattr(obj, "pk") and obj.pk in (None, ""):
return None

lookup_value = getattr(obj, self.lookup_field)
kwargs = {self.lookup_url_kwarg: lookup_value}

if isinstance(obj, FoiMessageDraft):
view_name = "api:message-draft-detail"
else:
view_name = "api:message-detail"

return self.reverse(view_name, kwargs=kwargs, request=request, format=format)


class FoiMessageSerializer(serializers.HyperlinkedModelSerializer):
resource_uri = serializers.HyperlinkedIdentityField(view_name="api:message-detail")
request = FoiRequestRelatedField()
Expand All @@ -193,8 +218,8 @@ class FoiMessageSerializer(serializers.HyperlinkedModelSerializer):
sender = serializers.CharField(read_only=True)
url = serializers.CharField(source="get_absolute_domain_url", read_only=True)
status = serializers.ChoiceField(choices=FoiRequest.STATUS.choices, required=False)
kind = serializers.ChoiceField(choices=MessageKind.choices, required=True)
is_draft = serializers.BooleanField(required=False)
kind = serializers.ChoiceField(choices=MessageKind.choices, default="post")
is_draft = serializers.BooleanField(read_only=True)
status_name = serializers.CharField(source="get_status_display", read_only=True)
not_publishable = serializers.BooleanField(read_only=True)
timestamp = serializers.DateTimeField(default=timezone.now)
Expand Down Expand Up @@ -289,6 +314,15 @@ def validate_request(self, value):
return value


class FoiMessageDraftSerializer(FoiMessageSerializer):
resource_uri = serializers.HyperlinkedIdentityField(
view_name="api:message-draft-detail"
)

class Meta(FoiMessageSerializer.Meta):
model = FoiMessageDraft


class FoiAttachmentSerializer(serializers.HyperlinkedModelSerializer):
resource_uri = serializers.HyperlinkedIdentityField(
view_name="api:attachment-detail", lookup_field="pk"
Expand All @@ -303,9 +337,7 @@ class FoiAttachmentSerializer(serializers.HyperlinkedModelSerializer):
lookup_field="pk",
read_only=True,
)
belongs_to = serializers.HyperlinkedRelatedField(
read_only=True, view_name="api:message-detail"
)
belongs_to = FoiMessageRelatedField(read_only=True)
document = DocumentSerializer()
site_url = serializers.CharField(source="get_absolute_domain_url", read_only=True)
anchor_url = serializers.CharField(source="get_domain_anchor_url", read_only=True)
Expand Down
6 changes: 3 additions & 3 deletions froide/foirequest/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,10 @@ def unpack_zipfile_attachment_task(instance_id):

@celery_app.task(name="froide.foirequest.tasks.remove_old_drafts", time_limit=10)
def remove_old_drafts():
from .models import FoiMessage
from .models import FoiMessageDraft

FoiMessage.objects.filter(
is_draft=True, last_modified_at__lt=timezone.now() - timedelta(days=30)
FoiMessageDraft.objects.filter(
last_modified_at__lt=timezone.now() - timedelta(days=30)
).delete()


Expand Down
Loading

0 comments on commit 8431713

Please sign in to comment.