独角鲸同步合作方公司数据项目
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.
 

393 lines
19 KiB

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)