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
|
||||
---------
|
||||
|
||||
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
|
||||
++++++++++++++++++++
|
||||
|
||||
|
@@ -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!
|
||||
^^^^^^^^^^^^^
|
||||
|
@@ -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 🥳
|
||||
|
@@ -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):
|
||||
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'))
|
||||
|
@@ -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
|
||||
|
@@ -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()
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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",))
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user