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

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)