Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app): adding models and admin for address lists #612

Merged
merged 5 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
748 changes: 343 additions & 405 deletions api/Pipfile.lock

Large diffs are not rendered by default.

74 changes: 72 additions & 2 deletions api/account/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@
from rest_framework_api_key.admin import APIKeyAdmin
from scorer.scorer_admin import ScorerModelAdmin
from scorer_weighted.models import Scorer

from .models import Account, AccountAPIKey, Community, Customization
from django.urls import path
from django.shortcuts import render, redirect
import csv
import codecs

from .models import (
Account,
AccountAPIKey,
AllowList,
Community,
Customization,
AddressList,
AddressListMember,
)


@admin.register(Account)
Expand Down Expand Up @@ -193,10 +205,16 @@ class Meta:
fields = "__all__"


class AllowListInline(admin.TabularInline):
model = AllowList
extra = 0


@admin.register(Customization)
class CustomizationAdmin(ScorerModelAdmin):
form = CustomizationForm
raw_id_fields = ["scorer"]
inlines = [AllowListInline]
fieldsets = [
(
None,
Expand Down Expand Up @@ -254,3 +272,55 @@ def save_model(self, request, obj, form, change):
# Perform some validation...
pass
super().save_model(request, obj, form, change)


class AddressListMemberInline(admin.TabularInline):
model = AddressListMember
extra = 0


class AddressListCsvImportForm(forms.Form):
list = forms.ModelChoiceField(queryset=AddressList.objects.all(), required=True)
csv_file = forms.FileField()


@admin.register(AddressList)
class AddressListAdmin(ScorerModelAdmin):
list_display = ["name", "address_count"]
inlines = [AddressListMemberInline]
change_list_template = "account/addresslist_changelist.html"

def address_count(self, obj):
return obj.addresses.count()

def get_urls(self):
return [
path("import-csv/", self.import_csv),
] + super().get_urls()

def import_csv(self, request):
if request.method == "POST":
csv_file = request.FILES["csv_file"]
reader = csv.reader(codecs.iterdecode(csv_file, "utf-8"))
list_id = request.POST.get("list")
address_list = AddressList.objects.get(id=list_id)
duplicate_count = 0
success_count = 0
for row in reader:
address = row[0].strip()
try:
AddressListMember.objects.create(address=address, list=address_list)
success_count += 1
except Exception:
duplicate_count += 1
continue

self.message_user(
request,
"Imported %d addresses, skipped %d duplicates"
% (success_count, duplicate_count),
)
return redirect("..")
form = AddressListCsvImportForm()
payload = {"form": form}
return render(request, "account/address_list_csv_import_form.html", payload)
5 changes: 5 additions & 0 deletions api/account/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,11 @@ def get_account_customization(request, dashboard_path: str):
elif scorer and getattr(scorer, "binaryweightedscorer", None):
weights = scorer.binaryweightedscorer.weights

for allow_list in customization.allow_lists.all():
weights[f"AllowList#{allow_list.address_list.name}"] = str(
allow_list.weight
)

return dict(
key=customization.path,
useCustomDashboardPanel=customization.use_custom_dashboard_panel,
Expand Down
58 changes: 58 additions & 0 deletions api/account/migrations/0025_addresslist_addresslistmember.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Generated by Django 4.2.6 on 2024-06-11 22:12

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


class Migration(migrations.Migration):
dependencies = [
("account", "0024_customization_scorer_panel_text"),
]

operations = [
migrations.CreateModel(
name="AddressList",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(db_index=True, max_length=100, unique=True)),
],
),
migrations.CreateModel(
name="AddressListMember",
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),
),
(
"list",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="addresses",
to="account.addresslist",
),
),
],
options={
"unique_together": {("address", "list")},
},
),
]
20 changes: 20 additions & 0 deletions api/account/migrations/0026_alter_customization_scorer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.6 on 2024-06-11 22:13

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


class Migration(migrations.Migration):
dependencies = [
("account", "0025_addresslist_addresslistmember"),
]

operations = [
migrations.AlterField(
model_name="customization",
name="scorer",
field=models.OneToOneField(
on_delete=django.db.models.deletion.PROTECT, to="account.community"
),
),
]
44 changes: 44 additions & 0 deletions api/account/migrations/0027_allowlist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 4.2.6 on 2024-06-11 22:35

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


class Migration(migrations.Migration):
dependencies = [
("account", "0026_alter_customization_scorer"),
]

operations = [
migrations.CreateModel(
name="AllowList",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("weight", models.FloatField(default=0.0)),
(
"address_list",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="allow_lists",
to="account.addresslist",
),
),
(
"customization",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="allow_lists",
to="account.customization",
),
),
],
),
]
17 changes: 17 additions & 0 deletions api/account/migrations/0028_alter_allowlist_weight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.6 on 2024-06-12 15:39

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("account", "0027_allowlist"),
]

operations = [
migrations.AlterField(
model_name="allowlist",
name="weight",
field=models.DecimalField(decimal_places=4, default=0.0, max_digits=7),
),
]
35 changes: 34 additions & 1 deletion api/account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,27 @@ async def aget_scorer(self) -> Scorer:
return await BinaryWeightedScorer.objects.aget(scorer_ptr_id=scorer.id)


class AddressList(models.Model):
name = models.CharField(max_length=100, db_index=True, unique=True)

def __str__(self):
return f"AllowList - {self.name}"


class AddressListMember(models.Model):
address = EthAddressField(null=False, blank=False, max_length=100, db_index=True)
list = models.ForeignKey(
AddressList,
related_name="addresses",
on_delete=models.CASCADE,
null=False,
db_index=True,
)

class Meta:
unique_together = ["address", "list"]


class Customization(models.Model):
class CustomizationLogoBackgroundType(models.TextChoices):
DOTS = "DOTS"
Expand All @@ -405,7 +426,7 @@ class CustomizationLogoBackgroundType(models.TextChoices):
blank=True,
unique=False,
)
scorer = models.ForeignKey(Community, on_delete=models.PROTECT)
scorer = models.OneToOneField(Community, on_delete=models.PROTECT)
use_custom_dashboard_panel = models.BooleanField(default=False)

# CustomizationTheme
Expand Down Expand Up @@ -452,3 +473,15 @@ class CustomizationLogoBackgroundType(models.TextChoices):
blank=True,
null=True,
)


class AllowList(models.Model):
address_list = models.ForeignKey(
AddressList, on_delete=models.PROTECT, related_name="allow_lists"
)

customization = models.ForeignKey(
Customization, on_delete=models.CASCADE, related_name="allow_lists"
)

weight = models.DecimalField(default=0.0, max_digits=7, decimal_places=4)
14 changes: 14 additions & 0 deletions api/account/templates/account/address_list_csv_import_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends 'admin/base.html' %}

{% block content %}
<div>
<form action="." method="POST" enctype="multipart/form-data">
{{ form.as_p }}
{% csrf_token %}

<button type="submit">Upload CSV</button>
</form>
</div>
<br />

{% endblock %}
11 changes: 11 additions & 0 deletions api/account/templates/account/addresslist_changelist.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends 'admin/change_list.html' %}

{% block object-tools %}
<a style="padding: 8px; margin: 20px; font-weight: bold; text-decoration: none; border-radius: 12px; background-color: blue; color: white;"
href="import-csv/">
Import CSV 📁
</a>
<br />
<br />
{{ block.super }}
{% endblock %}
11 changes: 9 additions & 2 deletions api/registry/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
from django.contrib import admin, messages
from registry.api.schema import SubmitPassportPayload
from registry.api.v1 import ahandle_submit_passport
from registry.models import Event, GTCStakeEvent, HashScorerLink, Passport, Score, Stamp
from registry.models import (
Event,
GTCStakeEvent,
HashScorerLink,
Passport,
Score,
Stamp,
)
from scorer.scorer_admin import ScorerModelAdmin


Expand All @@ -24,7 +31,7 @@ def recalculate_user_score(modeladmin, request, queryset):
)
async_to_sync(ahandle_submit_passport)(sp, c.account)
rescored_ids.append(score.id)
except Exception as e:
except Exception:
print(f"Error for {scorer_id} and {address}")
failed_rescoring.append(score.id)

Expand Down
4 changes: 1 addition & 3 deletions api/registry/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import json

from account.models import Community, EthAddressField
from django.db import models
from django.db.models.signals import pre_save
Expand Down Expand Up @@ -89,7 +87,7 @@ def score_updated(sender, instance, **kwargs):
address=instance.passport.address,
community=instance.passport.community,
data={
"score": float(instance.score) if instance.score != None else 0,
"score": float(instance.score) if instance.score is not None else 0,
"evidence": instance.evidence,
},
)
Expand Down
2 changes: 2 additions & 0 deletions api/scorer/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,5 @@
"127.0.0.1",
# ...
]

IMPORT_EXPORT_SKIP_ADMIN_CONFIRM = True
lucianHymer marked this conversation as resolved.
Show resolved Hide resolved
Loading