Compare commits

5 Commits

Author SHA1 Message Date
9e5446ff1d feat: Test adding a adoption as user 2025-01-18 15:22:08 +01:00
3b79809b8c docs: various 2025-01-18 09:07:33 +01:00
53e6db3655 refactor: Remove print 2025-01-14 07:31:00 +01:00
424f91e919 feat: Add a timestamp for when a notification is read 2025-01-14 07:30:36 +01:00
84ce5f54b2 refactor: Remove unnecessary print 2025-01-14 07:27:03 +01:00
11 changed files with 102 additions and 15 deletions

View File

@@ -36,6 +36,11 @@ An application can then send this token in the request header for authorization.
Endpoints
---------
All Endpoints are documented at https://notfellchen.org/api/schema/swagger-ui/ or at https://notfellchen.org/api/schema/redoc/ if you prefer redoc.
The OpenAI schema can be downloaded at https://notfellchen.org/api/schema/
Examples are documented here.
Get Adoption Notices
++++++++++++++++++++

View File

@@ -5,7 +5,7 @@ Report a bug
^^^^^^^^^^^^
To report a bug, file an issue on `Github
<https://codeberg.org/moanos/notfellchen/issues>`_
<https://github.com/moan0s/notfellchen/issues>`_
Try to include the following information:
@@ -29,7 +29,7 @@ To contribute simply clone the directory, make your changes and file a
pull request.
If you want to know what can be done, have a look at the current `Github
<https://codeberg.org/moanos/notfellchen/issues>`_.
<https://github.com/moan0s/notfellchen/issues>`_.
Get in touch!
^^^^^^^^^^^^^

View File

@@ -5,8 +5,7 @@ What qualifies as release?
^^^^^^^^^^^^^^^^^^^^^^^^^^
A new release should be announced when a significant number functions, bugfixes or other improvements to the software
is made. Usually this indicates a minor release.
Major releases are yet to be determined.
is made. Notfellchen follows `Semantic Versioning <https://semver.org/>`_.
What should be done before a release?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,7 +13,7 @@ What should be done before a release?
Tested basic functions
######################
Run :command:`pytest`
Run :command:`nf test src`
Test upgrade on a copy of a production database
###############################################
@@ -38,4 +37,4 @@ Do a final commit on this change, and tag the commit as release with appropriate
git tag -a v1.0.0 -m "Releasing version v1.0.0"
git push origin v1.0.0
Make sure the tag is visible on Codeberg and celebrate 🥳
Make sure the tag is visible on GitHub/Codeberg and celebrate 🥳

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2025-01-14 06:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0035_alter_image_alt_text_and_more'),
]
operations = [
migrations.AddField(
model_name='basenotification',
name='read_at',
field=models.DateTimeField(blank=True, null=True, verbose_name='Gelesen am'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2025-01-14 06:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0036_basenotification_read_at'),
]
operations = [
migrations.AlterField(
model_name='basenotification',
name='title',
field=models.CharField(max_length=100, verbose_name='Titel'),
),
]

View File

@@ -818,7 +818,8 @@ class Comment(models.Model):
class BaseNotification(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=100)
read_at = models.DateTimeField(blank=True, null=True, verbose_name=_("Gelesen am"))
title = models.CharField(max_length=100, verbose_name=_("Titel"))
text = models.TextField(verbose_name="Inhalt")
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_('Nutzer*in'))
read = models.BooleanField(default=False)
@@ -829,6 +830,11 @@ class BaseNotification(models.Model):
def get_absolute_url(self):
self.user.get_notifications_url()
def mark_read(self):
self.read = True
self.read_at = timezone.now()
self.save()
class CommentNotification(BaseNotification):
comment = models.ForeignKey(Comment, on_delete=models.CASCADE, verbose_name=_('Antwort'))

View File

@@ -137,7 +137,6 @@ class GeoAPI:
result = self.requests.get(self.api_url,
{"q": location_string, "lang": language},
headers=self.headers).json()
logging.warning(result)
geofeatures = GeoFeature.geofeatures_from_photon_result(result)
else:
raise NotImplementedError

View File

@@ -481,13 +481,11 @@ def my_profile(request):
notification = CommentNotification.objects.get(pk=notification_id)
except CommentNotification.DoesNotExist:
notification = BaseNotification.objects.get(pk=notification_id)
notification.read = True
notification.save()
notification.mark_read()
elif action == "notification_mark_all_read":
notifications = CommentNotification.objects.filter(user=request.user, mark_read=False)
for notification in notifications:
notification.read = True
notification.save()
notification.mark_read()
elif action == "search_subscription_delete":
search_subscription_id = request.POST.get("search_subscription_id")
SearchSubscription.objects.get(pk=search_subscription_id).delete()

View File

@@ -27,7 +27,6 @@ class DistanceTest(TestCase):
l_stuttgart = LocationProxy("Stuttgart")
l_tue = LocationProxy("Tübingen")
# Should be 30km
print(f"{l_stuttgart.position} -> {l_tue.position}")
distance_tue_stuttgart = calculate_distance_between_coordinates(l_stuttgart.position, l_tue.position)
self.assertLess(distance_tue_stuttgart, 50)
self.assertGreater(distance_tue_stuttgart, 20)

View File

@@ -4,7 +4,7 @@ from django.utils import timezone
from django.test import TestCase
from model_bakery import baker
from fellchensammlung.models import Announcement, Language, User, TrustLevel
from fellchensammlung.models import Announcement, Language, User, TrustLevel, BaseNotification
class UserTest(TestCase):
@@ -77,3 +77,21 @@ class AnnouncementTest(TestCase):
self.assertTrue(self.announcement2 not in active_announcements)
self.assertTrue(self.announcement4 not in active_announcements)
self.assertTrue(self.announcement5 in active_announcements)
class TestNotifications(TestCase):
@classmethod
def setUpTestData(cls):
cls.test_user_1 = User.objects.create(username="Testuser1", password="SUPERSECRET", email="test@example.org")
def test_mark_read(self):
not1 = BaseNotification.objects.create(user=self.test_user_1, text="New rats to adopt", title="🔔 New Rat alert")
not2 = BaseNotification.objects.create(user=self.test_user_1,
text="New wombat to adopt", title="🔔 New Wombat alert")
not1.mark_read()
self.assertTrue(not1.read)
self.assertFalse(not2.read)
self.assertTrue((timezone.now() - timedelta(hours=1)) < not1.read_at < timezone.now())
self.assertIsNone(not2.read_at)

View File

@@ -4,7 +4,7 @@ from django.urls import reverse
from model_bakery import baker
from fellchensammlung.models import Animal, Species, AdoptionNotice, User, Location, AdoptionNoticeStatus, TrustLevel
from fellchensammlung.models import Animal, Species, AdoptionNotice, User, Location, AdoptionNoticeStatus, TrustLevel, Animal
from fellchensammlung.views import add_adoption_notice
@@ -70,6 +70,33 @@ class AnimalAndAdoptionTest(TestCase):
self.assertTrue(response.status_code < 400)
self.assertTrue(AdoptionNotice.objects.get(name="TestAdoption4").is_active)
an = AdoptionNotice.objects.get(name="TestAdoption4")
animals = Animal.objects.filter(adoption_notice=an)
self.assertTrue(len(animals) == 2)
def test_creating_AN_as_user(self):
self.client.login(username='testuser1', password='12345')
form_data = {"name": "TestAdoption5",
"species": Species.objects.first().pk,
"num_animals": "3",
"date_of_birth": "2024-12-04",
"sex": "M",
"group_only": "on",
"searching_since": "2024-11-10",
"location_string": "München",
"description": "Blaaaa",
"further_information": "https://notfellchen.org/",
"save-and-add-another-animal": "Speichern"}
response = self.client.post(reverse('add-adoption'), data=form_data)
self.assertTrue(response.status_code < 400)
self.assertFalse(AdoptionNotice.objects.get(name="TestAdoption5").is_active)
an = AdoptionNotice.objects.get(name="TestAdoption5")
animals = Animal.objects.filter(adoption_notice=an)
self.assertTrue(len(animals) == 3)
self.assertTrue(an.sexes == set("M",))