From a2964b3452e5b87fc80777fae1aac132353e87ce Mon Sep 17 00:00:00 2001 From: guoshijiang Date: Mon, 4 Mar 2024 11:27:06 +0800 Subject: [PATCH] airdrop grpc server development --- airdrop/admin.py | 14 +++- airdrop/airdrop_server.py | 36 +++++++++ airdrop/management/__init__.py | 0 airdrop/management/commands/__init__.py | 0 airdrop/management/commands/airdrop_server.py | 20 +++++ airdrop/migrations/0001_initial.py | 54 +++++++++++++ airdrop/models.py | 79 +++++++++++++++++-- api/airdrop/api.sh | 4 + api/airdrop/api_v1.py | 46 +++++++++++ api/urls.py | 7 ++ 10 files changed, 252 insertions(+), 8 deletions(-) create mode 100644 airdrop/airdrop_server.py create mode 100644 airdrop/management/__init__.py create mode 100644 airdrop/management/commands/__init__.py create mode 100644 airdrop/management/commands/airdrop_server.py create mode 100644 airdrop/migrations/0001_initial.py create mode 100644 api/airdrop/api.sh diff --git a/airdrop/admin.py b/airdrop/admin.py index 8c38f3f..0a019ff 100644 --- a/airdrop/admin.py +++ b/airdrop/admin.py @@ -1,3 +1,15 @@ +#encoding=utf-8 + from django.contrib import admin +from airdrop.models import ( + AirdropUser, + PointsRecord +) + +@admin.register(AirdropUser) +class AddressAmountStatAdmin(admin.ModelAdmin): + list_display = ('id', 'name', 'address', 'points') -# Register your models here. +@admin.register(PointsRecord) +class ChainAdmin(admin.ModelAdmin): + list_display = ('id', 'address', 'type', 'points') diff --git a/airdrop/airdrop_server.py b/airdrop/airdrop_server.py new file mode 100644 index 0000000..7c6684f --- /dev/null +++ b/airdrop/airdrop_server.py @@ -0,0 +1,36 @@ +#encoding=utf-8 + +import pytz +from airdrop.models import AirdropUser, PointsRecord +from services.savour_rpc import airdrop_pb2_grpc, common_pb2, airdrop_pb2 +from django.conf import settings + +tz = pytz.timezone(settings.TIME_ZONE) + +class AirdropServer(airdrop_pb2_grpc.AirdropServiceServicer): + def submitDppLinkPoints(self, request, context) -> airdrop_pb2.DppLinkPointsResponse: + airdrop_user: AirdropUser + type = str(request.type) + address = str(request.address) + points = int(request.points) + airdrop_tmp_user = AirdropUser.objects.filter(address=address).first() + if airdrop_tmp_user is not None: + airdrop_tmp_user.points += points + airdrop_tmp_user.save() + airdrop_user = airdrop_tmp_user + else: + airdrop_user = AirdropUser.objects.create( + address=address, + points=points + ) + PointsRecord.objects.create( + user=airdrop_user, + address=address, + type=type, + points=points + ) + return airdrop_pb2.DppLinkPointsResponse( + code=common_pb2.SUCCESS, + msg="submit dapplink points success", + ) + diff --git a/airdrop/management/__init__.py b/airdrop/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/airdrop/management/commands/__init__.py b/airdrop/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/airdrop/management/commands/airdrop_server.py b/airdrop/management/commands/airdrop_server.py new file mode 100644 index 0000000..db1eb43 --- /dev/null +++ b/airdrop/management/commands/airdrop_server.py @@ -0,0 +1,20 @@ +#encoding=utf-8 + +import grpc +from django.core.management.base import BaseCommand +from concurrent import futures +from services.savour_rpc import airdrop_pb2_grpc +from airdrop.airdrop_server import AirdropServer + + +class Command(BaseCommand): + def handle(self, *args, **options): + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + airdrop_pb2_grpc.add_AirdropServiceServicer_to_server( + AirdropServer(), + server + ) + server.add_insecure_port('[::]:50251') + server.start() + print("airdrop rpc server start") + server.wait_for_termination() \ No newline at end of file diff --git a/airdrop/migrations/0001_initial.py b/airdrop/migrations/0001_initial.py new file mode 100644 index 0000000..f3f8315 --- /dev/null +++ b/airdrop/migrations/0001_initial.py @@ -0,0 +1,54 @@ +# Generated by Django 4.1.1 on 2024-03-03 03:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='AirdropUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.CharField(blank=True, max_length=100, null=True, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), + ('updated_at', models.DateTimeField(auto_now=True, db_index=True)), + ('name', models.CharField(default='unknown', max_length=100, unique=True, verbose_name='用户名')), + ('photo', models.ImageField(blank=True, null=True, upload_to='symbol/%Y/%m/%d/')), + ('address', models.CharField(max_length=100, unique=True, verbose_name='用户地址')), + ('email', models.EmailField(blank=True, max_length=254, null=True)), + ('points', models.PositiveIntegerField(default=0, verbose_name='积分数量')), + ('x_twitter', models.CharField(blank=True, default='', max_length=100, null=True, verbose_name='x')), + ('discord', models.CharField(blank=True, default='', max_length=100, null=True, verbose_name='discord')), + ('telegram', models.CharField(blank=True, default='', max_length=100, null=True, verbose_name='discord')), + ('info', models.CharField(blank=True, default='', max_length=100, null=True, verbose_name='个人介绍')), + ], + options={ + 'verbose_name': 'User', + 'verbose_name_plural': 'User', + }, + ), + migrations.CreateModel( + name='PointsRecord', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('uuid', models.CharField(blank=True, max_length=100, null=True, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), + ('updated_at', models.DateTimeField(auto_now=True, db_index=True)), + ('address', models.CharField(max_length=100, unique=True, verbose_name='用户地址')), + ('type', models.CharField(choices=[('BridgeTransfer', 'BridgeTransfer'), ('BridgeStaking', 'BridgeStaking')], default='BridgeTransfer', max_length=100, verbose_name='交易类别')), + ('points', models.PositiveIntegerField(default=0, verbose_name='积分数量')), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='airdrop_user', to='airdrop.airdropuser', verbose_name='收藏的商家')), + ], + options={ + 'verbose_name': 'PointsRecord', + 'verbose_name_plural': 'PointsRecord', + }, + ), + ] diff --git a/airdrop/models.py b/airdrop/models.py index 178ecc9..5f86ca7 100644 --- a/airdrop/models.py +++ b/airdrop/models.py @@ -5,8 +5,9 @@ TypeChoice = [(x, x) for x in ['BridgeTransfer', 'BridgeStaking']] -class User(BaseModel): +class AirdropUser(BaseModel): name = models.CharField( + default="unknown", max_length=100, unique=True, verbose_name='用户名' @@ -16,17 +17,47 @@ class User(BaseModel): blank=True, null=True ) - type = models.CharField( - max_length=100, - choices=TypeChoice, - default="BridgeTransfer", - verbose_name='交易类别' - ) address = models.CharField( max_length=100, unique=True, verbose_name='用户地址' ) + email = models.EmailField( + blank=True, + null=True + ) + points = models.PositiveIntegerField( + default=0, + verbose_name="积分数量" + ) + x_twitter = models.CharField( + max_length=100, + default="", + blank=True, + null=True, + verbose_name="x", + ) + discord = models.CharField( + max_length=100, + default="", + blank=True, + null=True, + verbose_name="discord", + ) + telegram = models.CharField( + max_length=100, + default="", + blank=True, + null=True, + verbose_name="discord", + ) + info = models.CharField( + max_length=100, + default="", + blank=True, + null=True, + verbose_name="个人介绍", + ) class Meta: verbose_name = 'User' @@ -39,15 +70,41 @@ def as_dict(self): return { 'id': self.id, 'name': self.name, + 'photo': str(self.photo), + 'address': self.address, + 'email': self.email, + 'points': self.points, + 'x_twitter': self.x_twitter, + 'discord': self.discord, + 'telegram': self.telegram, + 'info': self.info } class PointsRecord(BaseModel): + user = models.ForeignKey( + AirdropUser, + related_name="airdrop_user", + on_delete=models.CASCADE, + blank=True, + null=True, + verbose_name="收藏的商家", + ) address = models.CharField( max_length=100, unique=True, verbose_name='用户地址' ) + type = models.CharField( + max_length=100, + choices=TypeChoice, + default="BridgeTransfer", + verbose_name='交易类别' + ) + points = models.PositiveIntegerField( + default=0, + verbose_name="积分数量" + ) class Meta: verbose_name = 'PointsRecord' @@ -55,3 +112,11 @@ class Meta: def __str__(self): return self.address + + def as_dict(self): + return { + 'id': self.id, + 'name': self.address, + 'type': self.type, + 'points': self.points + } diff --git a/api/airdrop/api.sh b/api/airdrop/api.sh new file mode 100644 index 0000000..72d49bc --- /dev/null +++ b/api/airdrop/api.sh @@ -0,0 +1,4 @@ +curl --location --request POST 'http://127.0.0.1:8000/api/get_points_by_address' --header 'Content-Type: application/json' --data-raw '{"address": "0xe3b4ECd2EC88026F84cF17fef8bABfD9184C94F0" }' + + +curl --location --request POST 'http://127.0.0.1:8000/api/get_points_record_by_address' --header 'Content-Type: application/json' --data-raw '{"address": "0xe3b4ECd2EC88026F84cF17fef8bABfD9184C94F0" }' \ No newline at end of file diff --git a/api/airdrop/api_v1.py b/api/airdrop/api_v1.py index e69de29..b88d372 100644 --- a/api/airdrop/api_v1.py +++ b/api/airdrop/api_v1.py @@ -0,0 +1,46 @@ +#encoding=utf-8 + +import json +from common.helpers import ( + ok_json, + error_json +) +from airdrop.models import ( + AirdropUser, + PointsRecord +) + +# @check_api_token +def get_points_by_address(request): + params = json.loads(request.body.decode()) + address = params.get("address", None) + if address is None: + return error_json("address is empty", 4000) + airdrop_user = AirdropUser.objects.filter(address=address).first() + if airdrop_user is not None: + return ok_json(airdrop_user.as_dict()) + else: + return error_json("No this user address points", 4000) + +# @check_api_token +def get_points_record_by_address(request): + params = json.loads(request.body.decode()) + address = params.get("address", None) + if address is None: + return error_json("address is empty", 4000) + page = params.get('page', 1) + page_size = params.get('page_size', 20) + start = (page - 1) * page_size + end = start + page_size + points = PointsRecord.objects.filter(address=address).order_by("-id")[start:end] + total = PointsRecord.objects.filter(address=address).order_by("-id").count() + point_list = [] + for point in points: + point_list.append(point.as_dict()) + data = { + "total": total, + "points": point_list, + } + return ok_json(data) + + diff --git a/api/urls.py b/api/urls.py index 5bfbdf7..8d73114 100644 --- a/api/urls.py +++ b/api/urls.py @@ -52,6 +52,10 @@ get_arcticle_detail, like_article ) +from api.airdrop.api_v1 import ( + get_points_by_address, + get_points_record_by_address, +) urlpatterns = [ # Hd wallet module @@ -100,4 +104,7 @@ path(r'set_recovery_key', set_recovery_key, name='set_recovery_key'), path(r'get_tokens', get_tokens, name='get_tokens'), + # airdrop + path(r'get_points_by_address', get_points_by_address, name='get_points_by_address'), + path(r'get_points_record_by_address', get_points_record_by_address, name='get_points_record_by_address'), ] \ No newline at end of file