diff --git a/apps/auth1/services.py b/apps/auth1/services.py new file mode 100644 index 00000000..a75e9d64 --- /dev/null +++ b/apps/auth1/services.py @@ -0,0 +1,11 @@ +from django.core.cache import cache +from rest_framework.exceptions import ParseError + + +def check_phone_code(phone, code, raise_exception=True): + code_exist = cache.get(phone, None) + if code_exist == code: + return True + if raise_exception: + raise ParseError('验证码错误') + return False diff --git a/apps/auth1/views.py b/apps/auth1/views.py index 2a622b19..6f6fc462 100755 --- a/apps/auth1/views.py +++ b/apps/auth1/views.py @@ -13,6 +13,7 @@ import json from django.conf import settings from rest_framework_simplejwt.tokens import RefreshToken from django.core.cache import cache +from apps.auth1.services import check_phone_code from apps.utils.sms import send_sms from apps.utils.tools import rannum from apps.utils.wxmp import wxmpClient @@ -181,11 +182,9 @@ class CodeLogin(CreateAPIView): def post(self, request): phone = request.data['phone'] code = request.data['code'] - code_exist = cache.get(phone, None) - if code_exist == code: - user = User.objects.filter(phone=phone).first() - if user: - ret = get_tokens_for_user(user) - return Response(ret) - raise ParseError('账户不存在或已禁用') - raise ParseError('验证码错误') + check_phone_code(phone, code) + user = User.objects.filter(phone=phone).first() + if user: + ret = get_tokens_for_user(user) + return Response(ret) + raise ParseError('账户不存在或已禁用') diff --git a/apps/develop/tasks.py b/apps/develop/tasks.py index 86779f65..4ae24db9 100755 --- a/apps/develop/tasks.py +++ b/apps/develop/tasks.py @@ -56,11 +56,3 @@ def backup_media(): 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 diff --git a/apps/develop/views.py b/apps/develop/views.py index 952ee1b6..af4ab2fd 100755 --- a/apps/develop/views.py +++ b/apps/develop/views.py @@ -5,7 +5,7 @@ from rest_framework.response import Response 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 apps.develop.tasks import backup_database, backup_media, 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 @@ -15,6 +15,7 @@ from django.core.cache import cache import requests from apps.utils.viewsets import CustomGenericViewSet +from apps.utils.wx import wxClient # Create your views here. @@ -153,11 +154,8 @@ class TestViewSet(CustomGenericViewSet): 微信模板消息发送测试 """ - wx_token = cache.get('wx_token', None) - if not wx_token: - wx_token = get_wx_token() data = { - "touser": 'ocAnm5vab6QGOnf2dqpuUZGJ0xyw', + "touser": "ocAnm5vab6QGOnf2dqpuUZGJ0xyw", "template_id": "wczl-hB_bs8CpxwO8_KZuogSTPFXqhBxf8C5HjKl2M4", "url": "http://weixin.qq.com/download", # "miniprogram":{ @@ -172,5 +170,5 @@ class TestViewSet(CustomGenericViewSet): }, } } - 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'}) + res = wxClient.send_tem_msg(data=data) + return Response(res) diff --git a/apps/hrm/migrations/0005_alter_employee_phone.py b/apps/hrm/migrations/0005_alter_employee_phone.py new file mode 100644 index 00000000..bcdd7fe3 --- /dev/null +++ b/apps/hrm/migrations/0005_alter_employee_phone.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2022-07-28 10:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hrm', '0004_alter_employee_phone'), + ] + + operations = [ + migrations.AlterField( + model_name='employee', + name='phone', + field=models.CharField(blank=True, max_length=11, null=True, unique=True, verbose_name='手机号'), + ), + ] diff --git a/apps/hrm/models.py b/apps/hrm/models.py index c871515f..714a2c61 100755 --- a/apps/hrm/models.py +++ b/apps/hrm/models.py @@ -24,7 +24,7 @@ class Employee(CommonBModel): verbose_name='系统账号', on_delete=models.PROTECT, null=True, blank=True) name = models.CharField('姓名', max_length=20) - phone = models.CharField('手机号', max_length=11, null=True, blank=True) + phone = models.CharField('手机号', max_length=11, null=True, blank=True, unique=True) email = models.EmailField('邮箱号', null=True, blank=True) number = models.CharField('人员编号', max_length=50, null=True, blank=True) photo = models.CharField('证件照', max_length=1000, null=True, blank=True) diff --git a/apps/hrm/serializers.py b/apps/hrm/serializers.py index ffe7252c..c3e37dba 100755 --- a/apps/hrm/serializers.py +++ b/apps/hrm/serializers.py @@ -26,13 +26,13 @@ class EmployeeSimpleSerializer(CustomModelSerializer): fields = ['id', 'type', 'name', 'belong_dept', 'belong_dept_name', 'post', 'post_name', 'photo', 'third_info'] -class EmployeeBaseSerializer(CustomModelSerializer): - def save(self, **kwargs): - if self.validated_data.get('user', None): - user = self.validated_data['user'] - self.validated_data['name'] = user.name - self.validated_data['belong_dept'] = user.belong_dept - return super().save(**kwargs) +# class EmployeeBaseSerializer(CustomModelSerializer): +# def save(self, **kwargs): +# if self.validated_data.get('user', None): +# user = self.validated_data['user'] +# self.validated_data['name'] = user.name +# self.validated_data['belong_dept'] = user.belong_dept +# return super().save(**kwargs) def phone_check(phone): @@ -42,21 +42,15 @@ def phone_check(phone): return phone -class EmployeeImproveSerializer(CustomModelSerializer): - class Meta: - model = Employee - fields = ['phone', 'email'] - - -class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer): - phone = serializers.CharField(label="手机号") +class EmployeeCreateUpdateSerializer(CustomModelSerializer): class Meta: model = Employee exclude = EXCLUDE_FIELDS + ['is_atwork', 'last_check_time', - 'not_work_remark', 'third_info', 'type'] + 'not_work_remark', + 'third_info', + 'type', 'name', 'phone', 'belong_dept', 'post', 'user'] extra_kwargs = { - 'phone': {'required': True}, 'number': {'required': True}, 'photo': {'required': True}, 'id_number': {'required': True}, @@ -77,13 +71,20 @@ class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer): return instance +class EmployeeImproveSerializer(CustomModelSerializer): + class Meta: + model = Employee + fields = ['photo', 'id_number', 'email', 'gender', 'signature'] + + class ChannelAuthoritySerializer(serializers.Serializer): pks = serializers.ListField(child=serializers.CharField(max_length=20), label="员工ID列表") channels = serializers.ListField(child=serializers.CharField(max_length=20), label="门通道ID列表") -class EmployeeSerializer(EmployeeBaseSerializer): +class EmployeeSerializer(CustomModelSerializer): belong_dept_ = DeptSimpleSerializer(source='belong_dept', read_only=True) + user_ = UserSimpleSerializer(source='user', read_only=True) belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) post_name = serializers.CharField(source='post.name', read_only=True) blt_ = serializers.SerializerMethodField() diff --git a/apps/hrm/signals.py b/apps/hrm/signals.py index 19e63d3c..3699c9c5 100755 --- a/apps/hrm/signals.py +++ b/apps/hrm/signals.py @@ -19,4 +19,7 @@ def updateEmployee(sender, instance, created, **kwargs): if not ep_created: ep.belong_dept = instance.belong_dept ep.post = instance.post + if instance.phone != ep.phone: + ep.phone = instance.phone + ep.save() ep.save() diff --git a/apps/hrm/views.py b/apps/hrm/views.py index 7a31b74b..235789d7 100755 --- a/apps/hrm/views.py +++ b/apps/hrm/views.py @@ -19,6 +19,7 @@ from apps.hrm.serializers import (CertificateCreateUpdateSerializer, Certificate EmployeeNotWorkRemarkSerializer, EmployeeSerializer, NotWorkRemarkListSerializer) +from apps.hrm.services import HrmService from apps.third.clients import dhClient from apps.third.tapis import dhapis @@ -79,9 +80,6 @@ class EmployeeViewSet(CustomModelViewSet): serializer = EmployeeImproveSerializer(instance=ep, data=request.data) serializer.is_valid(raise_exception=True) serializer.save() - if ep.phone: - user.phone = ep.phone - user.save() return Response() @action(methods=['post'], detail=True, perms_map={'post': 'employee.notworkremark'}, diff --git a/apps/rpm/serializers.py b/apps/rpm/serializers.py index 349506fb..f09075ef 100644 --- a/apps/rpm/serializers.py +++ b/apps/rpm/serializers.py @@ -57,7 +57,9 @@ class RpartySimpleSerializer(CustomModelSerializer): class RpartyAssignSerializer(serializers.Serializer): - username = serializers.CharField(label='用户名') + name = serializers.CharField(label="姓名") + phone = serializers.CharField(label="手机号") + username = serializers.CharField(label="账号") class RfileListSerializer(CustomModelSerializer): diff --git a/apps/rpm/services.py b/apps/rpm/services.py index 6648f688..2a043d03 100644 --- a/apps/rpm/services.py +++ b/apps/rpm/services.py @@ -1,9 +1,12 @@ from threading import Thread +from apps.hrm.errors import PHONE_EXIST from apps.hrm.models import Certificate, Employee from apps.hrm.services import HrmService +from apps.system.models import User, UserPost from apps.wf.models import Ticket, Transition from apps.rpm.models import Rcertificate, Rfile, Rpj, Rpjcertificate, Rpjfile, Rpjmember - +from rest_framework.exceptions import ParseError +from django.contrib.auth.hashers import make_password def bind_rpj(ticket: Ticket, transition: Transition, new_ticket_data: dict): rpj = Rpj.objects.get(id=new_ticket_data['rpj']) @@ -20,6 +23,7 @@ def bind_rpj(ticket: Ticket, transition: Transition, new_ticket_data: dict): def rpj_audit_end(ticket): rpj = Rpj.objects.get(ticket=ticket) + rpj_dept = rpj.rparty.dept # 更新入厂项目人员库 for i in Rpjmember.objects.filter(rpj=rpj): rep = i.remployee @@ -35,6 +39,27 @@ def rpj_audit_end(ticket): ep.type = 'remployee' ep.belong_dept = rpj.rparty.dept ep.save() + # 给相关方人员创建账户 + user = ep.user + if user: # 如果该人员有账户 + pass + else: + user_e = User() + user_e.name = rep.name + user_e.phone = rep.phone + user_e.type = 'remployee' + user_e.password = make_password('0000') + user_e.save() + ep.user = user_e + ep.save() + + # 账号划给部门 + UserPost.objects.get_or_create(user=ep.user, dept=rpj_dept, + defaults={ + 'user': ep.user, + 'dept': rpj_dept + }) + # 回写 rep.employee = ep rep.rpj = rpj # 更新当前入厂项目 rep.save() @@ -56,7 +81,7 @@ def rpj_audit_end(ticket): ct.file = i.file ct.employee = i.rpj_member.remployee.employee ct.save() - # 更新相关方资料库 + # 更新相关方资料库后续可从资料库里选择 for i in Rpjfile.objects.filter(rpj=rpj): rf = Rfile.objects.filter(file_cate=i.file_cate, rparty=i.rpj.rparty).first() if rf: diff --git a/apps/rpm/views.py b/apps/rpm/views.py index 06169670..da82981c 100644 --- a/apps/rpm/views.py +++ b/apps/rpm/views.py @@ -4,6 +4,7 @@ from apps.hrm.serializers import CertificateCreateUpdateSerializer, CertificateS from apps.rpm.models import Rcertificate, Remployee, Rparty, Rfile, Rpjfile, Rpjmember, Rpj from apps.rpm.serializers import RcertificateCreateUpdateSerializer, RcertificateSerializer, RemployeeCreateSerializer, RemployeeSerializer, RpartyAssignSerializer, RpartyCreateUpdateSerializer, RfileListSerializer, RpartySerializer, RpjListSerializer, RpjfileSerializer, RpjfileUpdateSerializer, RpjmemberCreateSerializer, RpjmemberCreatesSerializer, RpjCreateUpdateSerializer, RpjmemberSerializer, RpjmemberUpdateSerializer from apps.system.models import Dictionary, Post, User, UserPost +from apps.system.serializers import UserCreateSerializer from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin from apps.utils.mixins import CustomDestoryModelMixin @@ -32,13 +33,10 @@ class RpartyViewSet(CustomModelViewSet): obj = self.get_object() if obj.admin: raise ParseError('已存在管理员账号') - username = request.data.get('username') - password = make_password('0000') - user = User.objects.create(username=username, - password=password, - type='remployee', - belong_dept=obj.dept) - obj.admin = user + serializer = UserCreateSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + ins = serializer.save(type='remployee') + obj.admin = ins obj.save() return Response() diff --git a/apps/system/migrations/0005_alter_userpost_post.py b/apps/system/migrations/0005_alter_userpost_post.py new file mode 100644 index 00000000..edd8c94b --- /dev/null +++ b/apps/system/migrations/0005_alter_userpost_post.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.12 on 2022-07-28 10:58 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0004_auto_20220724_1305'), + ] + + operations = [ + migrations.AlterField( + model_name='userpost', + name='post', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='up_post', to='system.post'), + ), + ] diff --git a/apps/system/models.py b/apps/system/models.py index 5e30f590..f5ef5e2a 100755 --- a/apps/system/models.py +++ b/apps/system/models.py @@ -157,7 +157,7 @@ class UserPost(BaseModel): """ name = models.CharField('名称', max_length=20, null=True, blank=True) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='up_user') - post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='up_post') + post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='up_post', null=True, blank=True) dept = models.ForeignKey(Dept, on_delete=models.CASCADE, related_name='up_dept') sort = models.PositiveSmallIntegerField('排序', default=1) diff --git a/apps/system/serializers.py b/apps/system/serializers.py index 71fbf875..ff5b39a6 100755 --- a/apps/system/serializers.py +++ b/apps/system/serializers.py @@ -2,6 +2,7 @@ from django_celery_beat.models import PeriodicTask, CrontabSchedule, IntervalSchedule from rest_framework import serializers from django_celery_results.models import TaskResult +from apps.hrm.errors import PHONE_EXIST from apps.system.errors import USERNAME_EXIST from apps.utils.serializers import CustomModelSerializer from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE @@ -297,7 +298,7 @@ class UserListSerializer(CustomModelSerializer): 用户列表序列化 """ belong_dept_ = DeptSimpleSerializer(source='belong_dept', read_only=True) - posts_ = PostSimpleSerializer(source='posts', many=True) + # posts_ = PostSimpleSerializer(source='posts', many=True) class Meta: model = User @@ -309,9 +310,10 @@ class UserListSerializer(CustomModelSerializer): # raise serializers.ValidationError(**PHONE_F_WRONG) # return phone -# def phone_exist(phone): -# if User.objects.filter(phone=phone).exists(): -# raise serializers.ValidationError(**PHONE_EXIST) + +def phone_exist(phone): + if User.objects.filter(phone=phone).exists(): + raise serializers.ValidationError(**PHONE_EXIST) def user_exist(username): @@ -340,6 +342,7 @@ class UserCreateSerializer(CustomModelSerializer): 创建用户序列化 """ username = serializers.CharField(required=True, validators=[user_exist]) + phone = serializers.CharField(required=False, validators=[phone_exist]) class Meta: model = User diff --git a/apps/system/views.py b/apps/system/views.py index 67be354e..05a7b8fc 100755 --- a/apps/system/views.py +++ b/apps/system/views.py @@ -403,7 +403,7 @@ class UserViewSet(CustomModelViewSet): filterset_class = UserFilterSet search_fields = ['username', 'name', 'phone', 'email'] select_related_fields = ['superior', 'belong_dept'] - prefetch_related_fields = ['posts'] + prefetch_related_fields = ['posts', 'roles', 'depts'] def filter_queryset(self, queryset): if not self.detail: diff --git a/apps/third/serializers.py b/apps/third/serializers.py index 51df2493..ef400238 100755 --- a/apps/third/serializers.py +++ b/apps/third/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from apps.am.models import Area -from apps.hrm.serializers import EmployeeBaseSerializer, EmployeeSimpleSerializer +from apps.hrm.serializers import EmployeeSimpleSerializer from apps.third.models import BltBind, TDevice, Tlog from apps.utils.serializers import CustomModelSerializer from django.db import transaction diff --git a/apps/utils/permission.py b/apps/utils/permission.py index 3888c9be..0ce35149 100755 --- a/apps/utils/permission.py +++ b/apps/utils/permission.py @@ -17,7 +17,7 @@ def get_user_perms_map(user): if user.is_superuser: user_perms_map = {'superuser': None} else: - objs = UserPost.objects.filter(user=user) + objs = UserPost.objects.filter(user=user).exclude(post=None) for i in objs: dept_id = str(i.dept.id) for pr in PostRole.objects.filter(post=i.post): diff --git a/apps/utils/wx.py b/apps/utils/wx.py index 843d67da..b43d77ae 100644 --- a/apps/utils/wx.py +++ b/apps/utils/wx.py @@ -1,7 +1,9 @@ +from django.core.cache import cache import json import time from threading import Thread import uuid +from async_timeout import timeout import requests from django.conf import settings @@ -13,7 +15,6 @@ 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') @@ -29,7 +30,7 @@ class WxClient: self.app_id = app_id self.app_secret = app_secret self.isRuning = True - self.token = None + self.token = cache.get(self.app_id + '_token', None) # 普通token self.t = None # 线程 self.log = {} self.setup() @@ -43,7 +44,8 @@ class WxClient: } _, ret = self.request(url='/cgi-bin/token', params=parmas, method='get') self.token = ret['access_token'] - time.sleep(3600) + cache.set(self.app_id + '_token', self.token, timeout=3600) + time.sleep(4000) def setup(self): t = Thread(target=self._get_token_loop, args=(), daemon=True) @@ -127,5 +129,13 @@ class WxClient: _, res = self.request('/sns/oauth2/access_token', params=params, method='get') return res + def send_tem_msg(self, data: dict): + """发送模板消息 + """ + + _, res = self.request('/cgi-bin/message/template/send', + params={'access_token': self.token}, json=data, method='post') + return res + wxClient = WxClient() diff --git a/apps/vm/serializers.py b/apps/vm/serializers.py index 87182fad..1d80d3b4 100644 --- a/apps/vm/serializers.py +++ b/apps/vm/serializers.py @@ -81,7 +81,8 @@ class VpeopleSerializer(CustomModelSerializer): class VisitorRegisterSerializer(serializers.Serializer): name = serializers.CharField(label="姓名") - username = serializers.CharField(label="账户名", required=False) + phone = serializers.CharField(label="手机号") + code = serializers.CharField(label='手机号验证码') wxmp_openid = serializers.CharField(label='微信小程序ID', required=False) wx_openid = serializers.CharField(label='微信公众号ID', required=False) diff --git a/apps/vm/services.py b/apps/vm/services.py index 506a12db..0711ae94 100644 --- a/apps/vm/services.py +++ b/apps/vm/services.py @@ -27,6 +27,8 @@ def visit_audit_end(ticket): visitor = i.visitor if visitor.id_number and visitor.photo: ep = Employee.objects.filter(id_number=visitor.id_number).first() + elif visitor.phone: + ep = Employee.objects.filter(phone=visitor.phone).first() else: ep = Employee.objects.filter(name=visitor.name, id_number=None).first() if ep: diff --git a/apps/vm/views.py b/apps/vm/views.py index 7b5ccc43..10005236 100644 --- a/apps/vm/views.py +++ b/apps/vm/views.py @@ -1,6 +1,9 @@ from django.shortcuts import render +from apps.auth1.services import check_phone_code +from apps.auth1.views import get_tokens_for_user from apps.hrm.models import Employee from apps.system.models import User +from apps.utils.tools import ranstr from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet, GenericViewSet from apps.vm.models import Visit, Visitor, Vpeople from apps.vm.serializers import VisitCreateUpdateSerializer, VisitDetailSerializer, VisitSerializer, VisitorCreateSerializer, VisitorRegisterSerializer, VisitorSerializer, VpeopleCreateSerializer, VpeopleSerializer @@ -67,6 +70,7 @@ class VisitorViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Custo @action(methods=['post'], detail=False, authentication_classes=[], permission_classes=[], serializer_class=VisitorRegisterSerializer) + @transaction.atomic def register(self, request, *args, **kwargs): """访客账户注册 @@ -75,21 +79,24 @@ class VisitorViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Custo serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data - if vdata.get('username', None): # 如果是用户名注册 - user = User.objects.get_queryset(all=True).filter(username=vdata['username']).first() - if user: - raise ParseError('账号已存在或禁用不可注册') - else: - password = make_password('0000') - user = User.objects.create(name=vdata['name'], - username=vdata['username'], - type='visitor', - password=password) - return Response({'user': user.id}, status=201) - elif vdata.get('wxmp_openid', None): # 如果是微信小程序注册 - pass - elif vdata.get('wx_openid', None): # 如果是微信公众号注册 - pass + name = vdata['name'] + phone = vdata['phone'] + code = vdata['code'] + check_phone_code(phone, code) + # 查询是否已注册 + user = User.objects.filter(phone=phone).first() + if user: + raise ParseError('该手机号已注册,请直接登录') + user = User() + user.type = 'visitor' + user.name = name + user.username = 'V_' + ranstr(10) + user.phone = phone + user.password = make_password('0000') + user.wx_openid = vdata.get('wx_openid', None) + user.wxmp_openid = vdata.get('wxmp_openid', None) + user.save() + return Response(get_tokens_for_user(user)) class VpeopleViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, CustomGenericViewSet):