Compare commits

...

9 Commits

Author SHA1 Message Date
caf98ba60b docs: Add two endpoints
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-11-24 11:51:37 +01:00
d7e466050a docs: remove not implemented warning 2024-11-24 11:50:34 +01:00
064a9bf83a feat: Streamline serializer use, check trust level, add log 2024-11-23 14:50:26 +01:00
93070a3bcd refactor: formatting 2024-11-22 21:55:25 +01:00
23c35fe7dd refactor: Naming 2024-11-22 18:50:59 +01:00
d2542060a1 feat: Allow to bulk-activate ANs in the admin interface 2024-11-22 18:50:46 +01:00
89f74cb709 fix: Save date of last checked
Otherwise, ANs will get deactivated in the next night again
2024-11-22 18:50:23 +01:00
ec38012ecb test: fix test by setting date of last checked correctly 2024-11-22 18:49:19 +01:00
72d45a4f47 refactor: typo 2024-11-22 18:48:57 +01:00
7 changed files with 83 additions and 33 deletions

View File

@ -20,11 +20,35 @@ http://notfellchen.org/
Via token
---------
.. warning::
This is currently not supported.
All users are able to generate a token that allows them to use the API. This can be done in the user's profile.
An application can then send this token in the request header for authorization.
.. code-block::
$ curl -X GET http://notfellchen.org/api/adoption_notice -H 'Authorization: Token 49b39856955dc6e5cc04365498d4ad30ea3aed78'
Endpoints
---------
Get Adoption Notices
++++++++++++++++++++
.. code-block::
curl --request GET \
--url http://localhost:8000/api/adoption_notice \
--header 'Authorization: {{token}}'
Create Adoption Notice
++++++++++++++++++++++
.. code-block::
curl --request POST \
--url http://localhost:8000/api/adoption_notice \
--header 'Authorization: {{token}}' \
--header 'content-type: multipart/form-data' \
--form name=TestAdoption1 \
--form searching_since=2024-11-19 \
--form 'description=Lorem ipsum **dolor sit** amet' \
--form further_information=https://notfellchen.org \
--form location_string=Berlin \
--form group_only=true

View File

@ -24,6 +24,13 @@ class AdoptionNoticeAdmin(admin.ModelAdmin):
inlines = [
StatusInline,
]
actions = ("activate",)
def activate(self, request, queryset):
for obj in queryset:
obj.set_active()
activate.short_description = _("Ausgewählte Vermittlungen aktivieren")
# Re-register UserAdmin

View File

@ -7,4 +7,4 @@ from rest_framework import serializers
class AdoptionNoticeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = AdoptionNotice
fields = ['created_at', 'last_checked', "searching_since", "name", "description", "further_information", "group_only"]
fields = ['created_at', 'last_checked', "searching_since", "name", "description", "further_information", "group_only"]

View File

@ -1,9 +1,12 @@
from django.contrib.auth.models import User
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework import permissions
from ..models import AdoptionNotice
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from django.db import transaction
from fellchensammlung.models import AdoptionNotice, Animal, Log, TrustLevel
from fellchensammlung.tasks import add_adoption_notice_location
from .serializers import AdoptionNoticeSerializer
@ -18,20 +21,35 @@ class AdoptionNoticeApiView(APIView):
serializer = AdoptionNoticeSerializer(adoption_notices, many=True, context=serializer_context)
return Response(serializer.data, status=status.HTTP_200_OK)
@transaction.atomic
def post(self, request, *args, **kwargs):
data = {
'name': request.data.get('name'),
"searching_since": request.data.get('searching_since'),
"description": request.data.get('description'),
"organization": request.data.get('organization'),
"further_information": request.data.get('further_information'),
"location_string": request.data.get('location_string'),
"group_only": request.data.get('group_only'),
"owner": request.data.get('owner')
}
serializer = AdoptionNoticeSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
"""
API view to add an adoption notice.b
"""
serializer = AdoptionNoticeSerializer(data=request.data, context={'request': request})
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
adoption_notice = serializer.save(owner=request.user)
# Add the location
add_adoption_notice_location.delay_on_commit(adoption_notice.pk)
# Only set active when user has trust level moderator or higher
if request.user.trust_level >= TrustLevel.MODERATOR:
adoption_notice.set_active()
else:
adoption_notice.set_unchecked()
# Log the action
Log.objects.create(
user=request.user,
action="add_adoption_notice",
text=f"{request.user} added adoption notice {adoption_notice.pk} via API",
)
# Return success response with new adoption notice details
return Response(
{"message": "Adoption notice created successfully!", "id": adoption_notice.pk},
status=status.HTTP_201_CREATED,
)

View File

@ -350,22 +350,22 @@ class AdoptionNotice(models.Model):
def set_closed(self):
self.last_checked = timezone.now()
self.adoptionnoticestatus.set_closed()
self.save()
self.adoptionnoticestatus.set_closed()
def set_active(self):
self.last_checked = timezone.now()
self.save()
if not hasattr(self, 'adoptionnoticestatus'):
AdoptionNoticeStatus.create_other(self)
self.adoptionnoticestatus.set_active()
self.save()
def set_unchecked(self):
self.last_checked = timezone.now()
self.save()
if not hasattr(self, 'adoptionnoticestatus'):
AdoptionNoticeStatus.create_other(self)
self.adoptionnoticestatus.set_unchecked()
self.save()
for subscription in self.get_subscriptions():
notification_title = _("Vermittlung deaktiviert:") + f" {self}"

View File

@ -53,11 +53,11 @@ def clean_locations(quiet=True):
def get_unchecked_adoption_notices(weeks=3):
now = timezone.now()
three_weeks_ago = now - timedelta(weeks=weeks)
n_weeks_ago = now - timedelta(weeks=weeks)
# Query for active adoption notices that were checked in the last three weeks
# Query for active adoption notices that were not checked in the last n weeks
unchecked_adoptions = AdoptionNotice.objects.filter(
last_checked__lte=three_weeks_ago
last_checked__lte=n_weeks_ago
)
active_unchecked_adoptions = [adoption for adoption in unchecked_adoptions if adoption.is_active]
return active_unchecked_adoptions
@ -71,7 +71,7 @@ def get_active_adoption_notices():
def deactivate_unchecked_adoption_notices():
for adoption_notice in get_unchecked_adoption_notices(weeks=3):
AdoptionNoticeStatus.objects.get(adoption_notice=adoption_notice).set_unchecked()
adoption_notice.set_unchecked()
def deactivate_404_adoption_notices():

View File

@ -10,7 +10,7 @@ from model_bakery import baker
from fellchensammlung.models import AdoptionNotice
class DeactiviationTest(TestCase):
class DeactivationTest(TestCase):
@classmethod
def setUpTestData(cls):
now = timezone.now()
@ -19,16 +19,18 @@ class DeactiviationTest(TestCase):
cls.adoption1 = baker.make(AdoptionNotice,
name="TestAdoption1",
created_at=more_than_three_weeks_ago,
last_checked=more_than_three_weeks_ago)
created_at=more_than_three_weeks_ago)
cls.adoption2 = baker.make(AdoptionNotice, name="TestAdoption2")
cls.adoption3 = baker.make(AdoptionNotice,
name="TestAdoption3",
created_at=less_than_three_weeks_ago,
last_checked=less_than_three_weeks_ago)
created_at=less_than_three_weeks_ago)
cls.adoption1.set_active()
cls.adoption1.last_checked = more_than_three_weeks_ago # Reset updated_at to simulate test conditions
cls.adoption1.save()
cls.adoption3.set_active()
cls.adoption3.last_checked = less_than_three_weeks_ago # Reset updated_at to simulate test conditions
cls.adoption3.save()
def test_get_unchecked_adoption_notices(self):
result = get_unchecked_adoption_notices()
@ -94,4 +96,3 @@ class PingTest(TestCase):
self.adoption2.refresh_from_db()
self.assertTrue(self.adoption1.is_active)
self.assertFalse(self.adoption2.is_active)