From 44e903300266702cbd9741d4e12ef79b7d475fda Mon Sep 17 00:00:00 2001 From: seek Date: Fri, 7 Jun 2024 15:04:57 +0800 Subject: [PATCH] solid audit projects dev (#42) Co-authored-by: guoshijiang --- api/solid/__init__.py | 0 api/solid/api_v1.py | 59 ++++++++ api/urls.py | 13 ++ hailstone/settings.py | 1 + solid/__init__.py | 0 solid/admin.py | 29 ++++ solid/apps.py | 6 + solid/migrations/0001_initial.py | 89 ++++++++++++ solid/migrations/__init__.py | 0 solid/models.py | 228 +++++++++++++++++++++++++++++++ solid/tests.py | 3 + solid/views.py | 3 + solid_api.md | 148 ++++++++++++++++++++ 13 files changed, 579 insertions(+) create mode 100644 api/solid/__init__.py create mode 100644 api/solid/api_v1.py create mode 100644 solid/__init__.py create mode 100644 solid/admin.py create mode 100644 solid/apps.py create mode 100644 solid/migrations/0001_initial.py create mode 100644 solid/migrations/__init__.py create mode 100644 solid/models.py create mode 100644 solid/tests.py create mode 100644 solid/views.py create mode 100644 solid_api.md diff --git a/api/solid/__init__.py b/api/solid/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/solid/api_v1.py b/api/solid/api_v1.py new file mode 100644 index 0000000..5309888 --- /dev/null +++ b/api/solid/api_v1.py @@ -0,0 +1,59 @@ +# encoding=utf-8 + +import json +import uuid + +from common.helpers import ( + ok_json, + error_json +) +from solid.models import ( + ServiceType, + AuditProject, + CoreMember, + LoadBoard +) + + +# @check_api_token +def get_services_type(request): + sr_list = ServiceType.objects.all().order_by("-id") + sr_response = [] + for sr in sr_list: + sr_response.append(sr.as_dict()) + return ok_json(sr_response) + + +# @check_api_token +def get_audit_projects(request): + params = json.loads(request.body.decode()) + service_type_id = params.get("service_type_id", 0) + status = params.get("status", "all") + if service_type_id not in ["0", 0] and status in ["all", "All", "ALL"]: + audit_project_lists = AuditProject.objects.filter(service_type__id=service_type_id).order_by("id").all() + elif status in ["all", "All", "ALL"]: + audit_project_lists = AuditProject.objects.all().order_by("id").all() + else: + audit_project_lists = AuditProject.objects.filter(status='Ongoing').order_by("id").all() + projects_ret_lists = [] + for ap in audit_project_lists: + projects_ret_lists.append(ap.as_dict()) + return ok_json(projects_ret_lists) + + +# @check_api_token +def get_core_members(request): + cm_lists = CoreMember.objects.all().order_by("-id").all() + cm_ret_lists = [] + for cm in cm_lists: + cm_ret_lists.append(cm.as_dict()) + return ok_json(cm_ret_lists) + + +# @check_api_token +def get_leadboard_list(request): + leadboard_lists = LoadBoard.objects.all().order_by("-payouts") + ret_leadboard_lists = [] + for ld in leadboard_lists: + ret_leadboard_lists.append(ld.as_dict()) + return ok_json(ret_leadboard_lists) diff --git a/api/urls.py b/api/urls.py index d75623d..97616fb 100644 --- a/api/urls.py +++ b/api/urls.py @@ -77,6 +77,13 @@ get_l2_withdraw_record ) +from api.solid.api_v1 import ( + get_services_type, + get_core_members, + get_audit_projects, + get_leadboard_list +) + urlpatterns = [ # Hd wallet module @@ -147,4 +154,10 @@ path(r'get_l2_stake_record', get_l2_stake_record, name='get_l2_stake_record'), path(r'get_l2_unstake_record', get_l2_unstake_record, name='get_l2_unstake_record'), path(r'get_l2_withdraw_record', get_l2_withdraw_record, name='get_l2_withdraw_record'), + + # solid + path(r'get_services_type', get_services_type, name='get_services_type'), + path(r'get_core_members', get_core_members, name='get_core_members'), + path(r'get_audit_projects', get_audit_projects, name='get_audit_projects'), + path(r'get_leadboard_list', get_leadboard_list, name='get_leadboard_list'), ] \ No newline at end of file diff --git a/hailstone/settings.py b/hailstone/settings.py index c1ac90d..7ee0731 100644 --- a/hailstone/settings.py +++ b/hailstone/settings.py @@ -25,6 +25,7 @@ 'airdrop', 'website', 'l3staking', + "solid", ] MIDDLEWARE = [ diff --git a/solid/__init__.py b/solid/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/solid/admin.py b/solid/admin.py new file mode 100644 index 0000000..35491b1 --- /dev/null +++ b/solid/admin.py @@ -0,0 +1,29 @@ +# encoding=utf-8 + +from django.contrib import admin +from solid.models import ( + ServiceType, + AuditProject, + CoreMember, + LoadBoard +) + +@admin.register(ServiceType) +class ServiceTypeAdmin(admin.ModelAdmin): + list_display = ('id', 'name', 'icon', 'detail') + + +@admin.register(AuditProject) +class AuditProjectAdmin(admin.ModelAdmin): + list_display = ('id', 'name', 'status', 'report_link') + + +@admin.register(CoreMember) +class CoreMemberAdmin(admin.ModelAdmin): + list_display = ('id', 'name') + + +@admin.register(LoadBoard) +class LoadBoardAdmin(admin.ModelAdmin): + list_display = ('id', 'competitor', 'payouts') + diff --git a/solid/apps.py b/solid/apps.py new file mode 100644 index 0000000..2ffaffc --- /dev/null +++ b/solid/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class SolidConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'solid' diff --git a/solid/migrations/0001_initial.py b/solid/migrations/0001_initial.py new file mode 100644 index 0000000..388865c --- /dev/null +++ b/solid/migrations/0001_initial.py @@ -0,0 +1,89 @@ +# Generated by Django 4.1.1 on 2024-06-07 05:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='CoreMember', + 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='Social', max_length=100, verbose_name='成员姓名')), + ('photo', models.ImageField(blank=True, null=True, upload_to='member/%Y/%m/%d/')), + ('detail', models.CharField(default='unknown', max_length=500, verbose_name='成员简介')), + ], + options={ + 'verbose_name': 'CoreMember', + 'verbose_name_plural': 'CoreMember', + }, + ), + migrations.CreateModel( + name='LoadBoard', + 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)), + ('competitor', models.CharField(default='unknown', max_length=500, verbose_name='审计员名称')), + ('payouts', models.CharField(default='0', max_length=500, verbose_name='获取的总收益')), + ('total_findings', models.CharField(default='0', max_length=500, verbose_name='找到的总问题数')), + ('solo', models.CharField(default='0', max_length=500, verbose_name='个人找到的问题')), + ('high', models.CharField(default='0', max_length=500, verbose_name='找到的高危漏洞数量')), + ('med', models.CharField(default='0', max_length=500, verbose_name='找到的中危漏洞数量')), + ('solo_high', models.CharField(default='0', max_length=500, verbose_name='个人找到的高危漏洞数量')), + ('solo_med', models.CharField(default='0', max_length=500, verbose_name='个人找到的中危漏洞数量')), + ('first_place', models.CharField(default='0', max_length=500, verbose_name='第一位置发现数量')), + ], + options={ + 'verbose_name': 'LeadBoard', + 'verbose_name_plural': 'LeadBoard', + }, + ), + migrations.CreateModel( + name='ServiceType', + 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='', max_length=100, verbose_name='服务名称')), + ('icon', models.ImageField(blank=True, null=True, upload_to='icon/%Y/%m/%d/')), + ('detail', models.CharField(default='unknown', max_length=500, verbose_name='服务描述')), + ], + options={ + 'verbose_name': 'ServiceType', + 'verbose_name_plural': 'ServiceType', + }, + ), + migrations.CreateModel( + name='AuditProject', + 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='', max_length=100, verbose_name='审计项目的名称')), + ('photo', models.ImageField(blank=True, null=True, upload_to='audit/%Y/%m/%d/')), + ('status', models.CharField(choices=[('Prepare', 'Prepare'), ('Ongoing', 'Ongoing'), ('End', 'End')], default='Ongoing', max_length=100, verbose_name='项目状体')), + ('project_link', models.CharField(blank=True, default='', max_length=100, null=True, verbose_name='项目链接')), + ('detail', models.CharField(default='unknown', max_length=500, verbose_name='项目描述')), + ('report_link', models.CharField(blank=True, default='', max_length=100, null=True, verbose_name='项目链接')), + ('service_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='services_type', to='solid.servicetype', verbose_name='项目类别')), + ], + options={ + 'verbose_name': 'AuditProject', + 'verbose_name_plural': 'AuditProject', + }, + ), + ] diff --git a/solid/migrations/__init__.py b/solid/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/solid/models.py b/solid/models.py new file mode 100644 index 0000000..92b0d9b --- /dev/null +++ b/solid/models.py @@ -0,0 +1,228 @@ +# encoding=utf-8 +import pytz + +from django.conf import settings +from django.db import models +from common.models import BaseModel, Asset + + +StatusChoice = [(x, x) for x in ['Prepare', 'Ongoing', 'End']] +tz = pytz.timezone(settings.TIME_ZONE) + +class ServiceType(BaseModel): + name = models.CharField( + default="", + max_length=100, + unique=False, + verbose_name='服务名称' + ) + icon = models.ImageField( + upload_to='icon/%Y/%m/%d/', + blank=True, + null=True + ) + detail = models.CharField( + default="unknown", + max_length=500, + unique=False, + verbose_name='服务描述' + ) + + class Meta: + verbose_name = 'ServiceType' + verbose_name_plural = verbose_name + + def __str__(self): + return self.name + + def as_dict(self): + tz = pytz.timezone(settings.TIME_ZONE) + return { + 'id': self.id, + 'name': self.name, + 'icon': settings.IMG_URL + str(self.icon), + 'detail': self.detail, + 'created_at': self.created_at.astimezone(tz).strftime("%Y-%m-%d %H:%M:%S") + } + + +class AuditProject(BaseModel): + service_type = models.ForeignKey( + ServiceType, + related_name="services_type", + on_delete=models.CASCADE, + blank=True, + null=True, + verbose_name="项目类别", + ) + name = models.CharField( + default="", + max_length=100, + unique=False, + verbose_name='审计项目的名称' + ) + photo = models.ImageField( + upload_to='audit/%Y/%m/%d/', + blank=True, + null=True + ) + status = models.CharField( + max_length=100, + choices=StatusChoice, + default="Ongoing", + verbose_name='项目状体' + ) + project_link = models.CharField( + max_length=100, + default="", + blank=True, + null=True, + verbose_name="项目链接", + ) + detail = models.CharField( + default="unknown", + max_length=500, + unique=False, + verbose_name='项目描述' + ) + report_link = models.CharField( + max_length=100, + default="", + blank=True, + null=True, + verbose_name="项目链接", + ) + + class Meta: + verbose_name = 'AuditProject' + verbose_name_plural = verbose_name + + def __str__(self): + return self.name + + def as_dict(self): + return { + 'id': self.id, + 'name': self.name, + 'photo': settings.IMG_URL + str(self.photo), + 'status': self.status, + 'project_link': self.project_link, + 'detail': self.detail, + 'report_link': self.report_link, + 'created_at': self.created_at.astimezone(tz).strftime("%Y-%m-%d %H:%M:%S") + } + + +class CoreMember(BaseModel): + name = models.CharField( + default="Social", + max_length=100, + unique=False, + verbose_name='成员姓名' + ) + photo = models.ImageField( + upload_to='member/%Y/%m/%d/', + blank=True, + null=True + ) + detail = models.CharField( + default="unknown", + max_length=500, + unique=False, + verbose_name='成员简介' + ) + + class Meta: + verbose_name = 'CoreMember' + verbose_name_plural = verbose_name + + def __str__(self): + return self.name + + def as_dict(self): + return { + 'id': self.id, + 'name': self.name, + 'photo': settings.IMG_URL + str(self.photo), + 'detail': self.detail, + 'created_at': self.created_at.astimezone(tz).strftime("%Y-%m-%d %H:%M:%S") + } + + +class LoadBoard(BaseModel): + competitor = models.CharField( + default="unknown", + max_length=500, + unique=False, + verbose_name='审计员名称' + ) + payouts = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='获取的总收益' + ) + total_findings = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='找到的总问题数' + ) + solo = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='个人找到的问题' + ) + high = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='找到的高危漏洞数量' + ) + med = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='找到的中危漏洞数量' + ) + solo_high = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='个人找到的高危漏洞数量' + ) + solo_med = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='个人找到的中危漏洞数量' + ) + first_place = models.CharField( + default="0", + max_length=500, + unique=False, + verbose_name='第一位置发现数量' + ) + + class Meta: + verbose_name = 'LeadBoard' + verbose_name_plural = verbose_name + + def __str__(self): + return self.competitor + + def as_dict(self): + tz = pytz.timezone(settings.TIME_ZONE) + return { + 'id': self.id, + 'competitor': self.competitor, + 'payouts': self.payouts, + 'solo': self.solo, + 'high': self.high, + 'med': self.med, + 'solo_high': self.solo_high, + 'solo_med': self.solo_med, + 'first_place': self.first_place, + 'created_at': self.created_at.astimezone(tz).strftime("%Y-%m-%d %H:%M:%S") + } diff --git a/solid/tests.py b/solid/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/solid/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/solid/views.py b/solid/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/solid/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/solid_api.md b/solid_api.md new file mode 100644 index 0000000..ccd52d8 --- /dev/null +++ b/solid_api.md @@ -0,0 +1,148 @@ +# 1. 获取服务类别接口 + +- 接口参数:无 +- 接口请求示范 +``` +curl --location 'http://127.0.0.1:8089/api/get_services_type' +``` +- 接口返回值 +``` +{ + "ok": true, + "code": 200, + "result": [ + { + "id": 1, + "name": "编辑用户资料", + "icon": "https://hailstone.testnet.dapplink.xyz/media/icon/2024/06/07/600x200.jpeg", + "detail": "编辑用户资料编辑用户资料编辑用户资料", + "created_at": "2024-06-07 14:49:28" + } + ] +} +``` +- name: 服务名称 +- icon: 服务的图标 +- detail:服务描述 + +# 2. 获取服务类别接口 + +- 接口参数:无 +- 接口请求示范 +``` +curl --location 'http://127.0.0.1:8089/api/get_core_members' +``` +- 接口返回值 +``` +{ + "ok": true, + "code": 200, + "result": [ + { + "id": 1, + "name": "seek", + "photo": "https://hailstone.testnet.dapplink.xyz/media/member/2024/06/07/20240605-144519.jpeg", + "detail": "Mantle DA 架构师", + "created_at": "2024-06-07 14:53:25" + } + ] +} +``` + +- name: 姓名 +- photo:头像 +- detail:详解介绍 + +# 3. 获取项目信息 + +- 接口参数: + - service_type_id 传 0 返回全部项目信息,传对应项目 id 返回项目信息 + - status:传 all 返回所用项目信息, 传人 Ongoing 返回正在进行中的项目 +- 接口请求示范 +``` +curl --location 'http://127.0.0.1:8089/api/get_audit_projects' \ +--header 'Content-Type: application/json' \ +--data '{ + "service_type_id": 1, + "status": "all" +}' +``` +- 接口返回值 +``` +{ + "ok": true, + "code": 200, + "result": [ + { + "id": 1, + "name": "DappLink Bridge", + "photo": "https://hailstone.testnet.dapplink.xyz/media/audit/2024/06/07/20240531-180630.jpeg", + "status": "Ongoing", + "project_link": "http://127.0.0.1:8089/admin/solid/auditproject/add/", + "detail": "DappLink BridgeDappLink BridgeDappLink BridgeDappLink BridgeDappLink Bridge", + "report_link": "http://127.0.0.1:8089/admin/solid/auditproject/add/", + "created_at": "2024-06-07 14:57:22" + } + ] +} +``` +- name: 项目名称 +- photo:项目头像 +- status:项目状态 +- project_link:项目 github 链接 +- detail:项目详解介绍 +- report_link:项目审计报告链接 + +# 4. 获取排行榜 + +- 接口参数:无 +- 接口请求示范 +``` +curl --location 'http://127.0.0.1:8089/api/get_leadboard_list' \ +--data '' +``` +- 接口返回值 +``` +{ + "ok": true, + "code": 200, + "result": [ + { + "id": 3, + "competitor": "seek01", + "payouts": "20", + "solo": "0", + "high": "0", + "med": "0", + "solo_high": "0", + "solo_med": "0", + "first_place": "0", + "created_at": "2024-06-07 15:01:28" + }, + { + "id": 4, + "competitor": "seek02", + "payouts": "1000", + "solo": "0", + "high": "0", + "med": "0", + "solo_high": "0", + "solo_med": "0", + "first_place": "0", + "created_at": "2024-06-07 15:01:37" + }, + { + "id": 2, + "competitor": "seek", + "payouts": "10", + "solo": "0", + "high": "0", + "med": "0", + "solo_high": "0", + "solo_med": "0", + "first_place": "0", + "created_at": "2024-06-07 15:01:20" + } + ] +} +``` \ No newline at end of file