tlog 增加errors

This commit is contained in:
曹前明 2022-07-26 12:21:53 +08:00
parent 28f2daca2b
commit d8b2ac28a3
24 changed files with 428 additions and 95 deletions

View File

@ -1,5 +1,5 @@
from __future__ import absolute_import, unicode_literals
from apps.utils.task import CustomTask
from apps.utils.tasks import CustomTask
from apps.am.models import Area
from celery import shared_task
from django.core.cache import cache

View File

@ -13,3 +13,7 @@ class SendCodeSerializer(serializers.Serializer):
class CodeLoginSerializer(serializers.Serializer):
phone = serializers.CharField(label="手机号")
code = serializers.CharField(label="验证码")
class WxCodeSerializer(serializers.Serializer):
code = serializers.CharField(label="code")

View File

@ -15,9 +15,11 @@ from rest_framework_simplejwt.tokens import RefreshToken
from django.core.cache import cache
from apps.utils.sms import send_sms
from apps.utils.tools import rannum
from apps.utils.wxmp import wxmpClient
from apps.utils.wx import wxClient
from apps.auth1.serializers import LoginSerializer, SendCodeSerializer
from apps.auth1.serializers import CodeLoginSerializer, LoginSerializer, SendCodeSerializer, WxCodeSerializer
from apps.system.models import User
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
@ -90,12 +92,11 @@ class WxmpLogin(CreateAPIView):
"""
authentication_classes = []
permission_classes = []
serializer_class = WxCodeSerializer
def post(self, request):
code = request.data['code']
info = requests.get('https://api.weixin.qq.com/sns/jscode2session?appid='+settings.WXMP_APPID+'&secret='+settings.WXMP_APPSECRET+'&js_code=' +
code+'&grant_type=authorization_code').content.decode('utf-8')
info = json.loads(info)
info = wxmpClient.get_basic_info(code=code)
openid = info['openid']
session_key = info['session_key']
try:
@ -116,23 +117,22 @@ class WxLogin(CreateAPIView):
"""
authentication_classes = []
permission_classes = []
serializer_class = WxCodeSerializer
def post(self, request):
code = request.data['code']
info = requests.get('https://api.weixin.qq.com/sns/jscode2session?appid='+settings.WXMP_APPID+'&secret='+settings.WXMP_APPSECRET+'&js_code=' +
code+'&grant_type=authorization_code').content.decode('utf-8')
info = json.loads(info)
info = wxClient.get_basic_info(code=code)
openid = info['openid']
session_key = info['session_key']
access = info['access_token']
try:
user = User.objects.get(wx_openid=openid, is_active=True)
ret = get_tokens_for_user(user)
ret['wx_session_key'] = session_key
ret['wx_token'] = access
ret['wx_openid'] = openid
cache.set(code, ret, 60*5)
return Response(ret)
except Exception:
return Response({'wx_openid': openid, 'wx_session_key': session_key}, status=400)
return Response({'wx_openid': openid, 'wx_token': access}, status=400)
class GetTokenFromCache(CreateAPIView):
@ -142,6 +142,7 @@ class GetTokenFromCache(CreateAPIView):
"""
authentication_classes = []
permission_classes = []
serializer_class = WxCodeSerializer
def post(self, request):
code = request.data['code']
@ -175,6 +176,7 @@ class CodeLogin(CreateAPIView):
"""
authentication_classes = []
permission_classes = []
serializer_class = CodeLoginSerializer
def post(self, request):
phone = request.data['phone']

View File

@ -0,0 +1,16 @@
from rest_framework import serializers
class SendSmsSerializer(serializers.Serializer):
phone = serializers.CharField(label='手机号')
template_code = serializers.CharField(label='模板标识')
template_param = serializers.JSONField(label='模板参数')
class GenerateVoiceSerializer(serializers.Serializer):
msg = serializers.CharField(label='文本')
class TestTaskSerializer(serializers.Serializer):
args = serializers.ListField(child=serializers.CharField(), label='列表参数', required=False, allow_null=True)
kwargs = serializers.JSONField(label="字典参数", required=False, allow_null=True)

View File

@ -1,7 +1,12 @@
from __future__ import absolute_import, unicode_literals
from celery import shared_task
import subprocess
from apps.utils.tasks import CustomTask
from server.settings import DATABASES, BACKUP_PATH, SH_PATH, SD_PWD
import requests
import json
from django.conf import settings
from django.core.cache import cache
@shared_task
@ -37,6 +42,7 @@ def reload_web_git():
if completed.returncode != 0:
return completed.stderr
@shared_task
def reload_server_only():
command = 'echo "{}" | sudo -S supervisorctl reload'.format(SD_PWD)
@ -49,3 +55,12 @@ def backup_media():
command = 'bash {}/backup_media.sh'.format(SH_PATH)
completed = subprocess.run(command, shell=True, capture_output=True, text=True)
return completed
@shared_task(base=CustomTask)
def get_wx_token():
r = requests.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}'.format(
settings.WX_APPID, settings.WX_APPSECRET)).text
token = json.loads(r)['access_token']
cache.set('wx_token', token)
return token

View File

@ -1,13 +1,17 @@
from django.urls import path
from apps.develop.views import BackupDatabase, BackupMedia, ReloadClientGit, ReloadServerGit, ReloadServerOnly
from django.urls import path, include
from apps.develop.views import BackupDatabase, BackupMedia, ReloadClientGit, ReloadServerGit, ReloadServerOnly, TestViewSet
from rest_framework.routers import DefaultRouter
API_BASE_URL = 'api/develop/'
HTML_BASE_URL = 'develop/'
router = DefaultRouter()
router.register('test', TestViewSet, basename='api_test')
urlpatterns = [
path(API_BASE_URL + 'reload_server_git/', ReloadServerGit.as_view()),
path(API_BASE_URL + 'reload_web_git/', ReloadClientGit.as_view()),
path(API_BASE_URL + 'reload_server_only/', ReloadServerOnly.as_view()),
path(API_BASE_URL + 'backup_database/', BackupDatabase.as_view()),
path(API_BASE_URL + 'backup_media/', BackupMedia.as_view())
path(API_BASE_URL + 'backup_media/', BackupMedia.as_view()),
path(API_BASE_URL, include(router.urls)),
]

View File

@ -1,8 +1,20 @@
import json
from rest_framework.views import APIView
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
from apps.develop.tasks import backup_database, backup_media, reload_web_git, reload_server_git, reload_server_only
from rest_framework.serializers import Serializer
from rest_framework.decorators import action
from apps.develop.serializers import GenerateVoiceSerializer, SendSmsSerializer, TestTaskSerializer
from apps.develop.tasks import backup_database, backup_media, get_wx_token, reload_web_git, reload_server_git, reload_server_only
from rest_framework.exceptions import APIException, ParseError
from apps.system.models import User
from apps.system.tasks import show
from apps.utils.sms import send_sms
from apps.utils.speech import generate_voice
from django.core.cache import cache
import requests
from apps.utils.viewsets import CustomGenericViewSet
# Create your views here.
@ -91,3 +103,74 @@ class BackupMedia(APIView):
return Response()
else:
raise APIException(completed.stdout)
class TestViewSet(CustomGenericViewSet):
authentication_classes = ()
permission_classes = ()
@action(methods=['post'], detail=False, serializer_class=SendSmsSerializer)
def send_sms(self, request, pk=None):
"""发送短信测试
发送短信测试
"""
serializer = SendSmsSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
res = send_sms(**vdata)
return Response(res)
@action(methods=['post'], detail=False, serializer_class=GenerateVoiceSerializer)
def generate_voice(self, request, pk=None):
"""文字转语音测试
文字转语音测试
"""
serializer = GenerateVoiceSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
res = generate_voice(**vdata)
return Response(res)
@action(methods=['post'], detail=False, serializer_class=TestTaskSerializer)
def task(self, request, pk=None):
"""任务派发测试
任务派发测试
"""
serializer = TestTaskSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
ret = {}
task = show.delay(*vdata.get('args', []), **vdata.get('kwargs', {}))
ret['task_id'] = task.task_id
return Response(ret)
@action(methods=['post'], detail=False, serializer_class=Serializer)
def send_wx_msg(self, request, pk=None):
"""微信模板消息发送测试
微信模板消息发送测试
"""
wx_token = cache.get('wx_token', None)
if not wx_token:
wx_token = get_wx_token()
data = {
"touser": 'ocAnm5vab6QGOnf2dqpuUZGJ0xyw',
"template_id": "wczl-hB_bs8CpxwO8_KZuogSTPFXqhBxf8C5HjKl2M4",
"url": "http://weixin.qq.com/download",
# "miniprogram":{
# "appid":"xiaochengxuappid12345",
# "pagepath":"index?foo=bar"
# },
"client_msg_id": "MSG_000001",
"data": {
"first": {
"value": "恭喜你购买成功!",
"color": "#173177"
},
}
}
requests.post(url='https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='+wx_token, json=data)
return Response({'wx_token': wx_token, 'wx_openid': 'ocAnm5vab6QGOnf2dqpuUZGJ0xyw'})

View File

@ -49,4 +49,6 @@ def check_event_timeout():
cate = i.cates.all().order_by('priority', 'create_time').first()
if cate.hanle_minute > 0 and (timezone.now()-i.create_time).seconds > cate.hanle_minute * 60:
i.is_timeout = True
i.save()
i.save()

View File

@ -1,7 +1,7 @@
# Create your tasks here
from __future__ import absolute_import, unicode_literals
from apps.opm.models import Operation, Opl
from apps.utils.task import CustomTask
from apps.utils.tasks import CustomTask
from celery import shared_task
from apps.wf.models import State, Ticket

View File

@ -2,5 +2,5 @@
from __future__ import absolute_import, unicode_literals
from apps.hrm.models import Certificate, Employee
from apps.rpm.models import Rcertificate, Remployee, Rpj, Rpjcertificate, Rpjmember
from apps.utils.task import CustomTask
from apps.utils.tasks import CustomTask
from celery import shared_task

View File

@ -1,7 +1,7 @@
# Create your tasks here
from __future__ import absolute_import, unicode_literals
from random import random, randint
from apps.utils.task import CustomTask
from apps.utils.tasks import CustomTask
from celery import shared_task
from django.core.mail import send_mail

View File

@ -476,11 +476,12 @@ class UserViewSet(CustomModelViewSet):
绑定微信小程序
"""
openid = request.data['openid']
user = request.user
if user.wxmp_openid != openid:
User.objects.filter(wxmp_openid=openid).update(wxmp_openid=None)
user.wxmp_openid = openid
user.save()
if openid:
user = request.user
if user.wxmp_openid != openid:
User.objects.filter(wxmp_openid=openid).update(wxmp_openid=None)
user.wxmp_openid = openid
user.save()
return Response({'wxmp_openid': openid})
@action(methods=['post'], detail=False, permission_classes=[IsAuthenticated])
@ -502,11 +503,12 @@ class UserViewSet(CustomModelViewSet):
绑定微信公众号, 用于发送通知
"""
openid = request.data['openid']
user = request.user
if user.wx_openid != openid:
User.objects.filter(wx_openid=openid).update(wx_openid=None)
user.wx_openid = openid
user.save()
if openid:
user = request.user
if user.wx_openid != openid:
User.objects.filter(wx_openid=openid).update(wx_openid=None)
user.wx_openid = openid
user.save()
return Response({'wx_openid': openid})

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2022-07-26 04:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('third', '0008_auto_20220713_1408'),
]
operations = [
migrations.AddField(
model_name='tlog',
name='errors',
field=models.TextField(blank=True, null=True),
),
]

View File

@ -76,5 +76,6 @@ class Tlog(BaseModel):
response = models.JSONField(null=True, blank=True)
method = models.CharField(max_length=10)
url = models.TextField(null=True, blank=True)
errors = models.TextField(null=True, blank=True)
params = models.JSONField(null=True, blank=True)
body = models.JSONField(null=True, blank=True)

View File

@ -1,2 +1,3 @@
SIGN_MAKE_FAIL = {"code": "sign_make_fail", "detail": "签名照生成失败,请重新上传"}
PKS_ERROR = {"code": "pks_error", "detail": "未获取到主键列表"}
WX_REQUEST_ERROR = {"code": "wx_request_error", "detail": "微信接口访问异常"}

View File

@ -39,18 +39,3 @@ class CustomModelSerializer(DynamicFieldsMixin, serializers.ModelSerializer):
if hasattr(instance, 'update_by'):
validated_data['update_by'] = getattr(self.request, 'user', None)
return super().update(instance, validated_data)
class SendSmsSerializer(serializers.Serializer):
phone = serializers.CharField(label='手机号')
template_code = serializers.CharField(label='模板标识')
template_param = serializers.JSONField(label='模板参数')
class GenerateVoiceSerializer(serializers.Serializer):
msg = serializers.CharField(label='文本')
class TestTaskSerializer(serializers.Serializer):
args = serializers.ListField(child=serializers.CharField(), label='列表参数', required=False, allow_null=True)
kwargs = serializers.JSONField(label="字典参数", required=False, allow_null=True)

View File

@ -1,3 +1,4 @@
# from __future__ import absolute_import, unicode_literals
from celery import Task
import logging

View File

@ -1,11 +1,10 @@
from django.urls import path, include
from rest_framework import routers
from apps.utils.views import SignatureViewSet, TestViewSet
from apps.utils.views import SignatureViewSet
API_BASE_URL = 'api/utils/'
router = routers.DefaultRouter()
router.register('signature', SignatureViewSet, basename='signature')
router.register('test', TestViewSet, basename='util_test')
urlpatterns = [
path(API_BASE_URL, include(router.urls)),

View File

@ -4,18 +4,19 @@ import cv2
from django.http import HttpResponse
from apps.system.tasks import show
from apps.utils.errors import SIGN_MAKE_FAIL
from apps.utils.sms import send_sms
from apps.utils.speech import generate_voice
from server.settings import BASE_DIR
import numpy as np
from rest_framework.response import Response
from rest_framework.exceptions import ParseError
from apps.utils.viewsets import CustomGenericViewSet
from apps.utils.mixins import CustomCreateModelMixin
from apps.utils.serializers import GenSignatureSerializer, GenerateVoiceSerializer, SendSmsSerializer, TestTaskSerializer
from apps.utils.serializers import GenSignatureSerializer
from rest_framework.views import APIView
from rest_framework.decorators import action
from rest_framework.serializers import Serializer
from django.core.cache import cache
import json
import requests
class SignatureViewSet(CustomCreateModelMixin, CustomGenericViewSet):
@ -54,47 +55,4 @@ class SignatureViewSet(CustomCreateModelMixin, CustomGenericViewSet):
cv2.imwrite(new_path, image)
return Response({'path': new_path.replace(BASE_DIR, '')})
except Exception:
raise ParseError(**SIGN_MAKE_FAIL)
class TestViewSet(CustomGenericViewSet):
authentication_classes = ()
permission_classes = ()
@action(methods=['post'], detail=False, serializer_class=SendSmsSerializer)
def send_sms(self, request, pk=None):
"""发送短信测试
发送短信测试
"""
serializer = SendSmsSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
res = send_sms(**vdata)
return Response(res)
@action(methods=['post'], detail=False, serializer_class=GenerateVoiceSerializer)
def generate_voice(self, request, pk=None):
"""文字转语音测试
文字转语音测试
"""
serializer = GenerateVoiceSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
res = generate_voice(**vdata)
return Response(res)
@action(methods=['post'], detail=False, serializer_class=TestTaskSerializer)
def task(self, request, pk=None):
"""任务派发测试
任务派发测试
"""
serializer = TestTaskSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
ret = {}
task = show.delay(*vdata.get('args', []), **vdata.get('kwargs', {}))
ret['task_id'] = task.task_id
return Response(ret)
raise ParseError(**SIGN_MAKE_FAIL)

131
apps/utils/wx.py Normal file
View File

@ -0,0 +1,131 @@
import json
import time
from threading import Thread
import uuid
import requests
from django.conf import settings
from rest_framework.exceptions import APIException, ParseError
import logging
from apps.third.models import Tlog
from apps.utils.errors import WX_REQUEST_ERROR
from apps.utils.tools import print_roundtrip
from django.utils.timezone import now
import traceback
requests.packages.urllib3.disable_warnings()
# 实例化myLogger
myLogger = logging.getLogger('log')
class WxClient:
"""
微信公众号相关
"""
def __init__(self, app_id=settings.WX_APPID,
app_secret=settings.WX_APPSECRET) -> None:
if settings.WX_ENABLED:
self.app_id = app_id
self.app_secret = app_secret
self.isRuning = True
self.token = None
self.t = None # 线程
self.log = {}
self.setup()
def _get_token_loop(self):
while self.isRuning:
parmas = {
'grant_type': 'client_credential',
'appid': self.app_id,
'secret': self.app_secret
}
_, ret = self.request(url='/cgi-bin/token', params=parmas, method='get')
self.token = ret['access_token']
time.sleep(3600)
def setup(self):
t = Thread(target=self._get_token_loop, args=(), daemon=True)
t.start()
def __del__(self):
"""
自定义销毁
"""
self.isRuning = False
# self.t.join()
def request(self, url: str, method: str, params=dict(), json=dict(), timeout=10,
file_path_rela=None, raise_exception=True):
if not settings.WX_ENABLED:
raise ParseError('微信公众号未启用')
self.log = {"requested_at": now(), "id": uuid.uuid4(), "path": url, "method": method,
"params": params, "body": json, "target": "wx", "result": 10}
files = None
if file_path_rela: # 相对路径
files = {'file': open(settings.BASE_DIR + file_path_rela, 'rb')}
try:
if params:
url = url.format(**params)
self.log.update({"path": url})
r = getattr(requests, method)('{}{}'.format('https://api.weixin.qq.com', url),
params=params, json=json,
timeout=timeout, files=files, verify=False)
except Exception:
errors = traceback.format_exc()
myLogger.error(errors)
self.handle_log(result='error', errors=errors)
if raise_exception:
raise APIException(**WX_REQUEST_ERROR)
return 'error', WX_REQUEST_ERROR
# if settings.DEBUG:
# print_roundtrip(r)
if r.status_code == 200:
ret = r.json()
if 'errcode' in ret and ret['errcode'] not in [0, '0']:
detail = '微信错误:' + \
'{}|{}'.format(str(ret['errcode']), ret.get('errmsg', ''))
err_detail = dict(detail=detail, code='wx_'+str(ret['errcode']))
self.handle_log(result='fail', response=ret)
if raise_exception:
raise ParseError(**err_detail)
return 'fail', dict(detail=detail, code='wx_'+str(ret['errcode']))
# self.handle_log(result='success', response=ret) # 成功的日志就不记录了
return 'success', ret
self.handle_log(result='error', response=None)
if raise_exception:
raise APIException(**WX_REQUEST_ERROR)
return 'error', WX_REQUEST_ERROR
def _get_response_ms(self):
"""
Get the duration of the request response cycle is milliseconds.
In case of negative duration 0 is returned.
"""
response_timedelta = now() - self.log["requested_at"]
response_ms = int(response_timedelta.total_seconds() * 1000)
return max(response_ms, 0)
def handle_log(self, result, response=None, errors=None):
self.log.update({
"result": result,
"response": response,
"response_ms": self._get_response_ms(),
"errors": errors
})
Tlog(**self.log).save()
def get_basic_info(self, code):
params = {
'appid': self.app_id,
'secret': self.app_secret,
'code': code,
'grant_type': 'authorization_code'
}
_, res = self.request('/sns/oauth2/access_token', params=params, method='get')
return res
wxClient = WxClient()

106
apps/utils/wxmp.py Normal file
View File

@ -0,0 +1,106 @@
from distutils import errors
import json
import time
from threading import Thread
import uuid
import requests
from django.conf import settings
from rest_framework.exceptions import APIException, ParseError
import logging
from apps.third.models import Tlog
from apps.utils.errors import WX_REQUEST_ERROR
from apps.utils.tools import print_roundtrip
from django.utils.timezone import now
import traceback
requests.packages.urllib3.disable_warnings()
# 实例化myLogger
myLogger = logging.getLogger('log')
class WxmpClient:
"""
微信小程序相关
"""
def __init__(self, app_id=settings.WXMP_APPID,
app_secret=settings.WXMP_APPSECRET) -> None:
if settings.WXMP_ENABLED:
self.app_id = app_id
self.app_secret = app_secret
self.log = {}
def request(self, url: str, method: str, params=dict(), json=dict(), timeout=10,
file_path_rela=None, raise_exception=True):
if not settings.WX_ENABLED:
raise ParseError('微信小程序未启用')
self.log = {"requested_at": now(), "id": uuid.uuid4(), "path": url, "method": method,
"params": params, "body": json, "target": "wx", "result": 10}
files = None
if file_path_rela: # 相对路径
files = {'file': open(settings.BASE_DIR + file_path_rela, 'rb')}
try:
if params:
url = url.format(**params)
self.log.update({"path": url})
r = getattr(requests, method)('{}{}'.format('https://api.weixin.qq.com', url),
params=params, json=json,
timeout=timeout, files=files, verify=False)
except Exception:
errors = traceback.format_exc()
myLogger.error(errors)
self.handle_log(result='error', errors=errors)
if raise_exception:
raise APIException(**WX_REQUEST_ERROR)
return 'error', WX_REQUEST_ERROR
# if settings.DEBUG:
# print_roundtrip(r)
if r.status_code == 200:
ret = r.json()
if 'errcode' in ret and ret['errcode'] not in [0, '0']:
detail = '微信错误:' + \
'{}|{}'.format(str(ret['errcode']), ret.get('errmsg', ''))
err_detail = dict(detail=detail, code='wx_'+str(ret['errcode']))
self.handle_log(result='fail', response=ret)
if raise_exception:
raise ParseError(**err_detail)
return 'fail', dict(detail=detail, code='wx_'+str(ret['errcode']))
# self.handle_log(result='success', response=ret) # 成功的日志就不记录了
return 'success', ret
self.handle_log(result='error', response=None)
if raise_exception:
raise APIException(**WX_REQUEST_ERROR)
return 'error', WX_REQUEST_ERROR
def _get_response_ms(self):
"""
Get the duration of the request response cycle is milliseconds.
In case of negative duration 0 is returned.
"""
response_timedelta = now() - self.log["requested_at"]
response_ms = int(response_timedelta.total_seconds() * 1000)
return max(response_ms, 0)
def handle_log(self, result, response=None, errors=None):
self.log.update({
"result": result,
"response": response,
"response_ms": self._get_response_ms(),
"errors": errors
})
Tlog(**self.log).save()
def get_basic_info(self, code):
params = {
'appid': self.app_id,
'secret': self.app_secret,
'js_code': code,
'grant_type': 'authorization_code'
}
_, res = self.request('/sns/jscode2session', params=params, method='get')
return res
wxmpClient = WxmpClient()

View File

@ -1,7 +1,7 @@
# Create your tasks here
from __future__ import absolute_import, unicode_literals
from apps.hrm.models import Employee
from apps.utils.task import CustomTask
from apps.utils.tasks import CustomTask
from apps.vm.models import Visit, Vpeople
from apps.wf.models import Ticket
from celery import shared_task

View File

@ -5,7 +5,7 @@ import logging
import traceback
from apps.system.models import User
from apps.utils.sms import send_sms
from apps.utils.task import CustomTask
from apps.utils.tasks import CustomTask
from celery import shared_task
from apps.wf.models import State, Ticket, TicketFlow, Transition

View File

@ -397,5 +397,10 @@ AI_IP = conf.AI_IP
# 微信有关
WXMP_ENABLED = conf.WXMP_ENABLED
WXMP_APPID = conf.WXMP_APPID
WXMP_APPSECRET = conf.WXMP_APPSECRET
WX_ENABLED = conf.WX_ENABLED
WX_APPID = conf.WX_APPID
WX_APPSECRET = conf.WX_APPSECRET