Skip to content

Commit

Permalink
feat(api): adds trusta labs stamp weight (#350)
Browse files Browse the repository at this point in the history
* feat(api): adds trusta labs stamp weight

* feat(cgrants): only return contributions greater than 1 dollar (#351)

* feat(cgrants): only return contributions greater than 1 dollar

* fix(cgrants): round total amount

* feat(api): adds api for trusta lab scores

* feat(api): add grantsstack weights (#352)

* feat(api): adds trusta labs stamp weight

* feat(api): adds api for trusta lab scores

---------

Co-authored-by: Tim <[email protected]>
  • Loading branch information
aminah-io and tim-schultz authored Aug 15, 2023
1 parent bb6b3ad commit 44fc36d
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 0 deletions.
1 change: 1 addition & 0 deletions api/scorer/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
# "debug_toolbar",
"cgrants",
"django_filters",
"trusta_labs",
]

AUTHENTICATION_BACKENDS = [
Expand Down
1 change: 1 addition & 0 deletions api/scorer/settings/gitcoin_passport_weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"GrantsStack2Programs": "1.07",
"GrantsStack4Programs": "1.07",
"GrantsStack6Programs": "1.07",
"TrustaLabs": "1.54",
}


Expand Down
1 change: 1 addition & 0 deletions api/scorer/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@
path("social/", include("social_django.urls", namespace="social")),
path("passport-admin/", passport_admin_api.urls),
# path("__debug__/", include("debug_toolbar.urls")),
path("trusta_labs/", include("trusta_labs.urls")),
]
Empty file added api/trusta_labs/__init__.py
Empty file.
12 changes: 12 additions & 0 deletions api/trusta_labs/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.contrib import admin
from trusta_labs.models import TrustaLabsScore


class TrustaLabsScoreAdmin(admin.ModelAdmin):
list_display = ["address", "sybil_risk_score"]
search_fields = ["address"]
search_help_text = "This will perform an exact case insensitive search by 'address'"
show_full_result_count = False


admin.site.register(TrustaLabsScore, TrustaLabsScoreAdmin)
60 changes: 60 additions & 0 deletions api/trusta_labs/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from django.conf import settings
from ninja import Schema
from ninja.security import APIKeyHeader
from ninja_extra import NinjaExtraAPI, status
from ninja_extra.exceptions import APIException
from trusta_labs.models import TrustaLabsScore

api = NinjaExtraAPI(urls_namespace="trusta_labs")


class CgrantsApiKey(APIKeyHeader):
param_name = "AUTHORIZATION"

def authenticate(self, request, key):
if key == settings.CGRANTS_API_TOKEN:
return key


cg_api_key = CgrantsApiKey()


class TrustaLabsScorePayload(Schema):
address: str
score: int


class TrustaLabsScoreResponse(Schema):
address: str
score: int


class TrustaLabsScoreHasNoPayload(APIException):
status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
default_detail = "There is no payload with this request"


class TrustaLabsScoreHasNoAddress(APIException):
status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
default_detail = "A Trusta Lab score must be accompanied by an address"


class TrustaLabsScoreHasNoScore(APIException):
status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
default_detail = "A Trusta Lab request must include a score"


@api.post("/trusta-labs-score", auth=cg_api_key)
def create_trusta_labs_score_db(request, payload: TrustaLabsScorePayload):
if payload == None:
raise TrustaLabsScoreHasNoPayload()

if payload.address == None:
raise TrustaLabsScoreHasNoAddress()

if payload.score == None:
raise TrustaLabsScoreHasNoScore()

TrustaLabsScore.objects.update_or_create(
address=payload.address, sybil_risk_score=payload.score
)
6 changes: 6 additions & 0 deletions api/trusta_labs/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class TrustaLabsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "trusta_labs"
36 changes: 36 additions & 0 deletions api/trusta_labs/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 4.2.3 on 2023-08-14 17:52

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


class Migration(migrations.Migration):
initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="TrustaLabsScore",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"address",
account.models.EthAddressField(
db_index=True, max_length=100, null=True
),
),
("sybil_risk_score", models.IntegerField(blank=True, null=True)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
],
),
]
Empty file.
12 changes: 12 additions & 0 deletions api/trusta_labs/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from account.models import EthAddressField
from django.db import models

# WHEN a Trusta Labs API call is made for verification,
# THEN the result of the call, including timestamps, passport addresses, and Trusta Labs scores, should be logged in a dedicated table, separate from the credential issuance.


class TrustaLabsScore(models.Model):
address = EthAddressField(null=True, blank=False, max_length=100, db_index=True)
sybil_risk_score = models.IntegerField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
36 changes: 36 additions & 0 deletions api/trusta_labs/test/test_trusta_labs_score.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import json
from datetime import datetime, timezone
from typing import cast

from django.conf import settings
from django.test import Client, TestCase
from trusta_labs.models import TrustaLabsScore

mock_trusta_labs_score_body = {
"address": "0x8u3eu3ydh3rydh3irydhu",
"score": 20,
}


class TrustaLabsScoreTestCase(TestCase):
def test_create_trusta_labs_score(self):
self.headers = {"HTTP_AUTHORIZATION": settings.CGRANTS_API_TOKEN}
"""Test that creation of a trusta lab score works and saved correctly"""
client = Client()
trusta_labs_response = client.post(
"/trusta_labs/trusta-labs-score",
json.dumps(mock_trusta_labs_score_body),
content_type="application/json",
**self.headers
)
self.assertEqual(trusta_labs_response.status_code, 200)

# Check that the trusta lab score was created
all_trusta_labs_scores = list(TrustaLabsScore.objects.all())
self.assertEqual(len(all_trusta_labs_scores), 1)
score = all_trusta_labs_scores[0]
self.assertEqual(score.address, mock_trusta_labs_score_body["address"])
self.assertEqual(score.sybil_risk_score, mock_trusta_labs_score_body["score"])

def test_error_creating_trusta_lab_score(self):
pass
7 changes: 7 additions & 0 deletions api/trusta_labs/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.urls import path

from .api import api

urlpatterns = [
path("", api.urls),
]

0 comments on commit 44fc36d

Please sign in to comment.