Skip to content

Commit

Permalink
feat: v2 history endpoint with permissions (#704)
Browse files Browse the repository at this point in the history
* feat: v2 history endpoint with permissions

* chore: comments

* feat(api): testing and fixing pagination logic

* feat(api): rework score history to just return snapshot

* chore(api): remove v1 history endpoint and common
  • Loading branch information
tim-schultz authored Oct 24, 2024
1 parent 9f7997c commit 079f717
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 324 deletions.
8 changes: 7 additions & 1 deletion api/account/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,13 @@ def edit_selected(modeladmin, request, queryset):


class APIKeyPermissionsAdmin(ScorerModelAdmin):
list_display = ("id", "submit_passports", "read_scores", "create_scorers")
list_display = (
"id",
"submit_passports",
"read_scores",
"create_scorers",
"historical_endpoint",
)


svg_widget = AceWidget(
Expand Down
17 changes: 17 additions & 0 deletions api/account/migrations/0038_accountapikey_historical_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.6 on 2024-10-21 20:57

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("account", "0037_customization_partner_name"),
]

operations = [
migrations.AddField(
model_name="accountapikey",
name="historical_endpoint",
field=models.BooleanField(default=False),
),
]
1 change: 1 addition & 0 deletions api/account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ class AccountAPIKey(AbstractAPIKey):
submit_passports = models.BooleanField(default=True)
read_scores = models.BooleanField(default=True)
create_scorers = models.BooleanField(default=False)
historical_endpoint = models.BooleanField(default=False)

@admin.display(description="Rate Limit")
def rate_limit_display(self):
Expand Down
251 changes: 0 additions & 251 deletions api/registry/api/common.py

This file was deleted.

6 changes: 6 additions & 0 deletions api/registry/api/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Dict, List, Optional

from ninja import Schema

from registry.models import Event, Score


Expand Down Expand Up @@ -74,6 +75,11 @@ class ActionEnum(str, Enum):
score_update = Event.Action.SCORE_UPDATE


class NoScoreResponse(Schema):
address: str
status: str


class DetailedScoreResponse(Schema):
address: str
score: Optional[str]
Expand Down
36 changes: 7 additions & 29 deletions api/registry/api/v1.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
from typing import List, Optional
from urllib.parse import urljoin

import api_logging as logging
import django_filters
import requests
from django.conf import settings
from django.core.cache import cache
from ninja import Router
from ninja.pagination import paginate
from ninja_extra.exceptions import APIException

import api_logging as logging
from account.api import UnauthorizedException, create_community_for_account

# --- Deduplication Modules
Expand All @@ -14,14 +20,7 @@
Rules,
)
from ceramic_cache.models import CeramicCache
from django.conf import settings
from django.core.cache import cache
from ninja import Router
from ninja.pagination import paginate
from ninja_extra.exceptions import APIException
from registry.api import common
from registry.api.schema import (
CursorPaginatedHistoricalScoreResponse,
CursorPaginatedStampCredentialResponse,
DetailedScoreResponse,
ErrorMessageResponse,
Expand Down Expand Up @@ -315,27 +314,6 @@ async def aget_scorer_by_id(scorer_id: int | str, account: Account) -> Community
raise NotFoundApiException("No scorer matches the given criteria.") from exc


@router.get(
common.history_endpoint["url"],
auth=common.history_endpoint["auth"],
response=common.history_endpoint["response"],
summary=common.history_endpoint["summary"],
description=common.history_endpoint["description"],
)
@track_apikey_usage(track_response=False)
def get_score_history(
request,
scorer_id: int,
address: Optional[str] = None,
created_at: str = "",
token: str = None,
limit: int = 1000,
) -> CursorPaginatedHistoricalScoreResponse:
return common.history_endpoint["handler"](
request, scorer_id, address, created_at, token, limit
)


@router.get(
"/score/{int:scorer_id}/{str:address}",
auth=ApiKey(),
Expand Down
5 changes: 5 additions & 0 deletions api/registry/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ class InvalidLimitException(APIException):
default_detail = "Invalid limit."


class CreatedAtIsRequired(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = "You must provide created_at as a query param."


class NoRequiredPermissionsException(APIException):
status_code = status.HTTP_403_FORBIDDEN
default_detail = "You are not allowed to access this endpoint."
Expand Down
Loading

0 comments on commit 079f717

Please sign in to comment.