From 819c9a701770f50df227fcd902f21991c3fbb04a Mon Sep 17 00:00:00 2001 From: youngS Date: Fri, 5 Nov 2021 18:07:39 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=B8=BE=E6=8A=A5=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fir_admin/src/api/report.js | 25 ++ fir_admin/src/router/index.js | 19 ++ fir_admin/src/views/report/Detail.vue | 157 +++++++++++++ fir_admin/src/views/report/list.vue | 227 +++++++++++++++++++ fir_ser/admin/urls.py | 2 + fir_ser/admin/views/report.py | 76 +++++++ fir_ser/api/migrations/0021_appreportinfo.py | 38 ++++ fir_ser/api/models.py | 3 + fir_ser/api/utils/modelutils.py | 6 +- fir_ser/api/utils/serializer.py | 18 ++ 10 files changed, 568 insertions(+), 3 deletions(-) create mode 100644 fir_admin/src/api/report.js create mode 100644 fir_admin/src/views/report/Detail.vue create mode 100644 fir_admin/src/views/report/list.vue create mode 100644 fir_ser/admin/views/report.py create mode 100644 fir_ser/api/migrations/0021_appreportinfo.py diff --git a/fir_admin/src/api/report.js b/fir_admin/src/api/report.js new file mode 100644 index 0000000..1774be1 --- /dev/null +++ b/fir_admin/src/api/report.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function getAppReportIfo(query) { + return request({ + url: '/report/info', + method: 'get', + params: query + }) +} + +export function updateAppReportIfo(data) { + return request({ + url: '/report/info', + method: 'put', + data + }) +} + +export function deleteAppReportIfo(data) { + return request({ + url: '/report/info', + method: 'delete', + data + }) +} diff --git a/fir_admin/src/router/index.js b/fir_admin/src/router/index.js index 69f9ae5..2b024db 100644 --- a/fir_admin/src/router/index.js +++ b/fir_admin/src/router/index.js @@ -196,6 +196,25 @@ export const constantRoutes = [ } ] }, + { + path: '/report', + component: Layout, + children: [ + { + path: 'list', + name: 'report_info_list', + component: () => import('@/views/report/list'), + meta: { title: '应用举报信息', icon: 'form' } + }, + { + path: 'edit/:id(\\d+)', + component: () => import('@/views/report/Detail'), + name: 'report_info_edit', + meta: { title: '编辑信息', noCache: true, activeMenu: '/report/list' }, + hidden: true + } + ] + }, { path: '/wxbind', component: Layout, diff --git a/fir_admin/src/views/report/Detail.vue b/fir_admin/src/views/report/Detail.vue new file mode 100644 index 0000000..69fc032 --- /dev/null +++ b/fir_admin/src/views/report/Detail.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/fir_admin/src/views/report/list.vue b/fir_admin/src/views/report/list.vue new file mode 100644 index 0000000..b126cff --- /dev/null +++ b/fir_admin/src/views/report/list.vue @@ -0,0 +1,227 @@ + + + diff --git a/fir_ser/admin/urls.py b/fir_ser/admin/urls.py index ff876c5..0f4fc05 100644 --- a/fir_ser/admin/urls.py +++ b/fir_ser/admin/urls.py @@ -19,6 +19,7 @@ from admin.views.app import AppInfoView, AppReleaseInfoView from admin.views.domain import DomainNameInfoView from admin.views.login import LoginView, LoginUserView from admin.views.order import OrderInfoView +from admin.views.report import AdminReportView from admin.views.storage import StorageInfoView, StorageChangeView from admin.views.supersign import DeveloperInfoView, DevicesInfoView from admin.views.user import UserInfoView, UserCertificationInfoView, ThirdWxAccountView @@ -40,5 +41,6 @@ urlpatterns = [ re_path("^devices/info", DevicesInfoView.as_view()), re_path("^domain/info", DomainNameInfoView.as_view()), re_path("^wxbind/info", ThirdWxAccountView.as_view()), + re_path("^report/info", AdminReportView.as_view()), ] diff --git a/fir_ser/admin/views/report.py b/fir_ser/admin/views/report.py new file mode 100644 index 0000000..17f90be --- /dev/null +++ b/fir_ser/admin/views/report.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# project: 4月 +# author: liuyu +# date: 2021/4/11 + +import logging + +from rest_framework.pagination import PageNumberPagination +from rest_framework.response import Response +from rest_framework.views import APIView + +from api.models import AppReportInfo +from api.utils.auth import AdminTokenAuthentication +from api.utils.baseutils import get_dict_from_filter_fields +from api.utils.response import BaseResponse +from api.utils.serializer import AdminAppReportSerializer + +logger = logging.getLogger(__name__) + + +class AppsPageNumber(PageNumberPagination): + page_size = 20 # 每页显示多少条 + page_size_query_param = 'limit' # URL中每页显示条数的参数 + page_query_param = 'page' # URL中页码的参数 + max_page_size = None # 最大页码数限制 + + +class AdminReportView(APIView): + authentication_classes = [AdminTokenAuthentication, ] + + def get(self, request): + res = BaseResponse() + filter_fields = ["id", "app_name", "bundle_id", "remote_addr", "report_type", "email", "status", "app_id"] + filter_data = get_dict_from_filter_fields(filter_fields, request.query_params) + sort = request.query_params.get("sort", "-created_time") + page_obj = AppsPageNumber() + obj_list = AppReportInfo.objects.filter(**filter_data).order_by(sort) + page_serializer = page_obj.paginate_queryset(queryset=obj_list, request=request, + view=self) + serializer = AdminAppReportSerializer(page_serializer, many=True) + res.data = serializer.data + res.total = obj_list.count() + return Response(res.dict) + + def put(self, request): + res = BaseResponse() + data = request.data + pk = data.get("id", None) + if not pk: + res.code = 1003 + res.msg = "参数错误" + return Response(res.dict) + obj = AppReportInfo.objects.filter(id=pk).first() + if obj: + data['pk'] = pk + serializer = AdminAppReportSerializer(obj, data=data, partial=True) + if serializer.is_valid(): + serializer.save() + res.data = serializer.data + return Response(res.dict) + res.code = 1004 + res.msg = "数据校验失败" + return Response(res.dict) + + def delete(self, request): + res = BaseResponse() + data = request.data + pk = data.get("id", None) + if not pk: + res.code = 1003 + res.msg = "参数错误" + else: + AppReportInfo.objects.filter(pk=pk).delete() + return self.get(request) + return Response(res.dict) diff --git a/fir_ser/api/migrations/0021_appreportinfo.py b/fir_ser/api/migrations/0021_appreportinfo.py new file mode 100644 index 0000000..f3f050c --- /dev/null +++ b/fir_ser/api/migrations/0021_appreportinfo.py @@ -0,0 +1,38 @@ +# Generated by Django 3.2.3 on 2021-11-05 17:12 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('api', '0020_auto_20211104_1118'), + ] + + operations = [ + migrations.CreateModel( + name='AppReportInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('app_name', models.CharField(blank=True, max_length=32, null=True, verbose_name='应用名称')), + ('bundle_id', models.CharField(blank=True, max_length=64, verbose_name='bundle id')), + ('remote_addr', models.GenericIPAddressField(verbose_name='远程IP地址')), + ('report_type', + models.SmallIntegerField(choices=[(0, '侵权'), (1, '色情'), (2, '赌博'), (3, '欺诈'), (4, '暴力'), (5, '其他')], + default=5, verbose_name='举报类型')), + ('report_reason', models.CharField(max_length=512, verbose_name='举报详情')), + ('email', models.CharField(max_length=64, verbose_name='联系方式')), + ('username', models.CharField(max_length=64, verbose_name='姓名')), + ('status', models.SmallIntegerField(choices=[(1, '处理中'), (2, '已经处理')], default=1, verbose_name='处理状态')), + ('description', models.CharField(blank=True, default='', max_length=256, verbose_name='备注')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='访问时间')), + ('app_id', + models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='api.apps', + verbose_name='应用信息')), + ], + options={ + 'verbose_name': '应用举报信息', + 'verbose_name_plural': '应用举报信息', + }, + ), + ] diff --git a/fir_ser/api/models.py b/fir_ser/api/models.py index fdf3afa..ae38a4a 100644 --- a/fir_ser/api/models.py +++ b/fir_ser/api/models.py @@ -584,6 +584,9 @@ class AppReportInfo(models.Model): report_reason = models.CharField(max_length=512, verbose_name="举报详情") email = models.CharField(max_length=64, verbose_name="联系方式") username = models.CharField(max_length=64, verbose_name="姓名") + status_choices = ((1, '处理中'), (2, '已经处理')) + status = models.SmallIntegerField(choices=status_choices, default=1, verbose_name="处理状态") + description = models.CharField(verbose_name="备注", max_length=256, default='', blank=True) created_time = models.DateTimeField(auto_now_add=True, verbose_name="访问时间") class Meta: diff --git a/fir_ser/api/utils/modelutils.py b/fir_ser/api/utils/modelutils.py index 9f5a922..d4c6510 100644 --- a/fir_ser/api/utils/modelutils.py +++ b/fir_ser/api/utils/modelutils.py @@ -80,11 +80,11 @@ def add_remote_info_from_request(request, description): if request.user and request.user.id is not None: description = f"{request.user.uid}_{description}" remote_info = { - 'user_agent': meta_info.get('HTTP_USER_AGENT'), + 'user_agent': meta_info.get('HTTP_USER_AGENT')[0:510], 'remote_addr': get_real_ip_address(request), 'method': meta_info.get('REQUEST_METHOD'), - 'uri_info': urljoin(meta_info.get('PATH_INFO'), meta_info.get('QUERY_STRING')), - 'a_domain': get_origin_domain_name(request), + 'uri_info': urljoin(meta_info.get('PATH_INFO'), meta_info.get('QUERY_STRING'))[0:255], + 'a_domain': get_origin_domain_name(request)[0:127], 'description': description[0:255] } RemoteClientInfo.objects.create(**remote_info) diff --git a/fir_ser/api/utils/serializer.py b/fir_ser/api/utils/serializer.py index 23c1c22..7d123f6 100644 --- a/fir_ser/api/utils/serializer.py +++ b/fir_ser/api/utils/serializer.py @@ -777,3 +777,21 @@ class AppReportSerializer(serializers.ModelSerializer): class Meta: model = models.AppReportInfo exclude = ["id"] + + +class AdminAppReportSerializer(AppReportSerializer): + class Meta: + model = models.AppReportInfo + fields = '__all__' + read_only_fields = ["id", "app_id", "username", "created_time", "email", "report_reason", "report_type", + "remote_addr", "bundle_id", "app_name"] + + report_type_choices = serializers.SerializerMethodField() + + def get_report_type_choices(self, obj): + return get_choices_dict(obj.report_type_choices) + + status_choices = serializers.SerializerMethodField() + + def get_status_choices(self, obj): + return get_choices_dict(obj.status_choices)