mirror of
https://github.com/ae-utbm/sith.git
synced 2025-06-08 12:15:18 +00:00
adapt CanAccessLookup
to api key auth
This commit is contained in:
parent
867878e5c0
commit
851db41665
@ -8,7 +8,7 @@ from ninja_extra.schemas import PaginatedResponseSchema
|
|||||||
|
|
||||||
from apikey.auth import ApiKeyAuth
|
from apikey.auth import ApiKeyAuth
|
||||||
from club.models import Club
|
from club.models import Club
|
||||||
from club.schemas import ClubSchema
|
from club.schemas import ClubSchema, SimpleClubSchema
|
||||||
from core.auth.api_permissions import CanAccessLookup, HasPerm
|
from core.auth.api_permissions import CanAccessLookup, HasPerm
|
||||||
|
|
||||||
|
|
||||||
@ -16,8 +16,10 @@ from core.auth.api_permissions import CanAccessLookup, HasPerm
|
|||||||
class ClubController(ControllerBase):
|
class ClubController(ControllerBase):
|
||||||
@route.get(
|
@route.get(
|
||||||
"/search",
|
"/search",
|
||||||
response=PaginatedResponseSchema[ClubSchema],
|
response=PaginatedResponseSchema[SimpleClubSchema],
|
||||||
|
auth=[SessionAuth(), ApiKeyAuth()],
|
||||||
permissions=[CanAccessLookup],
|
permissions=[CanAccessLookup],
|
||||||
|
url_name="search_club",
|
||||||
)
|
)
|
||||||
@paginate(PageNumberPaginationExtra, page_size=50)
|
@paginate(PageNumberPaginationExtra, page_size=50)
|
||||||
def search_club(self, search: Annotated[str, MinLen(1)]):
|
def search_club(self, search: Annotated[str, MinLen(1)]):
|
||||||
@ -28,6 +30,7 @@ class ClubController(ControllerBase):
|
|||||||
response=ClubSchema,
|
response=ClubSchema,
|
||||||
auth=[SessionAuth(), ApiKeyAuth()],
|
auth=[SessionAuth(), ApiKeyAuth()],
|
||||||
permissions=[HasPerm("club.view_club")],
|
permissions=[HasPerm("club.view_club")],
|
||||||
|
url_name="fetch_club",
|
||||||
)
|
)
|
||||||
def fetch_club(self, club_id: int):
|
def fetch_club(self, club_id: int):
|
||||||
return self.get_object_or_exception(
|
return self.get_object_or_exception(
|
||||||
|
@ -1,16 +1,21 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from django.test import Client
|
||||||
|
from django.urls import reverse
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
from ninja_extra.testing import TestClient
|
|
||||||
from pytest_django.asserts import assertNumQueries
|
from pytest_django.asserts import assertNumQueries
|
||||||
|
|
||||||
from club.api import ClubController
|
|
||||||
from club.models import Club, Membership
|
from club.models import Club, Membership
|
||||||
|
from core.baker_recipes import subscriber_user
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_fetch_club():
|
def test_fetch_club(client: Client):
|
||||||
club = baker.make(Club)
|
club = baker.make(Club)
|
||||||
baker.make(Membership, club=club, _quantity=10, _bulk_create=True)
|
baker.make(Membership, club=club, _quantity=10, _bulk_create=True)
|
||||||
with assertNumQueries(3):
|
user = subscriber_user.make()
|
||||||
res = TestClient(ClubController).get(f"/{club.id}")
|
client.force_login(user)
|
||||||
|
with assertNumQueries(7):
|
||||||
|
# - 4 queries for authentication
|
||||||
|
# - 3 queries for the actual data
|
||||||
|
res = client.get(reverse("api:fetch_club", kwargs={"club_id": club.id}))
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
|
@ -5,11 +5,13 @@ from django.conf import settings
|
|||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from ninja import File, Query
|
from ninja import File, Query
|
||||||
|
from ninja.security import SessionAuth
|
||||||
from ninja_extra import ControllerBase, api_controller, paginate, route
|
from ninja_extra import ControllerBase, api_controller, paginate, route
|
||||||
from ninja_extra.exceptions import PermissionDenied
|
from ninja_extra.exceptions import PermissionDenied
|
||||||
from ninja_extra.pagination import PageNumberPaginationExtra
|
from ninja_extra.pagination import PageNumberPaginationExtra
|
||||||
from ninja_extra.schemas import PaginatedResponseSchema
|
from ninja_extra.schemas import PaginatedResponseSchema
|
||||||
|
|
||||||
|
from apikey.auth import ApiKeyAuth
|
||||||
from club.models import Mailing
|
from club.models import Mailing
|
||||||
from core.auth.api_permissions import CanAccessLookup, CanView, HasPerm
|
from core.auth.api_permissions import CanAccessLookup, CanView, HasPerm
|
||||||
from core.models import Group, QuickUploadImage, SithFile, User
|
from core.models import Group, QuickUploadImage, SithFile, User
|
||||||
@ -90,6 +92,7 @@ class SithFileController(ControllerBase):
|
|||||||
@route.get(
|
@route.get(
|
||||||
"/search",
|
"/search",
|
||||||
response=PaginatedResponseSchema[SithFileSchema],
|
response=PaginatedResponseSchema[SithFileSchema],
|
||||||
|
auth=[SessionAuth(), ApiKeyAuth()],
|
||||||
permissions=[CanAccessLookup],
|
permissions=[CanAccessLookup],
|
||||||
)
|
)
|
||||||
@paginate(PageNumberPaginationExtra, page_size=50)
|
@paginate(PageNumberPaginationExtra, page_size=50)
|
||||||
@ -102,6 +105,7 @@ class GroupController(ControllerBase):
|
|||||||
@route.get(
|
@route.get(
|
||||||
"/search",
|
"/search",
|
||||||
response=PaginatedResponseSchema[GroupSchema],
|
response=PaginatedResponseSchema[GroupSchema],
|
||||||
|
auth=[SessionAuth(), ApiKeyAuth()],
|
||||||
permissions=[CanAccessLookup],
|
permissions=[CanAccessLookup],
|
||||||
)
|
)
|
||||||
@paginate(PageNumberPaginationExtra, page_size=50)
|
@paginate(PageNumberPaginationExtra, page_size=50)
|
||||||
|
@ -189,4 +189,4 @@ class IsLoggedInCounter(BasePermission):
|
|||||||
return Counter.objects.filter(token=token).exists()
|
return Counter.objects.filter(token=token).exists()
|
||||||
|
|
||||||
|
|
||||||
CanAccessLookup = IsOldSubscriber | IsRoot | IsLoggedInCounter
|
CanAccessLookup = IsLoggedInCounter | HasPerm("core.access_lookup")
|
||||||
|
@ -805,6 +805,8 @@ class Command(BaseCommand):
|
|||||||
"add_peoplepicturerelation",
|
"add_peoplepicturerelation",
|
||||||
"add_page",
|
"add_page",
|
||||||
"add_quickuploadimage",
|
"add_quickuploadimage",
|
||||||
|
"view_club",
|
||||||
|
"access_lookup",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
28
core/migrations/0046_permissionrights.py
Normal file
28
core/migrations/0046_permissionrights.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 5.2 on 2025-05-20 17:50
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("core", "0045_quickuploadimage")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="GlobalPermissionRights",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"permissions": [("access_lookup", "Can access any lookup in the sith")],
|
||||||
|
"managed": False,
|
||||||
|
"default_permissions": [],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
@ -754,6 +754,23 @@ class UserBan(models.Model):
|
|||||||
return f"Ban of user {self.user.id}"
|
return f"Ban of user {self.user.id}"
|
||||||
|
|
||||||
|
|
||||||
|
class GlobalPermissionRights(models.Model):
|
||||||
|
"""Little hack to have permissions not linked to a specific db table."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
# No database table creation or deletion
|
||||||
|
# operations will be performed for this model.
|
||||||
|
managed = False
|
||||||
|
|
||||||
|
# disable "add", "change", "delete" and "view" default permissions
|
||||||
|
default_permissions = []
|
||||||
|
|
||||||
|
permissions = [("access_lookup", "Can access any lookup in the sith")]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.__class__.__name__
|
||||||
|
|
||||||
|
|
||||||
class Preferences(models.Model):
|
class Preferences(models.Model):
|
||||||
user = models.OneToOneField(
|
user = models.OneToOneField(
|
||||||
User, related_name="_preferences", on_delete=models.CASCADE
|
User, related_name="_preferences", on_delete=models.CASCADE
|
||||||
|
@ -16,10 +16,12 @@ from django.conf import settings
|
|||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from ninja import Query
|
from ninja import Query
|
||||||
|
from ninja.security import SessionAuth
|
||||||
from ninja_extra import ControllerBase, api_controller, paginate, route
|
from ninja_extra import ControllerBase, api_controller, paginate, route
|
||||||
from ninja_extra.pagination import PageNumberPaginationExtra
|
from ninja_extra.pagination import PageNumberPaginationExtra
|
||||||
from ninja_extra.schemas import PaginatedResponseSchema
|
from ninja_extra.schemas import PaginatedResponseSchema
|
||||||
|
|
||||||
|
from apikey.auth import ApiKeyAuth
|
||||||
from core.auth.api_permissions import CanAccessLookup, CanView, IsInGroup, IsRoot
|
from core.auth.api_permissions import CanAccessLookup, CanView, IsInGroup, IsRoot
|
||||||
from counter.models import Counter, Product, ProductType
|
from counter.models import Counter, Product, ProductType
|
||||||
from counter.schemas import (
|
from counter.schemas import (
|
||||||
@ -62,6 +64,7 @@ class CounterController(ControllerBase):
|
|||||||
@route.get(
|
@route.get(
|
||||||
"/search",
|
"/search",
|
||||||
response=PaginatedResponseSchema[SimplifiedCounterSchema],
|
response=PaginatedResponseSchema[SimplifiedCounterSchema],
|
||||||
|
auth=[SessionAuth(), ApiKeyAuth()],
|
||||||
permissions=[CanAccessLookup],
|
permissions=[CanAccessLookup],
|
||||||
)
|
)
|
||||||
@paginate(PageNumberPaginationExtra, page_size=50)
|
@paginate(PageNumberPaginationExtra, page_size=50)
|
||||||
@ -74,6 +77,7 @@ class ProductController(ControllerBase):
|
|||||||
@route.get(
|
@route.get(
|
||||||
"/search",
|
"/search",
|
||||||
response=PaginatedResponseSchema[SimpleProductSchema],
|
response=PaginatedResponseSchema[SimpleProductSchema],
|
||||||
|
auth=[SessionAuth(), ApiKeyAuth()],
|
||||||
permissions=[CanAccessLookup],
|
permissions=[CanAccessLookup],
|
||||||
)
|
)
|
||||||
@paginate(PageNumberPaginationExtra, page_size=50)
|
@paginate(PageNumberPaginationExtra, page_size=50)
|
||||||
|
@ -68,7 +68,7 @@ class TestUVSearch(TestCase):
|
|||||||
def test_permissions(self):
|
def test_permissions(self):
|
||||||
# Test with anonymous user
|
# Test with anonymous user
|
||||||
response = self.client.get(self.url)
|
response = self.client.get(self.url)
|
||||||
assert response.status_code == 403
|
assert response.status_code == 401
|
||||||
|
|
||||||
# Test with not subscribed user
|
# Test with not subscribed user
|
||||||
self.client.force_login(baker.make(User))
|
self.client.force_login(baker.make(User))
|
||||||
|
@ -5,6 +5,7 @@ from django.core.exceptions import ValidationError
|
|||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from ninja import Body, File, Query
|
from ninja import Body, File, Query
|
||||||
|
from ninja.security import SessionAuth
|
||||||
from ninja_extra import ControllerBase, api_controller, paginate, route
|
from ninja_extra import ControllerBase, api_controller, paginate, route
|
||||||
from ninja_extra.exceptions import NotFound, PermissionDenied
|
from ninja_extra.exceptions import NotFound, PermissionDenied
|
||||||
from ninja_extra.pagination import PageNumberPaginationExtra
|
from ninja_extra.pagination import PageNumberPaginationExtra
|
||||||
@ -12,6 +13,7 @@ from ninja_extra.permissions import IsAuthenticated
|
|||||||
from ninja_extra.schemas import PaginatedResponseSchema
|
from ninja_extra.schemas import PaginatedResponseSchema
|
||||||
from pydantic import NonNegativeInt
|
from pydantic import NonNegativeInt
|
||||||
|
|
||||||
|
from apikey.auth import ApiKeyAuth
|
||||||
from core.auth.api_permissions import (
|
from core.auth.api_permissions import (
|
||||||
CanAccessLookup,
|
CanAccessLookup,
|
||||||
CanEdit,
|
CanEdit,
|
||||||
@ -53,6 +55,7 @@ class AlbumController(ControllerBase):
|
|||||||
@route.get(
|
@route.get(
|
||||||
"/autocomplete-search",
|
"/autocomplete-search",
|
||||||
response=PaginatedResponseSchema[AlbumAutocompleteSchema],
|
response=PaginatedResponseSchema[AlbumAutocompleteSchema],
|
||||||
|
auth=[SessionAuth(), ApiKeyAuth()],
|
||||||
permissions=[CanAccessLookup],
|
permissions=[CanAccessLookup],
|
||||||
)
|
)
|
||||||
@paginate(PageNumberPaginationExtra, page_size=50)
|
@paginate(PageNumberPaginationExtra, page_size=50)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user