import datetime import logging import logging import os import random import re import time import traceback import uuid from django.contrib.auth.hashers import make_password from django.db import transaction from django.db.models import Q from django_filters.rest_framework import DjangoFilterBackend from django_redis import get_redis_connection from operator import itemgetter from rest_framework.decorators import action from rest_framework.filters import SearchFilter, OrderingFilter from rest_framework.generics import ListAPIView from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView from rest_framework_jwt.authentication import JSONWebTokenAuthentication # from django.contrib.auth import authenticate from rest_framework_jwt.settings import api_settings # APPID_MP, SECRET_MP, \ # AuthorizationWX_URL, CCW_URL, FILE_HTTP, from ChaCeRndTrans import settings from ChaCeRndTrans.basic import CCAIResponse from ChaCeRndTrans.code import * from ChaCeRndTrans.settings import RELEASE_DOMAIN, TEST_DOMAIN, MAX_IMAGE_SIZE from rbac.views.message import msg_redis_code from utils.custom import CommonPagination, RbacPermission, CustomViewBase, \ generate_random_str, sha1_encrypt, is_all_chinese, is_valid_username from utils.funcs import generate_random_str from ..models import UserProfile, Menu, Role, Company from ..serializers.menu_serializer import MenuSerializer from ..serializers.user_serializer import UserListSerializer, UserCreateSerializer, UserModifySerializer, \ UserInfoListSerializer, CompanySerializer jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER err_logger = logging.getLogger('error') class UserAuthView(APIView): """ 用户认证获取token """ def post(self, request, *args, **kwargs): try: # type 登录类型 1:免密登录 2:账号登录 type = request.data.get("type", None) if type is None: return CCAIResponse(data="缺少必要参数", msg="缺少必要参数", status=BAD) if type == 1: mobile = request.data.get("telephone") verifycode = request.data.get("verifycode") if mobile == '' or mobile is None: return CCAIResponse("手机号不能为空!", status=BAD) if verifycode == '' or verifycode is None: return CCAIResponse("验证码不能为空!", status=BAD) user = UserProfile.objects.filter(mobile=mobile, is_active=1).first() if user is not None: try: conn = get_redis_connection('default') key = msg_redis_code + mobile code = conn.hget(key, 'code') count = conn.hget(key, 'count') if code is None: return CCAIResponse(data="验证码失效,请重新获取!", msg="验证码失效,请重新获取!", status=BAD) elif code.decode('utf8') != verifycode: if count is None: conn.hset(key, 'count', 1) else: count = int(count.decode('utf8')) + 1 if count < 5: conn.hset(key, 'count', count) else: conn.delete(key) return CCAIResponse(data="验证码有误!", msg="验证码有误!", status=VERIFYCODE_ERROR) else: # 验证码,验证通过 payload = jwt_payload_handler(user) if 'user_id' in payload: payload.pop('user_id') return CCAIResponse(data={"token": jwt_encode_handler(payload)}, status=OK) except Exception as e: err_logger.error( "user: %s, connect redis failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse(data="手机号登录失败!", msg="手机号登录失败!", status=BAD) else: user = UserProfile.objects.filter(mobile=mobile).first() if user: if user.is_active == 1: return CCAIResponse(data="根据相关法律规定,账号需要绑定手机号,请输入账号密码进行绑定!", status="根据相关法律规定,账号需要绑定手机号,请输入账号密码进行绑定!", code=BAD) else: return CCAIResponse(data="用户未激活!", msg="用户未激活!", status=BAD) else: return CCAIResponse( data="该手机号未注册,请点击下方“立即注册”按钮进行注册!", msg="该手机号未注册,请点击下方“立即注册”按钮进行注册!", status=BAD ) else: username = request.data.get("username", None) password = request.data.get("password", None) if not username: return CCAIResponse(data="请输入用户名,手机号或邮箱!", status=BAD) if not password: return CCAIResponse(data="请输入密码", status=BAD) if username: # 查询用户 # 此处可能会有问题,A用户的账号为B用户的手机号,故账号设置需要有复杂度 user = UserProfile.objects.filter(Q(username=username) | Q(email=username) | Q(mobile=username)).first() if user: if user.check_password(password): if user.is_active: payload = jwt_payload_handler(user) if 'user_id' in payload: payload.pop('user_id') return CCAIResponse({"token": jwt_encode_handler(payload)}, status=OK) else: return CCAIResponse(data="用户被锁定,请等待联系管理员。", msg="用户被锁定,请等待联系管理员。", status=BAD) else: return CCAIResponse(data="用户名或密码错误", msg="用户名或密码错误!", status=BAD) else: # 用户不存在 return CCAIResponse(data="用户名或密码错误", msg="用户名或密码错误!", status=BAD) except Exception as e: err_logger.error("user login failed: \n%s" % traceback.format_exc()) return CCAIResponse(msg="用户名或密码错误!", status=SERVER_ERROR) class UserInfoView(APIView): authentication_classes = (JSONWebTokenAuthentication,) permission_classes = (IsAuthenticated,) """ 获取当前用户信息和权限 """ @classmethod def get_permission_from_role(self, request, companyMid=None): """ 根据用户角色与公司id,返回对应的权限 """ try: if request.user: perms_list = [] # for item in request.user.roles.values("permissions__method").distinct(): # perms_list.append(item["permissions__method"]) if not companyMid: for item in request.user.roles.values("permissions__method").distinct(): perms_list.append(item["permissions__method"]) else: for item in request.user.roles.filter(Q(companyMid=companyMid) | Q(companyMid__isnull=True)).values("permissions__method").distinct(): perms_list.append(item["permissions__method"]) return perms_list except AttributeError: return None @classmethod def get_company_from_user(self, request): try: if request.user: if 2 == request.user.label: # 后台内部人员可以查看所有公司 company_list = Company.objects.all() else: company_list = request.user.company.all() return CompanySerializer(company_list, many=True).data except AttributeError: return None def get(self, request): try: companyMid = request.GET.get("companyMid") checkIn = None company = None if companyMid: if not Company.objects.filter(MainId=companyMid).exists(): return CCAIResponse("公司不存在", status=BAD) else: checkIn = Company.objects.filter(MainId=companyMid).values("checkIn").first()['checkIn'] company = Company.objects.filter(MainId=companyMid).values("AmStart", "AmEnd", "PmStart", "PmEnd", "tolerance").first() # else: # companyMid = request.user.companyMid if request.user.id is not None: company_list = self.get_company_from_user(request) if companyMid is None: checkIn = company_list[0]['checkIn'] company = company_list[0] perms = self.get_permission_from_role(request, companyMid) data = { "id": request.user.id, "username": request.user.username, "name": request.user.name, "avatar": request.user.image if request.user.image else "/upload/logo/default.jpg", "mobile": request.user.mobile, "email": request.user.email, "is_active": request.user.is_active, "createTime": request.user.date_joined, "roles": perms, "is_superuser": request.user.is_superuser, "area_code": request.user.area_code, "area_name": request.user.area_name, "is_sub": request.user.is_sub, # 1:子账号;2:主账号 "nowcompany": companyMid if companyMid else company_list[0]['MainId'], "checkIn": checkIn, "AmStart": company["AmStart"], "AmEnd": company["AmEnd"], "PmStart": company["PmStart"], "PmEnd": company["PmEnd"], "tolerance": company["tolerance"], "company": company_list, } return CCAIResponse(data=data, status=OK) else: return CCAIResponse("请登录后访问!", status=FORBIDDEN) except Exception as e: err_logger.error("get permission from role failed: \n%s" % traceback.format_exc()) return CCAIResponse(msg="获取当前用户信息和权限失败!", status=SERVER_ERROR) class UserBuildMenuView(APIView): """ 绑定当前用户,绑定当前公司的菜单信息 """ def get_menu_from_role(self, request): menu_dict = {} try: if request.user: companyMid = request.GET.get('companyMid') if not companyMid: menus = request.user.roles.values( "menus__id", "menus__name", "menus__route_name", "menus__path", "menus__is_frame", "menus__is_show", "menus__component", "menus__icon", "menus__sort", "menus__pid" ).distinct().order_by("menus__sort") else: menus = request.user.roles.filter(Q(companyMid=companyMid) | Q(companyMid__isnull=True)).values( "menus__id", "menus__name", "menus__route_name", "menus__path", "menus__is_frame", "menus__is_show", "menus__component", "menus__icon", "menus__sort", "menus__pid" ).distinct().order_by("menus__sort") # 获取公司打卡方案 company = Company.objects.filter(MainId=companyMid).first() companyCheckIn = company.checkIn for item in menus: # 如果公司打卡方案是A不展示B方案工时菜单 if item["menus__pid"] is None: if item["menus__is_frame"]: # 判断是否外部链接 top_menu = { "id": item["menus__id"], "path": item["menus__path"], "component": "Layout", "children": [{ "path": item["menus__path"], "meta": { "title": item["menus__name"], "icon": item["menus__icon"] } }], "pid": item["menus__pid"], "sort": item["menus__sort"] } else: top_menu = { "id": item["menus__id"], "name": item["menus__route_name"], "path": "/" + item["menus__path"], "redirect": "noredirect", "component": "Layout", "alwaysShow": True, "meta": { "title": item["menus__name"], "icon": item["menus__icon"] }, "pid": item["menus__pid"], "sort": item["menus__sort"], "children": [] } menu_dict[item["menus__id"]] = top_menu else: if item["menus__is_frame"]: children_menu = { "id": item["menus__id"], "name": item["menus__route_name"], "path": item["menus__path"], "component": "Layout", "meta": { "title": item["menus__name"], "icon": item["menus__icon"], }, "pid": item["menus__pid"], "sort": item["menus__sort"] } elif item["menus__is_show"]: children_menu = { "id": item["menus__id"], "name": item["menus__route_name"], "path": item["menus__path"], "component": item["menus__component"], "meta": { "title": item["menus__name"], "icon": item["menus__icon"], }, "pid": item["menus__pid"], "sort": item["menus__sort"] } else: children_menu = { "id": item["menus__id"], "name": item["menus__route_name"], "path": item["menus__path"], "component": item["menus__component"], "meta": { "title": item["menus__name"], "noCache": True, }, "hidden": True, "pid": item["menus__pid"], "sort": item["menus__sort"] } menu_dict[item["menus__id"]] = children_menu return menu_dict except Exception as e: err_logger.error("get menu from role failed: \n%s" % traceback.format_exc()) return menu_dict def get_all_menu_dict(self): """ 获取所有菜单数据,重组结构 """ try: menus = Menu.objects.all().order_by('sort') serializer = MenuSerializer(menus, many=True) tree_dict = {} for item in serializer.data: if item["pid"] is None: if item["is_frame"]: # 判断是否外部链接 top_menu = { "id": item["id"], "path": item["path"], "component": "Layout", "children": [{ "path": item["path"], "meta": { "title": item["name"], "icon": item["icon"] } }], "pid": item["pid"], "sort": item["sort"] } else: top_menu = { "id": item["id"], "name": item["route_name"], "path": "/" + item["path"], "redirect": "noredirect", "component": "Layout", "alwaysShow": True, "meta": { "title": item["name"], "icon": item["icon"] }, "pid": item["pid"], "sort": item["sort"], "children": [] } tree_dict[item["id"]] = top_menu else: if item["is_frame"]: children_menu = { "id": item["id"], "name": item["route_name"], "path": item["path"], "component": "Layout", "meta": { "title": item["name"], "icon": item["icon"], }, "pid": item["pid"], "sort": item["sort"] } elif item["is_show"]: children_menu = { "id": item["id"], "name": item["route_name"], "path": item["path"], "component": item["component"], "meta": { "title": item["name"], "icon": item["icon"], }, "pid": item["pid"], "sort": item["sort"] } else: children_menu = { "id": item["id"], "name": item["route_name"], "path": item["path"], "component": item["component"], "meta": { "title": item["name"], "noCache": True, }, "hidden": True, "pid": item["pid"], "sort": item["sort"] } tree_dict[item["id"]] = children_menu return tree_dict except Exception as e: err_logger.error("get all menu from role failed: \n%s" % traceback.format_exc()) return tree_dict def get_all_menus(self, request): try: perms = UserInfoView.get_permission_from_role(request) tree_data = [] if "admin" in perms or request.user.is_superuser: tree_dict = self.get_all_menu_dict() else: tree_dict = self.get_menu_from_role(request) for i in tree_dict: if tree_dict[i]["pid"]: pid = tree_dict[i]["pid"] try: parent = tree_dict[pid] except KeyError as e: # 缺少父级菜单 continue parent.setdefault("redirect", "noredirect") parent.setdefault("alwaysShow", True) parent.setdefault("children", []).append(tree_dict[i]) parent["children"] = sorted(parent["children"], key=itemgetter("sort")) else: tree_data.append(tree_dict[i]) return tree_data except Exception as e: err_logger.error("get all menu failed: \n%s" % traceback.format_exc()) return tree_data def get(self, request): try: if request.user.id is not None: menu_data = self.get_all_menus(request) return CCAIResponse(menu_data, status=OK) else: return CCAIResponse(msg="请登录后访问!", status=FORBIDDEN) except Exception as e: err_logger.error("get all menu failed: \n%s" % traceback.format_exc()) return CCAIResponse([], status=OK) class UserViewSet(CustomViewBase): """ 用户管理:增删改查 """ perms_map = ( {"*": "admin"}, {"*": "user_all"}, {"get": "user_list"}, {"post": "user_create"}, {"put": "user_edit"}, {"delete": "user_delete"} ) queryset = UserProfile.objects.all() serializer_class = UserListSerializer pagination_class = CommonPagination filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter) filter_fields = ("is_active", "is_sub") search_fields = ("username", "name", "mobile", "email") ordering_fields = ("id",) authentication_classes = (JSONWebTokenAuthentication,) # permission_classes = (RbacPermission,) def get_serializer_class(self): # 根据请求类型动态变更serializer if self.action == "create": return UserCreateSerializer elif self.action == "list": return UserListSerializer return UserModifySerializer def create(self, request, *args, **kwargs): # 创建用户默认添加密码 try: with transaction.atomic(): data = request.data.copy() password = sha1_encrypt("chacewang123456") data['password'] = password # 生成uuid,并设置到用户中,再create data['MainId'] = uuid.uuid4().__str__() # 用户mid companyname = data.get('companyname') com = Company.objects.filter(name=companyname).first() if com is None: companyMid = uuid.uuid4().__str__() # 公司mid com = Company() com.MainId = companyMid com.name = data.get('companyname') com.EUCC = data.get('eucc') com.userMid = data['MainId'] com.save() else: companyMid = com.MainId data['companyMid'] = companyMid serializer = self.get_serializer(data=data) try: serializer.is_valid(raise_exception=True) except Exception as e: msg = "" count = 0 for k, v in e.detail.items(): count += 1 if count == 2: msg += " 且 " + e.detail[k][0] else: msg += e.detail[k][0] return CCAIResponse(msg=msg, status=BAD) self.perform_create(serializer) user = UserProfile.objects.filter(id=serializer.data['id']).first() if user: # # 为注册用户添加角色 # # 公司管理员(公司的唯一最大权限拥有者)id=2 # role = Role.objects.filter(id=2).first() # if role: # user.roles.add(role) # 添加角色组合 其中角色仅为公司管理员 user.set_password(password) # 为注册用户添加公司 user.company.add(com) user.save() headers = self.get_success_headers(serializer.data) # data = serializer.data return CCAIResponse(data="chacewang123456", status=CREATED, headers=headers) except Exception as e: err_logger.error("create user failed: \n%s" % traceback.format_exc()) return CCAIResponse(msg='创建用户失败', status=SERVER_ERROR) def update(self, request, *args, **kwargs): try: partial = kwargs.pop('partial', False) instance = self.get_object() # 是否封禁用户 is_active = request.data.get('is_active') is_active = True if is_active == "true" else False flag = False if instance.is_active and not is_active: # 操作为封禁 flag = True # 查询是否存在已激活的子账号 subs = UserProfile.objects.filter(is_sub=1, parent_id=instance.id, is_active=1) serializer = self.get_serializer(instance, data=request.data, partial=partial) try: serializer.is_valid(raise_exception=True) except Exception as e: msg = "" count = 0 for k, v in e.detail.items(): count += 1 if count == 2: msg += " 且 " + k + e.detail[k][0] else: msg += k + e.detail[k][0] return CCAIResponse(msg=msg, status=BAD) with transaction.atomic(): self.perform_update(serializer) if flag and subs: subs.update(is_active=0) if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} return CCAIResponse(serializer.data, status=200) except Exception as e: err_logger.error("update user failed: \n%s" % traceback.format_exc()) return CCAIResponse(msg='修改用户失败', status=SERVER_ERROR) def list(self, request, *args, **kwargs): try: queryset = self.filter_queryset(self.get_queryset().filter().all()) page = self.paginate_queryset(queryset) domain = RELEASE_DOMAIN if settings.DEVELOP_DEBUG: domain = TEST_DOMAIN if page is not None: serializer = self.get_serializer(page, many=True) return_data = serializer.data # for item in return_data: # start = item['image'].rindex('/media/') # item['image'] = domain + item['image'][start:] return self.get_paginated_response(return_data) serializer = self.get_serializer(queryset, many=True) return_data = serializer.data for item in return_data: start = item['image'].rindex('/media/') item['image'] = domain + item['image'][start:] return CCAIResponse(data=return_data, status=200) except Exception as e: err_logger.error("get user list failed: \n%s" % traceback.format_exc()) return CCAIResponse(msg='获取用户失败', status=SERVER_ERROR) @action(methods=["post"], detail=True, permission_classes=[IsAuthenticated], url_path="association_company", url_name="association") def association_company(self, request, pk=None): """ 增加或删除账户关联公司,如果账户只剩一个公司,不给删除 """ try: params = request.data type = params.get('type', 1) # 1:增加关联公司 2:删除关联公司 companyId = params.get('companyId') # 对应的公司id if not companyId: return CCAIResponse('Missing param', BAD) instance = self.get_object() # 获取对应用户 company = Company.objects.filter(id=companyId).first() if company: if 1 == int(type): instance.company.add(company) elif 2 == int(type): instance.company.remove(company) else: pass return CCAIResponse('success') else: return CCAIResponse('查找不到公司', BAD) except Exception as e: err_logger.error("user association company failed: \n%s" % traceback.format_exc()) return CCAIResponse(msg='用户关联公司操作失败', status=SERVER_ERROR) @action(methods=["post"], detail=True, permission_classes=[IsAuthenticated], url_path="change-passwd", url_name="change-passwd") def update_password(self, request, pk=None): try: perms = UserInfoView.get_permission_from_role(request) old_password = request.data.get("old_password", "") new_password1 = request.data.get("new_password1", "") new_password2 = request.data.get("new_password2", "") if new_password1 == "" or new_password2 == "": return CCAIResponse("密码不允许为空!", status=status.HTTP_400_BAD_REQUEST) user = UserProfile.objects.get(id=pk if pk else request.user.id) if "admin" in perms or "user_all" in perms or request.user.is_superuser: new_password1 = request.data["new_password1"] new_password2 = request.data["new_password2"] if new_password1 == new_password2: # result_dict = check_password_complexity(new_password1) # if not result_dict["flag"]: # return CCAIResponse(msg=result_dict["message"], status=BAD) user.set_password(new_password2) user.save() return CCAIResponse(data="密码修改成功!", msg="密码修改成功!", status=OK) else: return CCAIResponse(data="新密码两次输入不一致!", msg="新密码两次输入不一致!", status=status.HTTP_400_BAD_REQUEST) else: if old_password: if not request.user.check_password(old_password): return CCAIResponse(data="旧密码错误!", msg="旧密码错误!", status=BAD) if new_password1 == new_password2: if old_password == new_password1: return CCAIResponse(data="新密码和旧密码不能一样!", msg="新密码和旧密码不能一样!", status=BAD) # 判断验证码是否正确 user.set_password(new_password1) user.save() return CCAIResponse(data="修改密码成功!", status=OK) else: return CCAIResponse(data="新密码两次输入不一致!", msg="新密码两次输入不一致!", status=status.HTTP_400_BAD_REQUEST) except Exception as e: err_logger.error("user update password failed: \n%s" % traceback.format_exc()) return CCAIResponse(msg='修改密码失败', status=SERVER_ERROR) # 重置密码 @action(methods=["get"], detail=False, permission_classes=[RbacPermission], url_path="reSetPassword", url_name="reSetPassword") def reSetPassword(self, request): try: user_ids = request.query_params.get('ids', None) if not user_ids: return CCAIResponse("id参数不对啊!", NOT_FOUND) password = "" with transaction.atomic(): user_list = UserProfile.objects.filter(id__in=user_ids.split(",")) for userl in user_list: user = UserProfile.objects.filter(username=userl.username).first() if user: # user.password = password special_str = "*@&%" password = "ccw" + user.mobile[-6:] + special_str[random.randint(0, len(special_str) - 1)] \ + generate_random_str(randomlength=3) password_ = sha1_encrypt(password) user.password = make_password(password_) user.save() return CCAIResponse(data={"pwd": password}, status=OK) except Exception as e: err_logger.error( "user: %s, reset password failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse("重新设置密码失败", SERVER_ERROR) # @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], # url_path="updateAvatar", url_name="updateAvatar") # def updateAvatar(self, request): # try: # avatar = request.FILES.get('avatar', "") # image_type = request.data.get("image_type", "") # # if avatar is None or avatar == '': # return CCAIResponse(data="avatar参数缺失!", status=BAD) # if not image_type: # return CCAIResponse(data="image_type参数缺失!", status=BAD) # if avatar.size > MAX_IMAGE_SIZE: # return CCAIResponse(data="上传文件需小于或等于2M", status=SERVER_ERROR) # # file_name = generate_random_str(12) + "." + image_type # ct = time.time() # 取得系统时间 # local_time = time.localtime(ct) # date_head = time.strftime("%Y%m%d%H%M%S", local_time) # 格式化时间 # date_m_secs = str(datetime.datetime.now().timestamp()).split(".")[-1] # 毫秒级时间戳 # time_stamp = "%s%.3s" % (date_head, date_m_secs) # 拼接时间字符串 # # 本地存储目录 # save_path = os.path.join(settings.FILE_PATH, image_type, time_stamp) # save_path = save_path.replace('\\', '/') # # 前端显示目录 # start = file_name.rindex('.') # show_path = os.path.join(settings.SHOW_UPLOAD_PATH, image_type, time_stamp, file_name) # show_path = show_path.replace('\\', '/') # # 如果不存在则创建目录 # if not os.path.exists(save_path): # os.makedirs(save_path) # os.chmod(save_path, mode=0o777) # # file_path = open(save_path + "/" + file_name, 'wb') # for chunk in avatar.chunks(): # file_path.write(chunk) # file_path.close() # # # 数据库存储路径 # request.user.image = show_path # request.user.save() # return CCAIResponse(status=200, data=show_path) # # except Exception as e: # err_logger.error("user: %s, user update avatar failed: \n%s" % (request.user.id, traceback.format_exc())) # return CCAIResponse(msg='修改头像失败', status=SERVER_ERROR) @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], url_path="updateAvatar", url_name="updateAvatar") def updateAvatar(self, request): """ 不支持用户上传图片 """ try: avatar = request.data.get('avatar') if avatar is None or avatar == '': return CCAIResponse("参数缺失!", BAD) request.user.image = avatar request.user.save() return CCAIResponse("头像修改成功!") except Exception as e: err_logger.error("user: %s, user update avatar failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse('修改头像失败', status=BAD) @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], url_path="change_mobile", url_name="change_mobile") def change_mobile(self, request, pk=None): # 更新手机号 try: user = UserProfile.objects.get(id=request.user.id) params = request.data mobile = params.get("mobile", "") if mobile == None or mobile == '': return CCAIResponse(data="手机号不能为空", msg="手机号不能为空", status=status.HTTP_400_BAD_REQUEST) is_exist = UserProfile.objects.filter(mobile=mobile).first() if is_exist: return CCAIResponse(data="手机号已被绑定", msg="手机号已被绑定", status=BAD) user.mobile = mobile user.save() return CCAIResponse("success") except Exception as e: err_logger.error("user update center mobile failed: \n%s" % traceback.format_exc()) return CCAIResponse(data='手机号修改失败', msg='手机号修改失败', status=SERVER_ERROR) @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], url_path="update_name", url_name="update_name") def update_name(self, request, pk=None): try: params = request.data name = params.get("name", None) # 真实姓名 if name: if len(name) < 2 or len(name) > 5: return CCAIResponse(data="请输入正确的真实名字!", msg="请输入正确的真实名字!", status=BAD) if not is_all_chinese(name): return CCAIResponse(data="格式不对,请输入正确的真实名字!", msg="格式不对,请输入正确的真实名字!", status=BAD) request.user.name = name request.user.save() return CCAIResponse(data="修改姓名成功!", msg='修改姓名成功!', status=OK) else: return CCAIResponse(data='真实姓名不能为空!', msg='真实姓名不能为空!', status=BAD) except Exception as e: err_logger.error( "user: %s update name failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse(msg='完善个人信息失败', status=SERVER_ERROR) @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], url_path="updateInfo", url_name="updateInfo") def updateInfo(self, request): try: params = request.data name = params.get("name", "") # 真实姓名 area_code = params.get("area_code", None) area_dict = params.get("area", None) # 地区字典 # if area_dict == None or area_dict == "": # return CCAIResponse("area参数不能为空!", status=status.HTTP_400_BAD_REQUEST) if not name: return CCAIResponse(msg="真实姓名不能为空!", status=BAD) request.user.name = name if area_dict: request.user.area_code = area_dict["value"] request.user.area_name = area_dict['label'] request.user.last_login = datetime.datetime.now() request.user.save() return CCAIResponse("success") except Exception as e: err_logger.error( "user: %s update user information failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse(msg='完善个人信息失败', status=SERVER_ERROR) @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], url_path="change_username", url_name="change_username") def change_name(self, request, pk=None): try: # user = UserProfile.objects.get(id=request.user.id) params = request.data username = params.get("username", None) if not username: return CCAIResponse(data="用户名不能为空", msg="用户名不能为空", status=status.HTTP_400_BAD_REQUEST) if not is_valid_username(username): return CCAIResponse(data="用户名格式不对,只能输入汉字,英文字母,数字!", msg="用户名格式不对,只能输入汉字,英文字母,数字!", status=BAD) is_exist = UserProfile.objects.filter(username=username).first() if is_exist: return CCAIResponse(data="用户名已被使用,请重新修改", msg="用户名已被使用,请重新修改", status=BAD) request.user.username = username request.user.save() return CCAIResponse(data="用户名修改成功!", msg="用户名修改成功!", status=OK) except Exception as e: err_logger.error("user: %s change user username failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse(msg='用户名修改失败', status=SERVER_ERROR) @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], url_path="update_email", url_name="update_email") def update_email(self, request, pk=None): try: params = request.data email = params.get("email", "") if email == None or email == '': return CCAIResponse("email参数不能为空!", status=status.HTTP_400_BAD_REQUEST) ret = re.match(r'^\w+@(\w+.)+(com|cn|net)$', email) if ret: email_exist = UserProfile.objects.filter(email=email).count() if email_exist > 0: return CCAIResponse("该Email已被注册!", status=status.HTTP_400_BAD_REQUEST) request.user.email = email request.user.save() return CCAIResponse("修改email成功!") else: return CCAIResponse("email格式不对,请检查!", status=status.HTTP_400_BAD_REQUEST) except Exception as e: err_logger.error( "user: %s update email failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse(msg='Email修改失败', status=SERVER_ERROR) @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated], url_path="update_area", url_name="update_area") def update_area(self, request, pk=None): try: params = request.data area_dict = params.get("area", "") if area_dict == None or area_dict == "": return CCAIResponse("area参数不能为空!", status=status.HTTP_400_BAD_REQUEST) request.user.area_code = area_dict["value"] request.user.area_name = area_dict['label'] request.user.save() return CCAIResponse("地区修改成功!") except Exception as e: err_logger.error( "user: %s update area failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse(msg='地区修改失败', status=SERVER_ERROR) @action(methods=["post"], detail=False, permission_classes=[], url_path="forget_password", url_name="forget_password") def forget_password(self, request, pk=None): try: mobile = request.data.get('mobile', None) verification_code = request.data.get('verification_code', None) new_password1 = request.data.get('new_password1') new_password2 = request.data.get('new_password2') if mobile is None: return CCAIResponse(data="缺少参数mobile", msg="缺少参数mobile", status=BAD) conn = get_redis_connection('default') key = msg_redis_code + mobile code = conn.hget(key, 'code') count = conn.hget(key, 'count') if code is None: return CCAIResponse(data="验证码失效,请重新获取!", msg="验证码失效,请重新获取!", status=status.HTTP_206_PARTIAL_CONTENT) elif code.decode('utf8') != verification_code: if count is None: conn.hset(key, 'count', 1) else: count = int(count.decode('utf8')) + 1 if count < 5: conn.hset(key, 'count', count) else: conn.delete(key) return CCAIResponse(data="验证码有误!", msg="验证码有误!", status=BAD) else: if new_password1 == new_password2: user = UserProfile.objects.filter(mobile=mobile, is_active=1).first() if user: user.set_password(new_password2) user.save() conn.delete(key) return CCAIResponse(data="密码修改成功!", msg="密码修改成功!", status=OK) else: err_logger.error( "user: %s, connect redis failed: \n%s" % (request.user.id, traceback.format_exc())) else: return CCAIResponse(data="新密码两次输入不一致!", msg="新密码两次输入不一致!", status=status.HTTP_400_BAD_REQUEST) return CCAIResponse(data="密码修改失败!", msg="密码修改失败!", status=BAD) except Exception as e: err_logger.error( "user: %s forget user password, reset password failed: \n%s" % ( request.user.id, traceback.format_exc())) return CCAIResponse(data="忘记密码,重置密码失败!", msg="忘记密码,重置密码失败!", status=SERVER_ERROR) class UserRegisterView(APIView): """ 用户注册(注册为主账号) """ def post(self, request, *args, **kwargs): try: new_password1 = request.data.get("new_password1", None) new_password2 = request.data.get("new_password2", None) username = request.data.get("username", None) # 公司管理员账户 mobile = request.data.get("telephone", None) # 手机号码 companyname = request.data.get("companyname", None) # 公司名称 eucc = request.data.get("eucc", None) # 企业社会统一信用代码,一般为16为数字 verifycode = request.data.get("verifycode", None) # 短信验证码 name = request.data.get("name", None) # 姓名 if not companyname or companyname == '': return CCAIResponse("公司名不能为空!", status=BAD) if username == '' or username is None or \ new_password1 == '' or new_password1 is None or \ new_password2 == '' or new_password2 is None: return CCAIResponse("用户名或密码不能为空!", status=BAD) # if mobile is None or verifycode is None: # return CCAIResponse(data="手机号与验证码不能为空!", msg="手机号与验证码不能为空!", status=BAD) # 判断账号是否已经存在 username_exists = UserProfile.objects.filter(username=username).exists() if username_exists: return CCAIResponse(data="该账号已被注册!", msg="该账号已被注册!", status=BAD) # 判断手机号是否已经被注册 phone_exist = UserProfile.objects.filter(mobile=mobile).count() if phone_exist > 0: return CCAIResponse(data="该手机号已被注册!", msg="该手机号已被注册!", status=BAD) if new_password1 != new_password2: return CCAIResponse(data="密码两次输入不一致!", msg="密码两次输入不一致!", status=status.HTTP_400_BAD_REQUEST) try: conn = get_redis_connection('default') key = msg_redis_code + mobile code = conn.hget(key, 'code') count = conn.hget(key, 'count') if code is None: return CCAIResponse(data="验证码失效,请重新获取!", msg="验证码失效,请重新获取!", status=status.HTTP_206_PARTIAL_CONTENT) elif code.decode('utf8') != verifycode: if count is None: conn.hset(key, 'count', 1) else: count = int(count.decode('utf8')) + 1 if count < 5: conn.hset(key, 'count', count) else: conn.delete(key) return CCAIResponse(data="验证码有误!", msg="验证码有误!", status=status.HTTP_202_ACCEPTED) except Exception as e: err_logger.error("user: %s, connect redis failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse("注册失败!", status=BAD) with transaction.atomic(): # 生成用户与公司的全局id userMid = uuid.uuid4().__str__() company = Company.objects.filter(name=companyname).first() if company is None: # 创建绑定的公司 companyMid = uuid.uuid4().__str__() # 公司mid company = Company() company.MainId = companyMid company.name = companyname company.EUCC = eucc company.userMid = userMid company.save() else: companyMid = company.MainId # 创建用户 user = UserProfile() user.MainId = userMid user.companyMid = companyMid user.username = username user.name = username user.mobile = mobile user.is_sub = 2 # 2:主账号 user.is_active = 0 # 注册时不激活,由后台管理员确认信息后手动激活 user.label = 1 # 默认前台用户 user.set_password(new_password1) user.save() # 为注册用户添加公司 user.company.add(company) # 为注册用户添加角色 # 公司管理员(公司的唯一最大权限拥有者)id=2 其中包含的后台角色的权限(companyadmin)与菜单(company_system) role = Role.objects.filter(id=2).first() if role: user.roles.add(role) return CCAIResponse(data="注册成功", status=OK) except Exception as e: err_logger.error("user: %s, new_password1: %s, new_password1: %s, telphone: %s, user resister failed: " "\n%s" % (request.user.id, new_password1, new_password2, mobile, traceback.format_exc())) return CCAIResponse("注册失败", SERVER_ERROR) # class UserBindWeChat(APIView): # """ # 用户绑定个人微信 # """ # def post(self, request, *args): # try: # wx_code = request.GET.get('wx_code') # 微信临时code # encryptedData = request.data.get("encryptedData") # 加密数据 # iv = request.data.get("iv") # 加密数据 # response_dict = get_session_key(wx_code, APPID_MP, SECRET_MP, AuthorizationWX_URL) # 获取session_key # if not response_dict: # return CCAIResponse("授权登录失败!", status=SERVER_ERROR) # session_key = response_dict["session_key"] # decrypted = decode_info(iv, encryptedData, APPID_MP, session_key) # 解密手机号码 # if not decrypted: # return CCAIResponse("授权登录失败!", status=SERVER_ERROR) # # wxphone = decrypted["purePhoneNumber"] # # if wxphone == "" or wxphone is None: # return CCAIResponse("授权登录失败!", status=SERVER_ERROR) # user = UserProfile.objects.filter(mobile=wxphone, is_active=1, is_bind=1).first() # if user is not None: # # 存放微信相关信息 # user.wx_phone_info = json.dumps(decrypted) # user.wx_openid = response_dict["openid"] # user.save() # else: # return CCAIResponse("该微信的手机号码与八爪蛙账号的手机号码不一致!", status=SERVER_ERROR) # return CCAIResponse("微信绑定成功!", status=OK) # # except Exception as e: # err_logger("user: %s, bind Wechat failed: \n%s" % (request.user.id, traceback.format_exc())) # return CCAIResponse("注册失败", SERVER_ERROR) class UserListView(ListAPIView): queryset = UserProfile.objects.all() serializer_class = UserInfoListSerializer filter_backends = (DjangoFilterBackend, OrderingFilter) filter_fields = ("name",) ordering_fields = ("id",) authentication_classes = (JSONWebTokenAuthentication,) permission_classes = (IsAuthenticated,) class RefreshTokenView(APIView): authentication_classes = (JSONWebTokenAuthentication,) permission_classes = (IsAuthenticated,) """ 刷新token """ def post(self, request, *args, **kwargs): try: if request.user.id: if request.user.is_active: payload = jwt_payload_handler(request.user) return CCAIResponse({"token": jwt_encode_handler(payload)}, status=OK) else: return CCAIResponse("用户未激活", status=BAD) else: return CCAIResponse("用户不存在!", status=BAD) except Exception as e: err_logger.error("user: %s, user refresh token failed: \n%s" % (request.user.id, traceback.format_exc())) return CCAIResponse("用户不存在!", status=BAD)