import json import random import warnings from calendar import timegm from datetime import date, datetime, timedelta import requests from django.db.models import Q from django_filters.rest_framework import DjangoFilterBackend from openpyxl import Workbook, load_workbook from rest_framework import status from rest_framework.decorators import action from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework_jwt.serializers import (jwt_encode_handler, jwt_payload_handler) from rest_framework_jwt.settings import api_settings from crm.zhenzismsclient import ZhenziSmsClient from examtest.models_paper import WorkScope from question.models import Questioncat from question.serializers import QuestionSerializer from server import settings from utils.custom import CommonPagination from .filters import ConsumerFilter from .exports import export_consumer from .models import Company, Consumer, PaySubject, SendCode, ConsumerPerm, ConsumerRole from .serializers import CompanySerializer, ConsumerSerializer, ConsumerPermSerializer, ConsumerRoleSerializer, ConsumerDetailSerializer import requests from lxml import etree from rbac.models import UserProfile from django.http import Http404 appid = 'wxf1e9471c93f05ad6' secret = '4bf7f9bd6c52634586bbe792a1f0a834' sms_appid = '100172' sms_appsecret = '00b8681c-0ce6-41c8-a867-904c1891c78a' sms_url = 'https://sms.zhenzikj.com' def jwt_payload_handler(user): payload = { 'user_id': user.pk, 'type':'consumer', 'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA } if api_settings.JWT_ALLOW_REFRESH: payload['orig_iat'] = timegm( datetime.utcnow().utctimetuple() ) if api_settings.JWT_AUDIENCE is not None: payload['aud'] = api_settings.JWT_AUDIENCE if api_settings.JWT_ISSUER is not None: payload['iss'] = api_settings.JWT_ISSUER return payload class ConsumerRoleViewSet(ModelViewSet): """ 客户角色:增删改查 """ perms_map = [ {'get': 'consumerrole_view'}, {'post': 'consumerrole_create'}, {'put': 'consumerrole_update'}, {'delete': 'consumerrole_delete'}] queryset = ConsumerRole.objects.filter(is_delete=0) serializer_class = ConsumerRoleSerializer pagination_class = None filter_backends = [DjangoFilterBackend,SearchFilter, OrderingFilter] search_fields = ['name','description'] ordering_fields = ['create_time'] ordering = ['-create_time'] class ConsumerPermViewSet(ModelViewSet): """ 客户权限:增删改查 """ perms_map = [ {'get': 'consumerperm_view'}, {'post': 'consumerperm_create'}, {'put': 'consumerperm_update'}, {'delete': 'consumerperm_delete'}] queryset = ConsumerPerm.objects.filter(is_delete=0) serializer_class = ConsumerPermSerializer pagination_class = None filter_backends = [DjangoFilterBackend,SearchFilter, OrderingFilter] search_fields = ['name','code'] ordering_fields = ['create_time'] ordering = ['-create_time'] class CompanyViewSet(ModelViewSet): """ 客户企业:增删改查 """ perms_map = [ {'get': 'company_view'}, {'post': 'company_create'}, {'put': 'company_update'}, {'delete': 'company_delete'}] queryset = Company.objects.filter(is_delete=0).all() serializer_class = CompanySerializer pagination_class = CommonPagination filter_backends = [DjangoFilterBackend,SearchFilter, OrderingFilter] search_fields = ('name',) ordering_fields = ('id',) ordering = ['-id'] def perform_create(self, serializer): serializer.save(create_admin=self.request.user) def get_queryset(self): queryset = self.queryset if self.request.query_params.get('perm', None): return queryset if not self.request.user.is_superuser: queryset = queryset.filter(create_admin = self.request.user) return queryset @action(methods=['put'], detail=True, url_name='company_transfer',perms_map=[{'*':'company_transfer'}]) def transfer(self, request, *args, **kwargs): """ 转交 """ obj = self.get_object() adminname = request.data.get('admin', None) if adminname and UserProfile.objects.filter(username=adminname).exists(): adminobj = UserProfile.objects.get(username=adminname) obj.create_admin = adminobj obj.save() Consumer.objects.filter(company=obj).update(create_admin=adminobj) return Response(status=status.HTTP_200_OK) else: return Response({"error":"账号错误"}) class ConsumerViewSet(ModelViewSet): """ 学员:增删改查 """ perms_map = [ {'get': 'consumer_view'}, {'post': 'consumer_create'}, {'put': 'consumer_update'}, {'delete': 'consumer_delete'}] queryset = Consumer.objects.all() serializer_class = ConsumerSerializer pagination_class = CommonPagination ordering_fields = ('id','company','create_time', 'username', 'workscope') ordering = ['-create_time'] filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter] filterset_class = ConsumerFilter search_fields = ['name','username','company__name'] def get_queryset(self): queryset = self.queryset queryset = self.get_serializer_class().setup_eager_loading(queryset) if self.request.query_params.get('adminoff', None): return queryset.filter(create_admin=None) if not self.request.user.is_superuser: queryset = queryset.filter(create_admin = self.request.user) return queryset def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) instance = serializer.save(create_admin=request.user) if request.data.get('subjects', None): for i in request.data.get('subjects'): PaySubject.objects.get_or_create(consumer = instance, subject__id=i, defaults={'consumer':instance,'subject':Questioncat.objects.get(id=i)}) return Response(serializer.data, status=status.HTTP_201_CREATED) def update(self, request, *args, **kwargs): instance = self.get_object() serializer = self.get_serializer(instance, data=request.data) if serializer.is_valid(): instance = serializer.save() else: return Response(serializer.errors) PaySubject.objects.filter(consumer = instance).delete() if request.data.get('subjects', None): for i in request.data.get('subjects'): PaySubject.objects.get_or_create(consumer = instance, subject__id=i, defaults={'consumer':instance,'subject':Questioncat.objects.get(id=i)}) return Response(serializer.data) @action(methods=['post'], detail=False, url_name='consumer_deletes',perms_map=[{'*':'consumer_deletes'}]) def deletes(self, request): """ 批量删除用户 """ ids = request.data.get('ids', None) if ids: Consumer.objects.filter(id__in = ids).delete() return Response(status=status.HTTP_200_OK) @action(methods=['get'], detail=False, url_path='subjectpaid', url_name='subject_paid',perms_map=[{'*':'my_subject'}]) def has_paid(self, request): """ 当前登陆消费者已付费的学科 """ queryset = PaySubject.objects.filter(consumer = request.user) data = queryset.values_list('subject__id',flat=True) return Response(data) @action(methods=['get'], detail=False, url_path='sendcode', url_name='code_send',authentication_classes=[],permission_classes=[]) def sendcode(self, request): ''' 发送验证码 ''' client = ZhenziSmsClient(sms_url, sms_appid, sms_appsecret) code = random.randint(1000,9999) phone = request.query_params.get('phone') params = {'message':'您的验证码为:' + str(code) +',5分钟内有效', 'number': phone} result = json.loads(client.send(params)) if result['code'] == 0: SendCode.objects.create(phone=phone, code=code) return Response(status=status.HTTP_200_OK) else: return Response({'error':result['data']}) @action(methods=['post','delete','get'], detail=False, url_path='collects', url_name='create_collects', perms_map=[{'*':'my_collects'}]) def collects(self, request): ''' 个人收藏集 ''' if request.method == 'POST': questionId = request.data.get('question',None) if questionId: request.user.collects.remove(questionId) request.user.collects.add(questionId) return Response(status=status.HTTP_200_OK) else: return Response({'error':'post参数错误'}) elif request.method == 'GET': queryset = request.user.collects.all().order_by('-update_time') serializer = QuestionSerializer(instance=queryset,many=True) return Response(serializer.data) elif request.method == 'DELETE': questionId = request.data.get('question',None) if questionId: request.user.collects.remove(questionId) return Response(status=status.HTTP_200_OK) else: return Response({'error':'delete参数错误'}) @action(methods=['get', 'put'], detail=False, url_path='process', url_name='exercise_process', perms_map=[{'*':'*'}]) def process(self, request): ''' 练习进度 ''' if request.method == 'GET': process = {} if hasattr(request.user, 'process'): process = request.user.process return Response({'process':process}) elif request.method == 'PUT': if hasattr(request.user, 'process'): request.user.process = request.data['process'] request.user.save() return Response(status=status.HTTP_200_OK) # @action(methods=['put'], detail=False, # url_path='process', url_name='exercise_processcat', perms_map=[{'*':'*'}]) # def processcat(self, request): # ''' # 练习进度单类别修改 # ''' # if hasattr(request.user, 'process'): # request.user.process = request.data['process'] # request.user.save() # return Response(status=status.HTTP_200_OK) @action(methods=['post'], detail=False, url_path='realinfo', url_name='get_realinfo', perms_map=[{'*':'*'}]) def realinfo(self, request): ''' 修改真实信息 ''' if isinstance(request.user, Consumer): request.user.ID_number = request.data['ID_number'] request.user.realname = request.data['realname'] request.user.save() return Response(status=status.HTTP_200_OK) @action(methods=['get'], detail=False, url_path='candidate', url_name='consumer_candidate', perms_map=[{'*':'*'}]) def candidate(self, request): ''' 证书查询 ''' payload = {'IndexModel[name]': request.query_params['realname'], 'IndexModel[identityNumber]': request.query_params['ID_number'], 'IndexModel[certNumber]':'', 'IndexModel[candidateNumber]':''} r = requests.post('https://fushe.chinansc.cn/open/candidate-list',data=payload) html = etree.HTML(r.text) results = html.xpath("//table[@class='cert-table']") candidates = [] try: for i in results: img = i.xpath('tr/td/a/@href') name = i.xpath('tr[1]/td[1]/text()') ID_number = i.xpath('tr[1]/td[2]/text()') report_number = i.xpath('tr[2]/td[1]/text()') issue_date = i.xpath('tr[2]/td[2]/text()') jsondata = { 'name':name[0], 'ID_number':ID_number[0], 'report_number':report_number[0], 'issue_date':issue_date[0], 'img':'https://fushe.chinansc.cn'+ img[0] } candidates.append(jsondata) except: pass return Response({'candidates':candidates}, status=status.HTTP_200_OK) @action(methods=['post'], detail=False, url_path='import', url_name='import_consumer') def import_consumer(self, request): """ 导入用户 """ role1 = ConsumerRole.objects.get(name='付费学员') xlsxpath = request.data['path'] fullpath = settings.BASE_DIR + xlsxpath wb = load_workbook(fullpath) sheet = wb.worksheets[0] # 验证文件内容 if sheet['a2'].value != '姓名': return Response({"error":"姓名列错误!"}) if sheet['b2'].value != '账户(手机号)': return Response({"error":"账户列错误!"}) if sheet['c2'].value != '单位': return Response({"error":"单位列错误!"}) if sheet['d2'].value != '工作类别': return Response({"error":"工作类别列错误!"}) if sheet['e2'].value != '角色': return Response({"error":"角色列错误!"}) m = 3 while sheet['B'+str(m)].value: name = sheet['A'+str(m)].value if name: name = name.replace(' ', '') username = sheet['B'+str(m)].value if username: username = str(username).replace(' ', '').replace("\n", "") companyname = sheet['C'+str(m)].value if companyname: companyname = companyname.replace(' ', '') if Company.objects.filter(name=companyname).exists(): companyobj = Company.objects.get(name=companyname) else: companyobj = Company.objects.create(name=companyname, create_admin=request.user) workscope = sheet['d'+str(m)].value role = sheet['e'+str(m)].value if Consumer.objects.filter(username = username).exists(): obj = Consumer.objects.filter(username = username).first() else: obj = Consumer() obj.username = username obj.create_admin = request.user obj.name = name obj.company = companyobj obj.save() if workscope: workscope = workscope.replace(' ', '') try: workscopeobj = WorkScope.objects.get(name=workscope) obj.workscope = workscopeobj PaySubject.objects.get_or_create(subject=workscopeobj.subject, consumer = obj) except: return Response({"error":"工作类别不存在!"}) obj.role = role1 if role: role = role.replace(' ', '') try: roleobj = ConsumerRole.objects.get(name=role) obj.role = roleobj except: pass obj.exceed_date = datetime.now() + timedelta(days=90) obj.save() m = m + 1 return Response(status=status.HTTP_200_OK) @action(methods=['get'], detail=False, url_path='export', url_name='export_consumer', perms_map=[{'*':'export_consumer'}]) def export(self, request): queryset = self.filter_queryset(self.queryset) queryset = ConsumerSerializer.setup_eager_loading(queryset) # 性能优化 serializer = ConsumerSerializer(instance=queryset, many=True) path = export_consumer(serializer.data) return Response({'path': path}) @action(methods=['get'], detail=True, url_name='consumer_unbind', perms_map=[{'*':'consumer_unbind'}]) def unbind(self, request, *args, **kwargs): obj = self.get_object() if obj.username and obj.openid: obj.openid = None obj.nickname = None obj.avatar = None obj.save() return Response(status=status.HTTP_200_OK) else: return Response({"error":"不支持解绑!"}) @action(methods=['get'], detail=False, url_path='correctrole', url_name='correct_role', perms_map=[{'*':'correct_role'}]) def correctrole(self, request): role0 = ConsumerRole.objects.get(name='游客') role1 = ConsumerRole.objects.get(name='付费学员') role2 = ConsumerRole.objects.get(name='注册用户') for i in Consumer.objects.filter(role__isnull = True): i.role = role0 if i.workscope and i.username: i.role = role1 elif i.username and i.openid: i.role = role2 i.save() print(i.id) return Response(status=status.HTTP_200_OK) @action(methods=['get'], detail=False, url_path='correctexceed', url_name='correct_exceed', perms_map=[{'*':'correct_exceed'}]) def correctexceed(self, request): Consumer.objects.exclude(exceed_date=None).update(exceed_date = datetime(2020,12,31)) return Response(status=status.HTTP_200_OK) @action(methods=['get'], detail=False, url_path='correctadmin', url_name='correct_admin', perms_map=[{'*':'correct_admin'}]) def correctadmin(self, request): Consumer.objects.filter(name='').update(create_admin=None) return Response(status=status.HTTP_200_OK) @action(methods=['put'], detail=True, url_name='consumer_claim', perms_map=[{'*':'consumer_claim'}]) def claim(self, request, pk=None): try: obj = Consumer.objects.get(pk=pk) if obj.username and obj.create_admin is None: obj.create_admin = request.user obj.save() return Response(status=status.HTTP_200_OK) else: return Response({"error":"认领失败!"}) except: raise Http404 class ConsumerMPLoginView(APIView): """ 小程序登陆颁发token """ authentication_classes=[] permission_classes=[] def post(self, request, *args, **kwargs): code = request.data['code'] info = requests.get('https://api.weixin.qq.com/sns/jscode2session?appid='+appid+'&secret='+secret+'&js_code=' + code+'&grant_type=authorization_code').content.decode('utf-8') info = json.loads(info) openid = info['openid'] session_key = info['session_key'] consumer = Consumer.objects.get_or_create(openid = openid)[0] serializer = ConsumerDetailSerializer(instance=consumer) payload = jwt_payload_handler(consumer) token = jwt_encode_handler(payload) return Response({"token":token,"session_key":session_key, "openid":openid, "userinfo":serializer.data}) class ConsumerLogoutView(APIView): authentication_classes = () permission_classes = () def get(self, request, *args, **kwargs): return Response(status=status.HTTP_200_OK) class ConsumerRegister(APIView): ''' 验证码登陆和注册 ''' def post(self, request, *args, **kwargs): data = request.data phone = data.get('phone', None) code = data.get('code', None) avatar = data.get('avatar', None) nickname = data.get('nickname', None) if phone and code: obj = SendCode.objects.filter(phone=phone).last() if obj: if code == obj.code: # 验证通过 consumer_queryset = Consumer.objects.filter(username=phone) if consumer_queryset.exists(): # 是否存在 consumer = consumer_queryset.first() if consumer.openid: return Response({'error':'该号码已使用!'}) openid = request.user.openid request.user.delete() # 删除 consumer.openid = openid if avatar and nickname: consumer.avatar = avatar consumer.nickname = nickname if consumer.role and consumer.role.name == '游客': consumer.role = ConsumerRole.objects.get(name='注册用户') consumer.save() return Response(status=status.HTTP_200_OK) else: consumer = request.user consumer.username = phone if avatar and nickname: consumer.avatar = avatar consumer.nickname = nickname if consumer.role and consumer.role.name == '游客': consumer.role = ConsumerRole.objects.get(name='注册用户') consumer.save() return Response(status=status.HTTP_200_OK) else: return Response({'error':'验证码错误!'}) else: return Response({'error':'认证错误!'}) else: return Response({'error':'信息不全!'}) class change_remain_count(APIView): perms_map=[{'*':'change_remain_count'}] def get(self, request, *args, **kwargs): # count = request.query_params.get('count', None) # if count: for i in Consumer.objects.all(): i.remain_count = i.remain_count + 2 i.save() return Response(status=status.HTTP_200_OK)