Compare commits
	
		
			9 Commits
		
	
	
		
			caf98ba60b
			...
			c1332ee1f0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c1332ee1f0 | |||
| f6240a7189 | |||
| 7a02774a29 | |||
| 8945fdc0f4 | |||
| 9f0a18ad91 | |||
| e7f26dd23a | |||
| fc5b1391df | |||
| 70bf8e2053 | |||
| 34b707ef20 | 
@@ -1,10 +1,48 @@
 | 
				
			|||||||
from ..models import AdoptionNotice
 | 
					from ..models import Animal, RescueOrganization, AdoptionNotice, Species, Image
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AdoptionNoticeSerializer(serializers.HyperlinkedModelSerializer):
 | 
					class AdoptionNoticeSerializer(serializers.HyperlinkedModelSerializer):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = AdoptionNotice
 | 
					        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"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AnimalCreateSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Animal
 | 
				
			||||||
 | 
					        fields = ["name", "date_of_birth", "description", "species", "sex", "adoption_notice"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AnimalGetSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Animal
 | 
				
			||||||
 | 
					        fields = "__all__"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RescueOrganizationSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = RescueOrganization
 | 
				
			||||||
 | 
					        exclude = ["internal_comment", "allows_using_materials"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ImageCreateSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def _animal_or_an(value):
 | 
				
			||||||
 | 
					        if not value in ["animal", "adoption_notice"]:
 | 
				
			||||||
 | 
					            raise serializers.ValidationError(
 | 
				
			||||||
 | 
					                'Set either animal or adoption_notice, depending on what type of object the image should be attached to.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    attach_to_type = serializers.CharField(validators=[_animal_or_an])
 | 
				
			||||||
 | 
					    attach_to = serializers.IntegerField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Image
 | 
				
			||||||
 | 
					        exclude = ["owner"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpeciesSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Species
 | 
				
			||||||
 | 
					        fields = "__all__"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,16 @@
 | 
				
			|||||||
from django.urls import path
 | 
					from django.urls import path
 | 
				
			||||||
from .views import (
 | 
					from .views import (
 | 
				
			||||||
    AdoptionNoticeApiView
 | 
					    AdoptionNoticeApiView,
 | 
				
			||||||
 | 
					    AnimalApiView, RescueOrganizationApiView, AddImageApiView, SpeciesApiView
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    path('adoption_notice', AdoptionNoticeApiView.as_view()),
 | 
					    path("adoption_notice", AdoptionNoticeApiView.as_view(), name="api-adoption-notice-list"),
 | 
				
			||||||
 | 
					    path("adoption_notice/<int:id>/", AdoptionNoticeApiView.as_view(), name="api-adoption-notice-detail"),
 | 
				
			||||||
 | 
					    path("animals/", AnimalApiView.as_view(), name="api-animal-list"),
 | 
				
			||||||
 | 
					    path("animals/<int:id>/", AnimalApiView.as_view(), name="api-animal-detail"),
 | 
				
			||||||
 | 
					    path("organizations/", RescueOrganizationApiView.as_view(), name="api-organization-list"),
 | 
				
			||||||
 | 
					    path("organizations/<int:id>/", RescueOrganizationApiView.as_view(), name="api-organization-detail"),
 | 
				
			||||||
 | 
					    path("images/", AddImageApiView.as_view(), name="api-add-image"),
 | 
				
			||||||
 | 
					    path("species/", SpeciesApiView.as_view(), name="api-species-list"),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,18 +7,36 @@ from rest_framework.permissions import IsAuthenticated
 | 
				
			|||||||
from django.db import transaction
 | 
					from django.db import transaction
 | 
				
			||||||
from fellchensammlung.models import AdoptionNotice, Animal, Log, TrustLevel
 | 
					from fellchensammlung.models import AdoptionNotice, Animal, Log, TrustLevel
 | 
				
			||||||
from fellchensammlung.tasks import add_adoption_notice_location
 | 
					from fellchensammlung.tasks import add_adoption_notice_location
 | 
				
			||||||
from .serializers import AdoptionNoticeSerializer
 | 
					from rest_framework import status
 | 
				
			||||||
 | 
					from rest_framework.permissions import IsAuthenticated
 | 
				
			||||||
 | 
					from .serializers import (
 | 
				
			||||||
 | 
					    AnimalGetSerializer,
 | 
				
			||||||
 | 
					    AnimalCreateSerializer,
 | 
				
			||||||
 | 
					    RescueOrganizationSerializer,
 | 
				
			||||||
 | 
					    AdoptionNoticeSerializer,
 | 
				
			||||||
 | 
					    ImageCreateSerializer,
 | 
				
			||||||
 | 
					    SpeciesSerializer,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from fellchensammlung.models import Animal, RescueOrganization, AdoptionNotice, Species, Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AdoptionNoticeApiView(APIView):
 | 
					class AdoptionNoticeApiView(APIView):
 | 
				
			||||||
    permission_classes = [permissions.IsAuthenticated]
 | 
					    permission_classes = [IsAuthenticated]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        serializer_context = {
 | 
					        """
 | 
				
			||||||
            'request': request,
 | 
					        Retrieve adoption notices with their related animals and images.
 | 
				
			||||||
        }
 | 
					        """
 | 
				
			||||||
 | 
					        adoption_notice_id = kwargs.get("id")
 | 
				
			||||||
 | 
					        if adoption_notice_id:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                adoption_notice = AdoptionNotice.objects.get(pk=adoption_notice_id)
 | 
				
			||||||
 | 
					                serializer = AdoptionNoticeSerializer(adoption_notice, context={"request": request})
 | 
				
			||||||
 | 
					                return Response(serializer.data, status=status.HTTP_200_OK)
 | 
				
			||||||
 | 
					            except AdoptionNotice.DoesNotExist:
 | 
				
			||||||
 | 
					                return Response({"error": "Adoption notice not found."}, status=status.HTTP_404_NOT_FOUND)
 | 
				
			||||||
        adoption_notices = AdoptionNotice.objects.all()
 | 
					        adoption_notices = AdoptionNotice.objects.all()
 | 
				
			||||||
        serializer = AdoptionNoticeSerializer(adoption_notices, many=True, context=serializer_context)
 | 
					        serializer = AdoptionNoticeSerializer(adoption_notices, many=True, context={"request": request})
 | 
				
			||||||
        return Response(serializer.data, status=status.HTTP_200_OK)
 | 
					        return Response(serializer.data, status=status.HTTP_200_OK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @transaction.atomic
 | 
					    @transaction.atomic
 | 
				
			||||||
@@ -53,3 +71,96 @@ class AdoptionNoticeApiView(APIView):
 | 
				
			|||||||
            {"message": "Adoption notice created successfully!", "id": adoption_notice.pk},
 | 
					            {"message": "Adoption notice created successfully!", "id": adoption_notice.pk},
 | 
				
			||||||
            status=status.HTTP_201_CREATED,
 | 
					            status=status.HTTP_201_CREATED,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AnimalApiView(APIView):
 | 
				
			||||||
 | 
					    permission_classes = [IsAuthenticated]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get list of animals or a specific animal by ID.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        animal_id = kwargs.get("id")
 | 
				
			||||||
 | 
					        if animal_id:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                animal = Animal.objects.get(pk=animal_id)
 | 
				
			||||||
 | 
					                serializer = AnimalGetSerializer(animal, context={"request": request})
 | 
				
			||||||
 | 
					                return Response(serializer.data, status=status.HTTP_200_OK)
 | 
				
			||||||
 | 
					            except Animal.DoesNotExist:
 | 
				
			||||||
 | 
					                return Response({"error": "Animal not found."}, status=status.HTTP_404_NOT_FOUND)
 | 
				
			||||||
 | 
					        animals = Animal.objects.all()
 | 
				
			||||||
 | 
					        serializer = AnimalGetSerializer(animals, many=True, context={"request": request})
 | 
				
			||||||
 | 
					        return Response(serializer.data, status=status.HTTP_200_OK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @transaction.atomic
 | 
				
			||||||
 | 
					    def post(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Create a new animal.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        serializer = AnimalCreateSerializer(data=request.data, context={"request": request})
 | 
				
			||||||
 | 
					        if serializer.is_valid():
 | 
				
			||||||
 | 
					            animal = serializer.save(owner=request.user)
 | 
				
			||||||
 | 
					            return Response(
 | 
				
			||||||
 | 
					                {"message": "Animal created successfully!", "id": animal.id},
 | 
				
			||||||
 | 
					                status=status.HTTP_201_CREATED,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RescueOrganizationApiView(APIView):
 | 
				
			||||||
 | 
					    permission_classes = [IsAuthenticated]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get list of rescue organizations or a specific organization by ID.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        org_id = kwargs.get("id")
 | 
				
			||||||
 | 
					        if org_id:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                organization = RescueOrganization.objects.get(pk=org_id)
 | 
				
			||||||
 | 
					                serializer = RescueOrganizationSerializer(organization, context={"request": request})
 | 
				
			||||||
 | 
					                return Response(serializer.data, status=status.HTTP_200_OK)
 | 
				
			||||||
 | 
					            except RescueOrganization.DoesNotExist:
 | 
				
			||||||
 | 
					                return Response({"error": "Organization not found."}, status=status.HTTP_404_NOT_FOUND)
 | 
				
			||||||
 | 
					        organizations = RescueOrganization.objects.all()
 | 
				
			||||||
 | 
					        serializer = RescueOrganizationSerializer(organizations, many=True, context={"request": request})
 | 
				
			||||||
 | 
					        return Response(serializer.data, status=status.HTTP_200_OK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddImageApiView(APIView):
 | 
				
			||||||
 | 
					    permission_classes = [IsAuthenticated]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @transaction.atomic
 | 
				
			||||||
 | 
					    def post(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Add an image to an animal or adoption notice.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        serializer = ImageCreateSerializer(data=request.data, context={"request": request})
 | 
				
			||||||
 | 
					        if serializer.is_valid():
 | 
				
			||||||
 | 
					            if serializer.validated_data["attach_to_type"] == "animal":
 | 
				
			||||||
 | 
					                object_to_attach_to = Animal.objects.get(id=serializer.validated_data["attach_to"])
 | 
				
			||||||
 | 
					            elif serializer.fields["attach_to_type"] == "adoption_notice":
 | 
				
			||||||
 | 
					                object_to_attach_to = AdoptionNotice.objects.get(id=serializer.validated_data["attach_to"])
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise ValueError("Unknown attach_to_type given, should not happen. Check serializer")
 | 
				
			||||||
 | 
					            serializer.validated_data.pop('attach_to_type', None)
 | 
				
			||||||
 | 
					            serializer.validated_data.pop('attach_to', None)
 | 
				
			||||||
 | 
					            image = serializer.save(owner=request.user)
 | 
				
			||||||
 | 
					            object_to_attach_to.photos.add(image)
 | 
				
			||||||
 | 
					            return Response(
 | 
				
			||||||
 | 
					                {"message": "Image added successfully!", "id": image.id},
 | 
				
			||||||
 | 
					                status=status.HTTP_201_CREATED,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpeciesApiView(APIView):
 | 
				
			||||||
 | 
					    permission_classes = [IsAuthenticated]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Retrieve a list of species.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        species = Species.objects.all()
 | 
				
			||||||
 | 
					        serializer = SpeciesSerializer(species, many=True, context={"request": request})
 | 
				
			||||||
 | 
					        return Response(serializer.data, status=status.HTTP_200_OK)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@
 | 
				
			|||||||
    --text-three: var(--primary-light-one);
 | 
					    --text-three: var(--primary-light-one);
 | 
				
			||||||
    --shadow-three: var(--primary-dark-one);
 | 
					    --shadow-three: var(--primary-dark-one);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**************************/
 | 
					/**************************/
 | 
				
			||||||
/* TAG SETTINGS (GENERAL) */
 | 
					/* TAG SETTINGS (GENERAL) */
 | 
				
			||||||
/**************************/
 | 
					/**************************/
 | 
				
			||||||
@@ -140,9 +141,8 @@ textarea {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.profile-card {
 | 
					.profile-card {
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    border-radius: 0px 0px 8px 8px;
 | 
					 | 
				
			||||||
    background-color: var(--highlight-two);
 | 
					 | 
				
			||||||
    color: var(--highlight-one-text);
 | 
					    color: var(--highlight-one-text);
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .btn2 {
 | 
					    .btn2 {
 | 
				
			||||||
        height: 40px;
 | 
					        height: 40px;
 | 
				
			||||||
@@ -211,8 +211,6 @@ select, .button {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*********************/
 | 
					/*********************/
 | 
				
			||||||
/* UNIQUE COMPONENTS */
 | 
					/* UNIQUE COMPONENTS */
 | 
				
			||||||
/*********************/
 | 
					/*********************/
 | 
				
			||||||
@@ -226,63 +224,143 @@ select, .button {
 | 
				
			|||||||
    background-color: var(--background-two);
 | 
					    background-color: var(--background-two);
 | 
				
			||||||
    border-bottom-left-radius: 15px;
 | 
					    border-bottom-left-radius: 15px;
 | 
				
			||||||
    border-bottom-right-radius: 15px;
 | 
					    border-bottom-right-radius: 15px;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
.nav-link {
 | 
					 | 
				
			||||||
    color: var(--text-one);
 | 
					 | 
				
			||||||
    text-align: center;
 | 
					 | 
				
			||||||
    text-decoration: none;
 | 
					 | 
				
			||||||
    border-radius: 4px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.header a, .header form {
 | 
					 | 
				
			||||||
    float: left;
 | 
					 | 
				
			||||||
    padding: 5px 12px 5px 12px;
 | 
					 | 
				
			||||||
    line-height: 25px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.header a:hover {
 | 
					 | 
				
			||||||
    background-color: var(--highlight-one);
 | 
					 | 
				
			||||||
    color: var(--highlight-one-text);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.header a.active {
 | 
					 | 
				
			||||||
    background-color: dodgerblue;
 | 
					 | 
				
			||||||
    color: white;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.header-right select.option {
 | 
					 | 
				
			||||||
    color: #000;
 | 
					 | 
				
			||||||
    background-color: var(--highlight-one);
 | 
					 | 
				
			||||||
    border: 1px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.header-right {
 | 
					 | 
				
			||||||
    float: right;
 | 
					 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    border-radius: 0px 0px 15px 15px;
 | 
					    flex-direction: row;
 | 
				
			||||||
    background-color: var(--highlight-two);
 | 
					    align-items: center;
 | 
				
			||||||
    color: var(--highlight-one-text);
 | 
					    justify-content: space-between;
 | 
				
			||||||
    padding: 5px 5px 0px 5px;
 | 
					    /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
 | 
				
			||||||
    height: 67px;
 | 
					    color: #FFF;
 | 
				
			||||||
 | 
					    height: 50px;
 | 
				
			||||||
 | 
					    padding: 1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media screen and (max-width: 500px) {
 | 
					#main-menu {
 | 
				
			||||||
    .header a {
 | 
					    order: -1;
 | 
				
			||||||
        float: none;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: row;
 | 
				
			||||||
 | 
					    list-style-type: none;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu > li {
 | 
				
			||||||
 | 
					    margin: 0 1rem;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu-button-container {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    width: 30px;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    justify-content: center;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    background: #4ab457;
 | 
				
			||||||
 | 
					    padding: 20px;
 | 
				
			||||||
 | 
					    border-radius: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#menu-toggle {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu-button,
 | 
				
			||||||
 | 
					.menu-button::before,
 | 
				
			||||||
 | 
					.menu-button::after {
 | 
				
			||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
        text-align: left;
 | 
					    background-color: #fff;
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    height: 4px;
 | 
				
			||||||
 | 
					    width: 30px;
 | 
				
			||||||
 | 
					    transition: transform 400ms cubic-bezier(0.23, 1, 0.32, 1);
 | 
				
			||||||
 | 
					    border-radius: 2px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .header-right {
 | 
					.menu-button::before {
 | 
				
			||||||
        float: none;
 | 
					    content: '';
 | 
				
			||||||
 | 
					    margin-top: -8px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu-button::after {
 | 
				
			||||||
 | 
					    content: '';
 | 
				
			||||||
 | 
					    margin-top: 8px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#menu-toggle:checked + .menu-button-container .menu-button::before {
 | 
				
			||||||
 | 
					    margin-top: 0px;
 | 
				
			||||||
 | 
					    transform: rotate(405deg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#menu-toggle:checked + .menu-button-container .menu-button {
 | 
				
			||||||
 | 
					    background: rgba(255, 255, 255, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#menu-toggle:checked + .menu-button-container .menu-button::after {
 | 
				
			||||||
 | 
					    margin-top: 0px;
 | 
				
			||||||
 | 
					    transform: rotate(-405deg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (max-width: 700px) {
 | 
				
			||||||
 | 
					    .menu-button-container {
 | 
				
			||||||
 | 
					        display: flex;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .menu {
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        top: 0;
 | 
				
			||||||
 | 
					        margin-top: 50px;
 | 
				
			||||||
 | 
					        left: 0;
 | 
				
			||||||
 | 
					        flex-direction: column;
 | 
				
			||||||
 | 
					        width: 100%;
 | 
				
			||||||
 | 
					        justify-content: center;
 | 
				
			||||||
 | 
					        align-items: center;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #menu-toggle ~ nav .menu li {
 | 
				
			||||||
 | 
					        height: 0;
 | 
				
			||||||
 | 
					        margin: 0;
 | 
				
			||||||
 | 
					        padding: 0;
 | 
				
			||||||
 | 
					        border: 0;
 | 
				
			||||||
 | 
					        transition: height 400ms cubic-bezier(0.23, 1, 0.32, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #menu-toggle:checked ~ nav .menu li {
 | 
				
			||||||
 | 
					        height: 3em;
 | 
				
			||||||
 | 
					        padding: 1em;
 | 
				
			||||||
 | 
					        transition: height 400ms cubic-bezier(0.23, 1, 0.32, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .header {
 | 
				
			||||||
 | 
					        border-radius: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .menu > li {
 | 
				
			||||||
 | 
					        display: flex;
 | 
				
			||||||
 | 
					        justify-content: center;
 | 
				
			||||||
 | 
					        margin: 0;
 | 
				
			||||||
 | 
					        padding: 0.5em 0;
 | 
				
			||||||
 | 
					        width: 100%;
 | 
				
			||||||
 | 
					        color: white;
 | 
				
			||||||
 | 
					        background-color: var(--background-two);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .menu > li:not(:last-child) {
 | 
				
			||||||
 | 
					        border-bottom: 1px solid #444;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #header-sign-out, #header-change-language {
 | 
				
			||||||
 | 
					        display: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.logo img {
 | 
					.logo img {
 | 
				
			||||||
    height: 40px;
 | 
					    height: 40px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -431,9 +509,6 @@ select, .button {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.photos {
 | 
					.photos {
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    flex-wrap: wrap;
 | 
					    flex-wrap: wrap;
 | 
				
			||||||
@@ -499,7 +574,6 @@ select, .button {
 | 
				
			|||||||
.btn-notification {
 | 
					.btn-notification {
 | 
				
			||||||
    display: inline-block;
 | 
					    display: inline-block;
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    padding: 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Make the badge float in the top right corner of the button */
 | 
					/* Make the badge float in the top right corner of the button */
 | 
				
			||||||
@@ -580,7 +654,6 @@ select, .button {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
.form-comments {
 | 
					.form-comments {
 | 
				
			||||||
    .btn {
 | 
					    .btn {
 | 
				
			||||||
        margin: 5px;
 | 
					        margin: 5px;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,16 @@
 | 
				
			|||||||
{% load static %}
 | 
					{% load static %}
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="header">
 | 
					<section class="header">
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
        <a href="{% url "index" %}" class="logo"><img src={% static 'fellchensammlung/img/logo_transparent.png' %}></a>
 | 
					        <a href="{% url "index" %}" class="logo"><img src={% static 'fellchensammlung/img/logo_transparent.png' %}></a>
 | 
				
			||||||
    <nav id="nav" class="nav justify-content-center">
 | 
					    </div>
 | 
				
			||||||
        <a class="nav-link " href="{% url "search" %}"><i class="fas fa-search"></i> {% translate 'Suchen' %}</a>
 | 
					 | 
				
			||||||
        <a class="nav-link " href="{% url "add-adoption" %}"><i
 | 
					 | 
				
			||||||
                class="fas fa-feather"></i> {% translate 'Vermittlung hinzufügen' %}</a>
 | 
					 | 
				
			||||||
        <a class="nav-link " href="{% url "about" %}"><i class="fas fa-info"></i> {% translate 'Über uns' %}</a>
 | 
					 | 
				
			||||||
        <a class="nav-link " href="{% url "rss" %}"><i class="fa-solid fa-rss"></i> {% translate 'RSS' %}</a>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </nav>
 | 
					 | 
				
			||||||
    <div class="header-right">
 | 
					 | 
				
			||||||
    <div class="profile-card">
 | 
					    <div class="profile-card">
 | 
				
			||||||
 | 
					        <div id="header-change-language">
 | 
				
			||||||
            {% include "fellchensammlung/forms/change_language.html" %}
 | 
					            {% include "fellchensammlung/forms/change_language.html" %}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
        {% if user.is_authenticated %}
 | 
					        {% if user.is_authenticated %}
 | 
				
			||||||
 | 
					 | 
				
			||||||
            <div class="btn2 button_darken btn-notification">
 | 
					            <div class="btn2 button_darken btn-notification">
 | 
				
			||||||
                <a href="{{ user.get_notifications_url }}">
 | 
					                <a href="{{ user.get_notifications_url }}">
 | 
				
			||||||
                    <i class="fa fa-bell" aria-hidden="true"></i>
 | 
					                    <i class="fa fa-bell" aria-hidden="true"></i>
 | 
				
			||||||
@@ -23,11 +18,10 @@
 | 
				
			|||||||
                {% if user.get_num_unread_notifications > 0 %}
 | 
					                {% if user.get_num_unread_notifications > 0 %}
 | 
				
			||||||
                    <span class="button__badge">{{ user.get_num_unread_notifications }}</span>
 | 
					                    <span class="button__badge">{{ user.get_num_unread_notifications }}</span>
 | 
				
			||||||
                {% endif %}
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <a class="btn2" href="{% url 'user-me' %}"><i aria-hidden="true" class="fas fa-user"></i></a>
 | 
					            <a class="btn2" href="{% url 'user-me' %}"><i aria-hidden="true" class="fas fa-user"></i></a>
 | 
				
			||||||
                <form class="btn2 button_darken" action="{% url 'logout' %}" method="post">
 | 
					            <form class="btn2 button_darken" id="header-sign-out" action="{% url 'logout' %}" method="post">
 | 
				
			||||||
                {% csrf_token %}
 | 
					                {% csrf_token %}
 | 
				
			||||||
                <button class="button" type="submit"><i aria-hidden="true" class="fas fa-sign-out"></i></button>
 | 
					                <button class="button" type="submit"><i aria-hidden="true" class="fas fa-sign-out"></i></button>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
@@ -35,7 +29,29 @@
 | 
				
			|||||||
            <a class="btn2" href="{% url "django_registration_register" %}">{% translate "Registrieren" %}</a>
 | 
					            <a class="btn2" href="{% url "django_registration_register" %}">{% translate "Registrieren" %}</a>
 | 
				
			||||||
            <a class="btn2" href="{% url "login" %}"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
 | 
					            <a class="btn2" href="{% url "login" %}"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					        <input id="menu-toggle" type="checkbox"/>
 | 
				
			||||||
 | 
					        <label class='menu-button-container' for="menu-toggle">
 | 
				
			||||||
 | 
					            <div class='menu-button'></div>
 | 
				
			||||||
 | 
					        </label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <nav id="main-menu">
 | 
				
			||||||
 | 
					            <ul class="menu">
 | 
				
			||||||
 | 
					                <li>
 | 
				
			||||||
 | 
					                    <a class="nav-link " href="{% url "search" %}"><i
 | 
				
			||||||
 | 
					                            class="fas fa-search"></i> {% translate 'Suchen' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li><a class="nav-link " href="{% url "add-adoption" %}"><i
 | 
				
			||||||
 | 
					                        class="fas fa-feather"></i> {% translate 'Vermittlung hinzufügen' %}</a></li>
 | 
				
			||||||
 | 
					                <li><a class="nav-link " href="{% url "about" %}"><i
 | 
				
			||||||
 | 
					                        class="fas fa-info"></i> {% translate 'Über uns' %}
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li><a class="nav-link " href="{% url "rss" %}"><i
 | 
				
			||||||
 | 
					                        class="fa-solid fa-rss"></i> {% translate 'RSS' %}
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					        </nav>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    </div>
 | 
					</section>
 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user