Skip to content

Commit

Permalink
1490 passport banner (#334)
Browse files Browse the repository at this point in the history
* feat(api): add passport_admin app

* feat(api): add passport admin models and app

* feat(api): passport admin model update

* feat(api): passport admin endpoints

* chore(api): unit tests for admin endpoints

* chore(api): remove name from model

* chore(api): fix test and squash migrations
  • Loading branch information
schultztimothy authored Aug 3, 2023
1 parent f116304 commit 42522c8
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 0 deletions.
Empty file added api/passport_admin/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions api/passport_admin/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Module for administering Passport Admin.
This includes registering the relevant models for PassportBanner and DismissedBanners.
"""

from django.contrib import admin

from .models import DismissedBanners, PassportBanner

admin.site.register(PassportBanner)
admin.site.register(DismissedBanners)
74 changes: 74 additions & 0 deletions api/passport_admin/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from typing import List

from ceramic_cache.api import JWTDidAuth
from django.db.models import Subquery
from ninja import Router, Schema

from .models import DismissedBanners, PassportBanner

router = Router()


def get_address(did: str):
start = did.index("0x")
return did[start:]


class Banner(Schema):
content: str
link: str
banner_id: int


@router.get(
"/banners",
response=List[Banner],
auth=JWTDidAuth(),
)
def get_banners(request):
"""
Get all banners
"""
try:
address = get_address(request.auth.did)
banners = (
PassportBanner.objects.filter(is_active=True)
.exclude(
pk__in=Subquery(
DismissedBanners.objects.filter(address=address).values("banner_id")
)
)
.all()
)

return [Banner(content=b.content, link=b.link, banner_id=b.pk) for b in banners]
except:
return {
"status": "failed",
}


class GenericResponse(Schema):
status: str


@router.post(
"/banners/{banner_id}/dismiss",
response={200: GenericResponse},
auth=JWTDidAuth(),
)
def dismiss_banner(request, banner_id: int):
"""
Dismiss a banner
"""
try:
banner = PassportBanner.objects.get(id=banner_id)
address = get_address(request.auth.did)
DismissedBanners.objects.create(address=address, banner=banner)
return {
"status": "success",
}
except PassportBanner.DoesNotExist:
return {
"status": "failed",
}
6 changes: 6 additions & 0 deletions api/passport_admin/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class PassportAdminConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "passport_admin"
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Generated by Django 4.2.3 on 2023-08-03 16:32

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

replaces = [
("passport_admin", "0001_initial"),
("passport_admin", "0002_rename_description_passportbanner_content_and_more"),
("passport_admin", "0003_remove_passportbanner_name"),
]

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="PassportBanner",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("content", models.TextField()),
("link", models.URLField(blank=True, null=True)),
("is_active", models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name="DismissedBanners",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("address", models.CharField(max_length=255)),
(
"banner",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
related_name="dismissedbanners",
to="passport_admin.passportbanner",
),
),
],
),
]
Empty file.
30 changes: 30 additions & 0 deletions api/passport_admin/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Module for defining models for Passport Admin.
Includes models for PassportBanner and DismissedBanners.
"""

from django.db import models


class PassportBanner(models.Model):
"""
Model representing a Passport Banner.
"""

content = models.TextField()
link = models.URLField(blank=True, null=True)
is_active = models.BooleanField(default=True)


class DismissedBanners(models.Model):
"""
Model representing Dismissed Banners.
"""

address = models.CharField(max_length=255)
banner = models.ForeignKey(
PassportBanner,
on_delete=models.CASCADE,
default=None,
related_name="dismissedbanners",
)
7 changes: 7 additions & 0 deletions api/passport_admin/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from scorer.test.conftest import (
api_key,
sample_address,
sample_provider,
sample_token,
verifiable_credential,
)
47 changes: 47 additions & 0 deletions api/passport_admin/tests/test_passport_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import pytest
from django.test import Client
from passport_admin.api import get_address
from passport_admin.models import DismissedBanners, PassportBanner

pytestmark = pytest.mark.django_db

client = Client()


class TestPassPortAdmin:
def test_get_address(self):
assert (
get_address("did:pkh:eip155:1:0xc79abb54e4824cdb65c71f2eeb2d7f2db5da1fb8")
== "0xc79abb54e4824cdb65c71f2eeb2d7f2db5da1fb8"
)

def test_get_banners(self, sample_token):
response = client.get(
"/passport-admin/banners",
HTTP_AUTHORIZATION=f"Bearer {sample_token}",
content_type="application/json",
)
assert response.json() == []

def test_dismiss_banner(self, sample_token, sample_address):
banner = PassportBanner.objects.create(content="test", link="test")
response = client.post(
f"/passport-admin/banners/{banner.pk}/dismiss",
{},
content_type="application/json",
HTTP_AUTHORIZATION=f"Bearer {sample_token}",
)
assert response.json() == {"status": "success"}
dismissed_banner = DismissedBanners.objects.get(
banner=banner, address=sample_address.lower()
)
assert dismissed_banner.banner == banner

def test_dismiss_banner_does_not_exist(self, sample_token):
response = client.post(
"/passport-admin/banners/1/dismiss",
{},
content_type="application/json",
HTTP_AUTHORIZATION=f"Bearer {sample_token}",
) # Needs JWT Auth
assert response.json() == {"status": "failed"}
4 changes: 4 additions & 0 deletions api/scorer/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ninja.openapi.schema import OpenAPISchema
from ninja.operation import Operation
from ninja.types import DictStrAny
from passport_admin.api import router as passport_admin_router
from registry.api.v1 import analytics_router, feature_flag_router
from registry.api.v1 import router as registry_router_v1
from registry.api.v2 import router as registry_router_v2
Expand Down Expand Up @@ -89,5 +90,8 @@ def service_unavailable(request, _):
ceramic_cache_api = NinjaAPI(urls_namespace="ceramic-cache", docs_url=None)
ceramic_cache_api.add_router("", ceramic_cache_router)

passport_admin_api = NinjaAPI(urls_namespace="passport-admin", docs_url=None)
passport_admin_api.add_router("", passport_admin_router)

analytics_api = NinjaAPI(urls_namespace="analytics", title="Data Analytics API")
analytics_api.add_router("", analytics_router)
1 change: 1 addition & 0 deletions api/scorer/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"account",
"ninja_extra",
"social_django",
"passport_admin",
# "debug_toolbar",
"cgrants",
"django_filters",
Expand Down
2 changes: 2 additions & 0 deletions api/scorer/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
analytics_api,
ceramic_cache_api,
feature_flag_api,
passport_admin_api,
registry_api_v1,
registry_api_v2,
)
Expand All @@ -43,5 +44,6 @@
path("admin/", admin.site.urls),
path("account/", include("account.urls")),
path("social/", include("social_django.urls", namespace="social")),
path("passport-admin/", passport_admin_api.urls),
# path("__debug__/", include("debug_toolbar.urls")),
]

0 comments on commit 42522c8

Please sign in to comment.