Compare commits
5 Commits
main
...
9e5446ff1d
Author | SHA1 | Date | |
---|---|---|---|
9e5446ff1d | |||
3b79809b8c | |||
53e6db3655 | |||
424f91e919 | |||
84ce5f54b2 |
@@ -36,6 +36,11 @@ An application can then send this token in the request header for authorization.
|
|||||||
Endpoints
|
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
|
Get Adoption Notices
|
||||||
++++++++++++++++++++
|
++++++++++++++++++++
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ Report a bug
|
|||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
To report a bug, file an issue on `Github
|
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:
|
Try to include the following information:
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ To contribute simply clone the directory, make your changes and file a
|
|||||||
pull request.
|
pull request.
|
||||||
|
|
||||||
If you want to know what can be done, have a look at the current `Github
|
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!
|
Get in touch!
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
@@ -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
|
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.
|
is made. Notfellchen follows `Semantic Versioning <https://semver.org/>`_.
|
||||||
Major releases are yet to be determined.
|
|
||||||
|
|
||||||
What should be done before a release?
|
What should be done before a release?
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@@ -14,7 +13,7 @@ What should be done before a release?
|
|||||||
Tested basic functions
|
Tested basic functions
|
||||||
######################
|
######################
|
||||||
|
|
||||||
Run :command:`pytest`
|
Run :command:`nf test src`
|
||||||
|
|
||||||
Test upgrade on a copy of a production database
|
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 tag -a v1.0.0 -m "Releasing version v1.0.0"
|
||||||
git push origin 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 🥳
|
||||||
|
@@ -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'),
|
||||||
|
),
|
||||||
|
]
|
@@ -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'),
|
||||||
|
),
|
||||||
|
]
|
@@ -818,7 +818,8 @@ class Comment(models.Model):
|
|||||||
class BaseNotification(models.Model):
|
class BaseNotification(models.Model):
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
updated_at = models.DateTimeField(auto_now=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")
|
text = models.TextField(verbose_name="Inhalt")
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_('Nutzer*in'))
|
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_('Nutzer*in'))
|
||||||
read = models.BooleanField(default=False)
|
read = models.BooleanField(default=False)
|
||||||
@@ -829,6 +830,11 @@ class BaseNotification(models.Model):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
self.user.get_notifications_url()
|
self.user.get_notifications_url()
|
||||||
|
|
||||||
|
def mark_read(self):
|
||||||
|
self.read = True
|
||||||
|
self.read_at = timezone.now()
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
class CommentNotification(BaseNotification):
|
class CommentNotification(BaseNotification):
|
||||||
comment = models.ForeignKey(Comment, on_delete=models.CASCADE, verbose_name=_('Antwort'))
|
comment = models.ForeignKey(Comment, on_delete=models.CASCADE, verbose_name=_('Antwort'))
|
||||||
|
@@ -137,7 +137,6 @@ class GeoAPI:
|
|||||||
result = self.requests.get(self.api_url,
|
result = self.requests.get(self.api_url,
|
||||||
{"q": location_string, "lang": language},
|
{"q": location_string, "lang": language},
|
||||||
headers=self.headers).json()
|
headers=self.headers).json()
|
||||||
logging.warning(result)
|
|
||||||
geofeatures = GeoFeature.geofeatures_from_photon_result(result)
|
geofeatures = GeoFeature.geofeatures_from_photon_result(result)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@@ -481,13 +481,11 @@ def my_profile(request):
|
|||||||
notification = CommentNotification.objects.get(pk=notification_id)
|
notification = CommentNotification.objects.get(pk=notification_id)
|
||||||
except CommentNotification.DoesNotExist:
|
except CommentNotification.DoesNotExist:
|
||||||
notification = BaseNotification.objects.get(pk=notification_id)
|
notification = BaseNotification.objects.get(pk=notification_id)
|
||||||
notification.read = True
|
notification.mark_read()
|
||||||
notification.save()
|
|
||||||
elif action == "notification_mark_all_read":
|
elif action == "notification_mark_all_read":
|
||||||
notifications = CommentNotification.objects.filter(user=request.user, mark_read=False)
|
notifications = CommentNotification.objects.filter(user=request.user, mark_read=False)
|
||||||
for notification in notifications:
|
for notification in notifications:
|
||||||
notification.read = True
|
notification.mark_read()
|
||||||
notification.save()
|
|
||||||
elif action == "search_subscription_delete":
|
elif action == "search_subscription_delete":
|
||||||
search_subscription_id = request.POST.get("search_subscription_id")
|
search_subscription_id = request.POST.get("search_subscription_id")
|
||||||
SearchSubscription.objects.get(pk=search_subscription_id).delete()
|
SearchSubscription.objects.get(pk=search_subscription_id).delete()
|
||||||
|
@@ -27,7 +27,6 @@ class DistanceTest(TestCase):
|
|||||||
l_stuttgart = LocationProxy("Stuttgart")
|
l_stuttgart = LocationProxy("Stuttgart")
|
||||||
l_tue = LocationProxy("Tübingen")
|
l_tue = LocationProxy("Tübingen")
|
||||||
# Should be 30km
|
# Should be 30km
|
||||||
print(f"{l_stuttgart.position} -> {l_tue.position}")
|
|
||||||
distance_tue_stuttgart = calculate_distance_between_coordinates(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.assertLess(distance_tue_stuttgart, 50)
|
||||||
self.assertGreater(distance_tue_stuttgart, 20)
|
self.assertGreater(distance_tue_stuttgart, 20)
|
||||||
|
@@ -4,7 +4,7 @@ from django.utils import timezone
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from model_bakery import baker
|
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):
|
class UserTest(TestCase):
|
||||||
@@ -77,3 +77,21 @@ class AnnouncementTest(TestCase):
|
|||||||
self.assertTrue(self.announcement2 not in active_announcements)
|
self.assertTrue(self.announcement2 not in active_announcements)
|
||||||
self.assertTrue(self.announcement4 not in active_announcements)
|
self.assertTrue(self.announcement4 not in active_announcements)
|
||||||
self.assertTrue(self.announcement5 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)
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ from django.urls import reverse
|
|||||||
|
|
||||||
from model_bakery import baker
|
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
|
from fellchensammlung.views import add_adoption_notice
|
||||||
|
|
||||||
|
|
||||||
@@ -70,6 +70,33 @@ class AnimalAndAdoptionTest(TestCase):
|
|||||||
|
|
||||||
self.assertTrue(response.status_code < 400)
|
self.assertTrue(response.status_code < 400)
|
||||||
self.assertTrue(AdoptionNotice.objects.get(name="TestAdoption4").is_active)
|
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",))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user