You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
394 lines
19 KiB
394 lines
19 KiB
|
10 months ago
|
import logging
|
||
|
|
import random
|
||
|
|
import string
|
||
|
|
import traceback
|
||
|
|
import uuid
|
||
|
|
|
||
|
|
from django.db import transaction
|
||
|
|
from django.db.models import Q
|
||
|
|
from django_filters.rest_framework import DjangoFilterBackend
|
||
|
|
from rest_framework.decorators import action
|
||
|
|
from rest_framework.filters import SearchFilter, OrderingFilter
|
||
|
|
from rest_framework.permissions import IsAuthenticated
|
||
|
|
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
|
||
|
|
|
||
|
|
from ChaCeRndTrans import settings
|
||
|
|
from ChaCeRndTrans.basic import CCAIResponse
|
||
|
|
from ChaCeRndTrans.code import SERVER_ERROR, BAD, OK
|
||
|
|
from ChaCeRndTrans.settings import RELEASE_DOMAIN, TEST_DOMAIN
|
||
|
|
from rbac.models import UserProfile, Role, Company
|
||
|
|
from rbac.serializers.role_serializer import RoleListSerializer
|
||
|
|
from rbac.serializers.user_serializer import UserListSerializer, CompanyRoleSerializer, UserCreateSerializer, \
|
||
|
|
UserModifySerializer
|
||
|
|
from utils.custom import CustomViewBase, sha1_encrypt, CommonPagination, is_valid_username
|
||
|
|
|
||
|
|
logger = logging.getLogger('error')
|
||
|
|
|
||
|
|
|
||
|
|
class SubAccountViewSet(CustomViewBase):
|
||
|
|
'''
|
||
|
|
子账号
|
||
|
|
'''
|
||
|
|
perms_map = (
|
||
|
|
{"*": "admin"},
|
||
|
|
{"*": "sub_account_all"},
|
||
|
|
{"get": "sub_account_list"},
|
||
|
|
{"post": "sub_account_create"},
|
||
|
|
{"put": "sub_account_edit"},
|
||
|
|
{"delete": "sub_account_delete"}
|
||
|
|
)
|
||
|
|
queryset = UserProfile.objects.all()
|
||
|
|
serializer_class = UserListSerializer
|
||
|
|
pagination_class = CommonPagination
|
||
|
|
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
|
||
|
|
filter_fields = ("is_active",)
|
||
|
|
search_fields = ("username", "name", "mobile", "email")
|
||
|
|
ordering_fields = ("id",)
|
||
|
|
authentication_classes = (JSONWebTokenAuthentication,)
|
||
|
|
|
||
|
|
def get_serializer_class(self):
|
||
|
|
# 根据请求类型动态变更serializer
|
||
|
|
if self.action == "create":
|
||
|
|
return UserCreateSerializer
|
||
|
|
elif self.action == "list":
|
||
|
|
return UserListSerializer
|
||
|
|
return UserModifySerializer
|
||
|
|
|
||
|
|
def get_queryset(self):
|
||
|
|
"""
|
||
|
|
我的企业-子账号
|
||
|
|
1.后台人员直接查看当前公司所有子用户
|
||
|
|
2.前台用户只能查看当前公司,当前用户的子用户
|
||
|
|
"""
|
||
|
|
companyMid = self.request.query_params.get('companyMid', None)
|
||
|
|
parent_id = self.request.query_params.get('parent_id', None)
|
||
|
|
queryset = UserProfile.objects.all()
|
||
|
|
query = Q()
|
||
|
|
if 1 == self.request.user.label: # 前台用户
|
||
|
|
if parent_id: # 查询当前用户的子账号
|
||
|
|
query &= Q(parent_id=parent_id)
|
||
|
|
if companyMid: # 且子账号需要有关联本公司
|
||
|
|
query &= Q(company__MainId=companyMid)
|
||
|
|
else: # 后台用户
|
||
|
|
if companyMid: # 且子账号需要有关联本公司
|
||
|
|
query &= Q(company__MainId=companyMid)
|
||
|
|
query &= ~Q(parent_id=None)
|
||
|
|
queryset = queryset.filter(query)
|
||
|
|
return queryset
|
||
|
|
|
||
|
|
# def list(self, request, *args, **kwargs):
|
||
|
|
# pagination = {}
|
||
|
|
# try:
|
||
|
|
# params = request.GET
|
||
|
|
# page_size = params.get('size', None)
|
||
|
|
# page = params.get('page', None)
|
||
|
|
# name = params.get("name", None) # 子账号真实姓名
|
||
|
|
# mobile = params.get("mobile", None) # 手机号码
|
||
|
|
# is_active = params.get("is_active", None) # 是否激活
|
||
|
|
# if page is None:
|
||
|
|
# page = 1
|
||
|
|
# if page_size is None:
|
||
|
|
# page_size = 10
|
||
|
|
# start_index = (int(page) - 1) * int(page_size)
|
||
|
|
#
|
||
|
|
# parent_id = params.get("parent_id", None)
|
||
|
|
# if parent_id is None:
|
||
|
|
# return CCAIResponse("缺少参数parent_id", BAD)
|
||
|
|
# main_account = UserProfile.objects.filter(id=parent_id).first()
|
||
|
|
# count = 0
|
||
|
|
# row = []
|
||
|
|
# sql = """
|
||
|
|
# select U.id, U.username, U.is_active, U.mobile, U.name
|
||
|
|
# from rbac_userprofile as U
|
||
|
|
# where U.is_sub = 1 and U.parent_id = {}
|
||
|
|
# """.format(parent_id)
|
||
|
|
# sql_count = """
|
||
|
|
# select U.id, count(U.id) as count
|
||
|
|
# from rbac_userprofile as U
|
||
|
|
# where U.is_sub = 1 and U.parent_id = {}
|
||
|
|
# """.format(parent_id)
|
||
|
|
# if name:
|
||
|
|
# temp = r""" and U.name = '{}' """.format(name)
|
||
|
|
# sql = sql + temp
|
||
|
|
# sql_count = sql_count + temp
|
||
|
|
# if mobile:
|
||
|
|
# temp = r""" and U.mobile = '{}' """.format(mobile)
|
||
|
|
# sql = sql + temp
|
||
|
|
# sql_count = sql_count + temp
|
||
|
|
# if is_active:
|
||
|
|
# temp = r""" and U.is_active = '{}' """.format(is_active)
|
||
|
|
# sql = sql + temp
|
||
|
|
# sql_count = sql_count + temp
|
||
|
|
# sql = sql + """ ORDER BY U.id desc limit {}, {} """.format(start_index, int(page_size))
|
||
|
|
# sub_account = UserProfile.objects.raw(sql)
|
||
|
|
# count_result = UserProfile.objects.raw(sql_count)
|
||
|
|
# if len(count_result) > 0:
|
||
|
|
# count = count_result[0].count
|
||
|
|
# if sub_account:
|
||
|
|
# for item in sub_account:
|
||
|
|
# item.__dict__.pop('_state')
|
||
|
|
# row.append(item.__dict__)
|
||
|
|
# return CCAIResponse(data=row, count=count)
|
||
|
|
# except Exception as e:
|
||
|
|
# logger.error("get sub account list failed: \n%s" % traceback.format_exc())
|
||
|
|
# return CCAIResponse("获取子账号列表失败", 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:
|
||
|
|
logger.error("get sub account list failed: \n%s" % traceback.format_exc())
|
||
|
|
return CCAIResponse(msg='获取子用户列表失败', status=SERVER_ERROR)
|
||
|
|
def create(self, request, *args, **kwargs):
|
||
|
|
try:
|
||
|
|
companyMid = request.query_params.get('companyMid', None)
|
||
|
|
data = request.data.copy()
|
||
|
|
company = data.get('company')
|
||
|
|
roles = data.get('roles')
|
||
|
|
|
||
|
|
if request.user.is_sub == 1:
|
||
|
|
return CCAIResponse("本账号为子账号,不允许开设子账号!", BAD)
|
||
|
|
|
||
|
|
# 验证公司信息是否有效
|
||
|
|
# if companyMid:
|
||
|
|
# company = Company.objects.filter(MainId=companyMid).first()
|
||
|
|
|
||
|
|
# if roles:
|
||
|
|
# roleid_list = roles.split(',')
|
||
|
|
#
|
||
|
|
# if companies:
|
||
|
|
# companies_list = companies.split(',')
|
||
|
|
|
||
|
|
# if not data['parent_id']:
|
||
|
|
# return CCAIResponse(data="缺少参数parent_id", status=BAD)
|
||
|
|
user_count = UserProfile.objects.filter(username=data['username']).count()
|
||
|
|
if user_count > 0:
|
||
|
|
return CCAIResponse(data="用户名冲突,请重新输入", msg="用户名冲突,请重新输入", status=BAD)
|
||
|
|
|
||
|
|
if data['mobile']:
|
||
|
|
user_count = UserProfile.objects.filter(mobile=data['mobile']).count()
|
||
|
|
if user_count > 0:
|
||
|
|
return CCAIResponse(data="手机号码已被注册,请校对手机号码", msg="手机号码已被注册,请校对手机号码",
|
||
|
|
status=BAD)
|
||
|
|
if data['username']:
|
||
|
|
if not is_valid_username(data['username']):
|
||
|
|
return CCAIResponse(data="用户名命名不符合规定,只能使用汉字、英文字母、数字,不能使用特殊字符。",
|
||
|
|
msg="用户名命名不符合规定,只能使用汉字、英文字母、数字,不能使用特殊字符。",
|
||
|
|
status=BAD)
|
||
|
|
with transaction.atomic():
|
||
|
|
# 生成用户与公司的全局id
|
||
|
|
userMid = uuid.uuid4().__str__()
|
||
|
|
# 创建用户
|
||
|
|
user = UserProfile()
|
||
|
|
user.MainId = userMid
|
||
|
|
user.companyMid = companyMid # 默认绑定当前公司
|
||
|
|
user.username = data['username']
|
||
|
|
user.name = data['username']
|
||
|
|
user.mobile = data['mobile']
|
||
|
|
user.is_sub = 1 # 子账号账号
|
||
|
|
user.is_active = 1 # 注册即激活
|
||
|
|
user.label = 1 # 前台用户
|
||
|
|
user.parent_id = request.user.id
|
||
|
|
# 创建随机密码,并返回
|
||
|
|
random_password = ''.join(random.sample(string.ascii_letters + string.digits, 8))
|
||
|
|
password = sha1_encrypt(random_password)
|
||
|
|
user.set_password(password)
|
||
|
|
user.save()
|
||
|
|
|
||
|
|
com_list = Company.objects.filter(id__in=company)
|
||
|
|
for c in com_list:
|
||
|
|
# 为注册用户添加公司
|
||
|
|
user.company.add(c)
|
||
|
|
|
||
|
|
# 添加默认角色测试服29 / 正式服 32
|
||
|
|
if settings.DEBUG:
|
||
|
|
role = Role.objects.get(id=29)
|
||
|
|
else:
|
||
|
|
role = Role.objects.get(id=32)
|
||
|
|
user.roles.add(role)
|
||
|
|
|
||
|
|
if roles and len(roles) > 0:
|
||
|
|
# 为子账号添加角色
|
||
|
|
roles = Role.objects.filter(id__in=roles).all()
|
||
|
|
for role in roles:
|
||
|
|
user.roles.add(role)
|
||
|
|
|
||
|
|
return CCAIResponse(data=random_password, status=OK)
|
||
|
|
except Exception:
|
||
|
|
logger.error("user:%s, add sub account failed: \n%s" % (request.user.id, traceback.format_exc()))
|
||
|
|
return CCAIResponse("创建子账号失败", SERVER_ERROR)
|
||
|
|
|
||
|
|
def update(self, request, *args, **kwargs):
|
||
|
|
try:
|
||
|
|
data = request.data.copy()
|
||
|
|
|
||
|
|
partial = kwargs.pop('partial', False)
|
||
|
|
if 'parent_id' not in data and data['parent_id'] is None:
|
||
|
|
return CCAIResponse("缺少参数parent_id", BAD)
|
||
|
|
# roles = data.get('roles')
|
||
|
|
# companies = data.get('companies')
|
||
|
|
# if roles:
|
||
|
|
# roles = roles.split(',')
|
||
|
|
# data['roles'] =roles
|
||
|
|
# if companies:
|
||
|
|
# companies = companies.split(',')
|
||
|
|
# data['companies'] =companies
|
||
|
|
|
||
|
|
instance = self.get_object()
|
||
|
|
serializer = self.get_serializer(instance, data=data, partial=partial)
|
||
|
|
serializer.is_valid(raise_exception=True)
|
||
|
|
self.perform_update(serializer)
|
||
|
|
user = UserProfile.objects.filter(id=data['id']).first()
|
||
|
|
if user is None:
|
||
|
|
return CCAIResponse("账号不存在", SERVER_ERROR)
|
||
|
|
if data['mobile']:
|
||
|
|
user_count = UserProfile.objects.filter(mobile=data['mobile']).exclude(id=data['id']).count()
|
||
|
|
if user_count > 0:
|
||
|
|
return CCAIResponse(data="手机号码已被注册,请校对手机号码", msg="手机号码已被注册,请校对手机号码",
|
||
|
|
status=BAD)
|
||
|
|
if data['username']:
|
||
|
|
if not is_valid_username(data['username']):
|
||
|
|
return CCAIResponse(data="用户名格式不对,只能输入汉字,英文字母,数字!",
|
||
|
|
msg="用户名格式不对,只能输入汉字,英文字母,数字!", status=BAD)
|
||
|
|
user_count = UserProfile.objects.filter(username=data['username']).exclude(id=data['id']).count()
|
||
|
|
if user_count > 0:
|
||
|
|
return CCAIResponse("该用户名已被注册,请校对用户名", status=BAD)
|
||
|
|
# if data['ratio']:
|
||
|
|
# ratio = Decimal(data['ratio']) # 子账号的分销比例 = 父账号的分销比例 * 父账号为其分配的分销比例
|
||
|
|
# user.ratio = ratio
|
||
|
|
user.username = data['username']
|
||
|
|
user.mobile = data['mobile']
|
||
|
|
user.save()
|
||
|
|
return CCAIResponse("success")
|
||
|
|
except Exception as e:
|
||
|
|
logger.error("user:%s, update sub account failed: \n%s" % (request.user.id, traceback.format_exc()))
|
||
|
|
return CCAIResponse("更新子账号失败", SERVER_ERROR)
|
||
|
|
|
||
|
|
def destroy(self, request, *args, **kwargs):
|
||
|
|
try:
|
||
|
|
with transaction.atomic():
|
||
|
|
instance = self.get_object()
|
||
|
|
self.perform_destroy(instance)
|
||
|
|
users = UserProfile.objects.filter(username=instance.username)
|
||
|
|
for user in users:
|
||
|
|
user.delete()
|
||
|
|
return CCAIResponse(data="删除账号成功")
|
||
|
|
except Exception as e:
|
||
|
|
logger.error("user:%s, delete sub account failed: \n%s" % (request.user.id, traceback.format_exc()))
|
||
|
|
return CCAIResponse(data="删除子账号失败", msg="删除子账号失败", status=SERVER_ERROR)
|
||
|
|
|
||
|
|
@action(methods=["POST"], detail=False, permission_classes=[IsAuthenticated],
|
||
|
|
url_path="disable_sub_user", url_name="disable_sub_user")
|
||
|
|
def disable_sub_user(self, request):
|
||
|
|
try:
|
||
|
|
data = request.data.copy()
|
||
|
|
if 'uid' not in data and data['uid'] is None:
|
||
|
|
return CCAIResponse(data="缺少参数uid", msg="缺少参数uid", status=BAD)
|
||
|
|
if 'is_active' not in data:
|
||
|
|
return CCAIResponse(data="缺少参数is_active", msg="缺少参数is_active", status=BAD)
|
||
|
|
user = UserProfile.objects.filter(id=data['uid']).first()
|
||
|
|
if user is None:
|
||
|
|
return CCAIResponse(data="账号不存在", msg="账号不存在", status=SERVER_ERROR)
|
||
|
|
if data['is_active']:
|
||
|
|
user.is_active = 1
|
||
|
|
else:
|
||
|
|
user.is_active = 0
|
||
|
|
user.save()
|
||
|
|
return CCAIResponse(data="修改子账号激活状态")
|
||
|
|
except Exception as e:
|
||
|
|
logger.error(
|
||
|
|
"user: %s disable sub user 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="reset_sub_password", url_name="reset_sub_password")
|
||
|
|
def reset_subAccount_password(self, request, pk=None):
|
||
|
|
try:
|
||
|
|
data = request.data.copy()
|
||
|
|
if 'uid' not in data and data['uid'] is None:
|
||
|
|
return CCAIResponse(data="缺少参数uid", msg="缺少参数uid", status=BAD)
|
||
|
|
user = UserProfile.objects.get(id=data['uid'])
|
||
|
|
if user and request.user.is_sub == 2:
|
||
|
|
with transaction.atomic():
|
||
|
|
random_password = ''.join(random.sample(string.ascii_lowercase + string.digits, 8))
|
||
|
|
password = sha1_encrypt(random_password)
|
||
|
|
user.set_password(password)
|
||
|
|
user.save()
|
||
|
|
return CCAIResponse(data=random_password, status=OK)
|
||
|
|
else:
|
||
|
|
return CCAIResponse(data="子账号异常,请联系管理员", status=BAD)
|
||
|
|
except Exception as e:
|
||
|
|
logger.error("main account reset sub account password failed: \n%s" % traceback.format_exc())
|
||
|
|
return CCAIResponse(msg='修改子账号密码失败', status=SERVER_ERROR)
|
||
|
|
|
||
|
|
# @action(methods=["post"], detail=False, permission_classes=[IsAuthenticated],
|
||
|
|
# url_path="set_sub_ratio", url_name="set_sub_ratio")
|
||
|
|
# def set_subAcount_ratio(self, request, pk=None):
|
||
|
|
# try:
|
||
|
|
# data = request.data.copy()
|
||
|
|
# if 'uid' not in data and data['uid'] is None:
|
||
|
|
# return CCAIResponse(data="缺少参数uid", msg="缺少参数uid", status=BAD)
|
||
|
|
# if 'ratio' not in data and data['ratio'] is None:
|
||
|
|
# return CCAIResponse(data="缺少参数ratio", msg="缺少参数ratio", status=BAD)
|
||
|
|
# user = UserProfile.objects.get(id=data['uid'])
|
||
|
|
# if user and request.user.is_sub == 2:
|
||
|
|
# user.ratio = data['ratio']
|
||
|
|
# user.save()
|
||
|
|
# return CCAIResponse(data="修改子账号佣金分销比例成功!", msg="修改子账号佣金分销比例成功!", status=OK)
|
||
|
|
# except Exception as e:
|
||
|
|
# logger.error("main account set sub account ratio failed: \n%s" % traceback.format_exc())
|
||
|
|
# return CCAIResponse(msg='修改子账号佣金分销比例失败', status=SERVER_ERROR)
|
||
|
|
|
||
|
|
@action(methods=["get"], detail=False, permission_classes=[IsAuthenticated],
|
||
|
|
url_path="getCompanyAndRole", url_name="getCompanyAndRole")
|
||
|
|
def getCompanyAndRole(self, request):
|
||
|
|
"""
|
||
|
|
获取当前用户的关联公司与该公司的角色,及系统默认提供的角色(除去后台角色label=2)
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
|
||
|
|
# 获取公司
|
||
|
|
companyList = request.user.company.all()
|
||
|
|
companyMainIdList = [item.MainId for item in companyList]
|
||
|
|
|
||
|
|
# 获取角色
|
||
|
|
rolelist = Role.objects.filter(
|
||
|
|
~Q(label=2) & (Q(companyMid__in=companyMainIdList) | Q(companyMid__isnull=True)))
|
||
|
|
|
||
|
|
sysRole = set() # 系统默认角色
|
||
|
|
# 将角色封装到对应的公司中 (当前方法时间复杂度较高,有提升空间)
|
||
|
|
for com in companyList:
|
||
|
|
com.roles = []
|
||
|
|
for role in rolelist:
|
||
|
|
if role.companyMid and role.companyMid != '':
|
||
|
|
if role.companyMid == com.MainId:
|
||
|
|
com.roles.append(role)
|
||
|
|
else:
|
||
|
|
sysRole.add(role)
|
||
|
|
data = {
|
||
|
|
'sysRole': RoleListSerializer(sysRole, many=True).data,
|
||
|
|
'comRole': CompanyRoleSerializer(companyList, many=True).data,
|
||
|
|
}
|
||
|
|
return CCAIResponse(data)
|
||
|
|
except Exception as e:
|
||
|
|
logger.error("getCompanyAndRole failed: \n%s" % traceback.format_exc())
|
||
|
|
return CCAIResponse(msg='获取公司与角色映射失败', status=SERVER_ERROR)
|