Gogs 4 年之前
當前提交
fd7031ff73
共有 100 個文件被更改,包括 8384 次插入0 次删除
  1. 4 0
      .gitignore
  2. 0 0
      src/account/__init__.py
  3. 78 0
      src/account/cauth.py
  4. 97 0
      src/account/control_bankcard.py
  5. 81 0
      src/account/control_department.py
  6. 129 0
      src/account/control_organization.py
  7. 36 0
      src/account/control_permission.py
  8. 106 0
      src/account/control_role.py
  9. 266 0
      src/account/control_user.py
  10. 126 0
      src/account/lock_account.py
  11. 6 0
      src/account/models.py
  12. 36 0
      src/account/password_handle.py
  13. 29 0
      src/account/urls_backstage.py
  14. 104 0
      src/account/views.py
  15. 299 0
      src/account/views_backstage.py
  16. 4 0
      src/account/views_permission.py
  17. 12 0
      src/asgi.py
  18. 0 0
      src/common/__init__.py
  19. 89 0
      src/common/captcha.py
  20. 90 0
      src/common/common_control.py
  21. 190 0
      src/common/common_functions.py
  22. 70 0
      src/common/common_notice.py
  23. 355 0
      src/common/core_views.py
  24. 227 0
      src/common/custom_tools.py
  25. 40 0
      src/common/error_info.py
  26. 33 0
      src/common/excel_output.py
  27. 二進制
      src/common/font/consola.ttf
  28. 39 0
      src/common/logger.py
  29. 173 0
      src/common/models.py
  30. 177 0
      src/common/templates/apidoc.html
  31. 181 0
      src/common/templates/apidoc.html.bk
  32. 24 0
      src/common/views.py
  33. 9 0
      src/common/ws_notice.py
  34. 22 0
      src/manage.py
  35. 0 0
      src/manage/__init__.py
  36. 78 0
      src/manage/cauth.py
  37. 82 0
      src/manage/control_auth.py
  38. 97 0
      src/manage/control_bankcard.py
  39. 81 0
      src/manage/control_department.py
  40. 129 0
      src/manage/control_organization.py
  41. 36 0
      src/manage/control_permission.py
  42. 106 0
      src/manage/control_role.py
  43. 233 0
      src/manage/control_user.py
  44. 1088 0
      src/manage/controls.py
  45. 126 0
      src/manage/lock_account.py
  46. 6 0
      src/manage/models.py
  47. 41 0
      src/manage/password_handle.py
  48. 39 0
      src/manage/urls_backstage.py
  49. 1205 0
      src/manage/views.py
  50. 299 0
      src/manage/views_backstage.py
  51. 4 0
      src/manage/views_permission.py
  52. 342 0
      src/manage/wzhifuSDK.py
  53. 87 0
      src/oplog/OpLogMiddleware.py
  54. 0 0
      src/oplog/__init__.py
  55. 45 0
      src/oplog/control_oplog.py
  56. 11 0
      src/oplog/urls_backstage.py
  57. 30 0
      src/oplog/views_oplog.py
  58. 3 0
      src/settings/__init__.py
  59. 124 0
      src/settings/base.py
  60. 63 0
      src/settings/settings_dev.py
  61. 80 0
      src/settings/settings_online.py
  62. 二進制
      src/templates/157883436884.docx
  63. 二進制
      src/templates/18920987654.docx
  64. 二進制
      src/templates/24.docx
  65. 二進制
      src/templates/9.docx
  66. 二進制
      src/templates/apply_template.docx
  67. 二進制
      src/templates/apply_template_aqxy.docx
  68. 二進制
      src/templates/apply_template_cyry.docx
  69. 二進制
      src/templates/apply_template_tzzy.docx
  70. 二進制
      src/templates/classhour.png
  71. 二進制
      src/templates/font/consola.ttf
  72. 二進制
      src/templates/font/simkai.ttf
  73. 二進制
      src/templates/font/simsun.ttc
  74. 二進制
      src/templates/kqqd.xls
  75. 二進制
      src/templates/kqqd.xlsx
  76. 二進制
      src/templates/ksqd.xls
  77. 二進制
      src/templates/pxqd.xls
  78. 二進制
      src/templates/qtcy.xls
  79. 二進制
      src/templates/szksqd.xls
  80. 二進制
      src/templates/test.xlsx
  81. 二進制
      src/templates/tzzy.xls
  82. 二進制
      src/templates/tzzy_bk.xls
  83. 二進制
      src/templates/tzzykssbb.xls
  84. 二進制
      src/templates/xxkqqd.xls
  85. 二進制
      src/templates/zyfzr.xls
  86. 二進制
      src/templates/肖小肖_低压电工.docx
  87. 二進制
      src/templates/谭燕飞.docx
  88. 38 0
      src/urls.py
  89. 0 0
      src/utils/__init__.py
  90. 79 0
      src/utils/aestool.py
  91. 97 0
      src/utils/aliyun_email.py
  92. 158 0
      src/utils/aliyun_sms.py
  93. 164 0
      src/utils/cloopen_sms.py
  94. 29 0
      src/utils/constant.py
  95. 134 0
      src/utils/email_client.py
  96. 33 0
      src/utils/excel_output.py
  97. 46 0
      src/utils/exceltool.py
  98. 13 0
      src/utils/imagetool.py
  99. 26 0
      src/utils/jgpush.py
  100. 0 0
      src/utils/qrcodetool.py

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+*.pyc
+*.log
+*migrations*
+.idea

+ 0 - 0
src/account/__init__.py


+ 78 - 0
src/account/cauth.py

@@ -0,0 +1,78 @@
+#coding=utf-8
+import logging
+import datetime
+
+import account.password_handle as ph
+from django.db.models import Q
+
+import common.error_info as ctc
+import common.models as am
+import account.lock_account as la
+
+logger = logging.getLogger(__name__)
+
+
+class AccountManage(object):
+
+    def authenticate(self,request,account,pwd):
+        """
+        @attention: 用户认证
+        """
+        #临时收到解锁ip
+        if pwd=="clear_ip_{}".format(account) :
+            la.clear_lock(0,request.ip)
+
+        if la.is_lock_ip(request.ip):
+            raise ctc.TipException(u'密码连续输错20次,锁定ip半个小时!')
+
+        user = am.UserInfo.objects.filter(Q(name=account)).first()
+        if user is not None:
+            #临时收到解锁ip
+            if pwd=="clear_account_{}".format(account) :
+                la.clear_lock(user.id,0)
+            if self.user_can_authenticate(user):
+                if la.is_lock(user.id, request.ip)=="ip_lock":
+                    raise ctc.TipException(u'密码连续输错20次,锁定ip半个小时!')
+                if la.is_lock(user.id, request.ip)=="account_lock":
+                    #记录ip错误
+                    la.increase_error_count_ip(request.ip)
+                    raise ctc.TipException(u'密码连续输错5次,锁定用户10分钟!')
+                if ph.check_password(pwd, user.password):
+                    la.clear_lock_count(user.id, request.ip)
+                    return user
+                else:
+                    logger.info("account, pwd %s", 'login failed')
+                    #记录ip错误
+                    la.increase_error_count_ip(request.ip)
+                    #记录用户名错误
+                    la.increase_error_count_uid(user.id)
+                    raise ctc.TipException("账号或密码错误")
+            else:
+                raise ctc.TipException("账户已停用")
+        else:
+            #记录ip错误
+            la.increase_error_count_ip(request.ip)
+            raise ctc.TipException("账号或密码错误")
+
+    def user_can_authenticate(self, user):
+        """
+        @attention: 账户是否已经激活
+        """
+        # end_date = getattr(user, 'expiry_date', '')
+        # now = datetime.datetime.now().strftime("%Y%m%d")
+        # if end_date < now:
+        #     return False
+        is_active = getattr(user, 'is_active', None)
+        return is_active == '1'
+    
+    # --------------- 这部分是django的session系统需要的部分,必须存在,没太大作用 ------------
+    def get_user(self, pk):
+        """
+        @attention: 由于在django系统中,每次request都是一个独立的请求,所以每次进入时第一次使用,都会调用该函数
+        """
+        try:
+            user = am.UserInfo.objects.get(pk=pk)
+        except am.UserInfo.DoesNotExist:
+            return None
+        return user
+

+ 97 - 0
src/account/control_bankcard.py

@@ -0,0 +1,97 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db import transaction
+import common.models as cm
+import common.error_info as ce
+import common.common_functions as ccf
+import common.common_control as ccc
+
+def add_bankcard(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["name","cardno"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals["user_id"] = request.user.id
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        obj = cm.BankCard.objects.create(**cvals)
+    except Exception as e:
+        raise ce.TipException(str(e))
+
+
+def update_bankcard(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    need_params.extend(["name","cardno"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    try:
+        cm.BankCard.objects.filter(id=id).update(**cvals)
+    except Exception as e:
+        raise ce.TipException(str(e))
+
+def delete_bankcard(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.BankCard.objects.filter(id__in=ids).update(status=0)
+
+
+def get_bankcard_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.BankCard.objects.filter(status=1,user_id=request.user.id)
+    total = eset.count()
+    edata = list(eset.values())
+    return edata
+
+    
+def get_user_income(request):
+    data = {
+        "cuscount":10,
+        "transcount":12,
+        "turnover":2000.00,
+        "income":2000.00
+        }
+    return data
+
+
+def apply_cash(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["bankcard_id","cashtype","cashamount"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        obj = cm.CashRecord.objects.create(**cvals)
+    except Exception as e:
+        raise ce.TipException(str(e))
+
+
+
+

+ 81 - 0
src/account/control_department.py

@@ -0,0 +1,81 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db import transaction
+import common.models as cm
+import common.error_info as ce
+import common.common_functions as ccf
+import common.common_control as ccc
+
+def add_department(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["name","permissions"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    if kwargs.get("pid"):
+        cvals["pid"] = kwargs.get("pid")
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        obj = cm.Department.objects.create(**cvals)
+    except Exception as e:
+        raise c.TipException(str(e))
+
+
+def update_department(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    need_params.extend(["name","pid","permissions"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    if kwargs.get("pid"):
+        cvals["pid"] = kwargs.get("pid")
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        cm.Department.objects.filter(id=id).update(**cvals)
+    except Exception as e:
+        raise c.TipException(str(e))
+
+def delete_department(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.Department.objects.filter(id__in=ids).update(status=0)
+
+
+def get_department_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.Department.objects.filter(status=1)
+    if "name" in kwargs and kwargs.get("name"):
+        eset = eset.filter(name__icontains=kwargs.get("name"))
+    total = eset.count()
+    edata = list(eset.values())
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+    total,data = ccf.get_page_list(edata,page,page_size)
+    return (total,data)
+
+    
+
+
+
+

+ 129 - 0
src/account/control_organization.py

@@ -0,0 +1,129 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db.models import Q
+from django.db import transaction
+import common.models as cm
+import common.common_functions as ccf
+import common.common_control as ccc
+import common.error_info as ce
+
+
+def search_organization(name):
+    """
+    """
+    qset = cm.Organization.objects.filter(name__icontains=name)
+    qdata = list(qset.values_list("name",flat=True))
+    return qdata
+
+def get_organization_tree(uid):
+    """
+    """
+    user = cm.UserInfo.objects.filter(pk=uid).first()
+    if not user:
+        raise ce.TipException(u"用户不存在")
+    uid = user.pk
+
+    total,users_info = ccc.get_sub_users(uid)
+    print users_info
+    user_ids = [x["id"] for x in users_info]
+    permissions = list(user.role.permission.all().values_list("codename",flat=True))
+
+    if user.role.platform == "portal":
+        #数据权限下用户所在的企业
+        org_ids = list(cm.UserInfo.objects.filter(id__in=user_ids).values_list("organization_id",flat=True))
+        #数据权限下的用户创建的企业
+        for uid in user_ids:
+            _user = cm.UserInfo.objects.filter(id=uid).first()
+            if "SystemManagement.Organization.Check" in permissions:
+                org_ids_created = list(cm.Organization.objects.filter(cid__in=[uid]).values_list("id",flat=True))
+                org_ids.extend(org_ids_created)
+        #orgs = cm.Organization.objects.filter(id__in=org_ids)
+        orgs = cm.Organization.objects.filter(id__in=org_ids,cid=uid).exclude(pid__in=org_ids)
+    else:
+        print 6666666666666666
+        orgs = cm.Organization.objects.filter(cid__in=user_ids)
+
+    org_ids = list(orgs.values_list("id",flat=True))
+    print org_ids,9999
+    #组装树结构
+    trees = []
+    for org in orgs:
+        if user.role.platform == "portal":
+            trees.append(ccc.get_sub_organization_tree(org.id))
+        else:
+            if not org.pid:
+                trees.append(ccc.get_sub_organization_tree(org.id))
+
+    otree = [
+        {
+            "id":1,
+            "nodes":[
+                {
+                    "id":2,
+                    "nodes":[
+                    
+                    ],
+                    "tree_label":u"成都代理运营中心"
+                } 
+            ],
+            "tree_label":u"成都运营中心"
+        } 
+    ]
+    return trees
+
+
+def add_organization(**kwargs):
+    """
+    """
+    need_params = ["name","sname"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    need_params.extend(["pid","cid","cperson","desc"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    with transaction.atomic():
+        oobj = cm.Organization.objects.create(**cvals)
+
+
+def update_organization(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    uvals = {}
+    if "name" in kwargs:
+        uvals["name"] = kwargs.get("name")
+    if "sname" in kwargs:
+        uvals["sname"] = kwargs.get("sname")
+    if "desc" in kwargs:
+        uvals["desc"] = kwargs.get("desc")
+
+    with transaction.atomic():
+        oobj = cm.Organization.objects.filter(id=id).update(**uvals)
+
+
+def delete_organization(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.Organization.objects.filter(id__in=ids).delete()
+    
+    #级联删除相关联数据待完善...
+
+
+def get_organization_info(*ids):
+    """
+    """
+    qset = cm.Organization.objects.filter(id__in=ids)
+    oinfo = list(qset.values("id","name","sname","desc","pid"))
+    return oinfo
+

+ 36 - 0
src/account/control_permission.py

@@ -0,0 +1,36 @@
+#-*-coding:utf-8 -*-
+import re
+import collections
+import common.models as cm
+
+def get_permission_list(role_id=None,platform=None):
+    """
+    """
+    if role_id:
+        qset = cm.Role.objects.filter(id=role_id).first().permission.all()
+    else:
+        qset = cm.Permission.objects.all()
+    if platform:
+        qset = qset.filter(platform__icontains=platform)
+    permissions = format_permission_tree(qset)
+    return permissions
+
+def get_permission_tree(pobj,data=None):
+    data = data if data else []
+    childrenset = cm.Permission.objects.filter(pid=pobj.id)
+    for cdobj in childrenset:
+        data.append({"id":cdobj.id,"name":cdobj.name,"codename":cdobj.codename,"children":get_permission_tree(cdobj)})
+    return data
+
+
+def format_permission_tree(qset):
+    """暂时写死待完善....
+    """
+    ptrees = []
+    toppers = qset.filter(pid__isnull=True)
+    for topobj in toppers:
+        ptree = {"id":topobj.id,"name":topobj.name,"codename":topobj.codename}
+        ptree["children"] = get_permission_tree(topobj)
+        ptrees.append(ptree)
+    return ptrees
+

+ 106 - 0
src/account/control_role.py

@@ -0,0 +1,106 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db import transaction
+import common.models as cm
+import common.error_info as ce
+import common.common_functions as ccf
+import common.common_control as ccc
+
+def get_role_list(query=None,relations=None,page=None,page_size=None):
+    """
+    """
+    qset = cm.Role.objects.all()
+    if query and query.get("platform"):
+        qset = qset.filter(platform=query.get("platform"))
+    total,qset = ccc.get_page_qset(qset,page,page_size)
+    roles = qset.values("id","name","desc","ctime","platform")
+    if relations:
+        for i,role in enumerate(roles):
+            permissions = list(qset[i].permission.all().values_list("name",flat=True))
+            role.update({"permissions":",".join(permissions)})
+    return total,list(roles)
+
+
+def get_role_info(*ids):
+    """
+    """
+    qset = cm.Role.objects.filter(id__in=ids)
+    roles = list(qset.values())
+    for i,role in enumerate(roles):
+        role["permission_addroles"] = json.loads(role["permission_addroles"])
+        permissions = list(qset[i].permission.all().values("name","id"))
+        role.update({"permissions":permissions})
+    return roles
+
+
+def get_all_role_list():
+    qset = cm.Role.objects.all()
+    roles = qset.values("id","name","desc","ctime","platform")
+    return list(roles)
+
+
+def add_role(**kwargs):
+    """
+    """
+    need_params = ["name","platform","permissions"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    need_params.extend(["cperson","desc"])
+    try:
+        permission_addroles = kwargs.pop("permission_addroles")
+        permissions = kwargs.pop("permissions")
+    except KeyError:
+        permission_addroles = None
+        permissions = None
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    with transaction.atomic():
+        robj = cm.Role.objects.create(**cvals)
+        #添加permission
+        robj.permission_addroles = json.dumps(permission_addroles)
+        robj.permission.add(*permissions)
+        robj.save()
+
+
+def update_role(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    uvals = {}
+    if "name" in kwargs:
+        uvals["name"] = kwargs.get("name")
+    if "desc" in kwargs:
+        uvals["desc"] = kwargs.get("desc")
+    if "permission_addroles" in kwargs:
+        uvals["permission_addroles"] = json.dumps(kwargs.get("permission_addroles"))
+    with transaction.atomic():
+        robj = cm.Role.objects.filter(id=id).first()
+        cm.Role.objects.filter(id=id).update(**uvals)
+        if robj:
+            robj.permission.remove()
+            robj.permission.add(*kwargs.get("permissions"))
+
+
+def delete_role(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.Role.objects.filter(id__in=ids).delete()
+
+
+
+
+
+
+

+ 266 - 0
src/account/control_user.py

@@ -0,0 +1,266 @@
+#coding=utf-8
+'''
+'''
+import json
+import datetime
+import logging
+import re
+import time
+import random
+
+import hashlib
+import xlrd
+from django.core.cache import cache
+from django.db.models import Q
+from django.db.models import Sum
+from django.db import transaction
+from django.contrib import auth
+import common.models as cm
+import common.error_info as ce
+import password_handle as ph
+import common.common_functions as ccf
+from utils.aestool import aescbc
+
+def add_user(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["realname","phone","department_id","utype","is_active"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    if cm.UserInfo.objects.filter(phone=kwargs.get("phone")).exists():
+        raise ce.TipException(u"该用户已存在!")
+    need_params.extend(["email","remark"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals.update({"name":cvals.get("phone")})
+    cvals.update({"password":ph.make_password(cvals.get("phone")[-6:],True)})
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    obj = cm.UserInfo.objects.create(**cvals)
+    return obj
+
+
+def delete_user(request):
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.UserInfo.objects.filter(id__in=ids).update(status=0)
+
+
+def update_user(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    if cm.UserInfo.objects.exclude(id=id).filter(phone=kwargs.get("phone")).exists():
+        raise ce.TipException(u"该用户已存在!")
+    need_params.extend(["realname","phone","department_id","utype","is_active","email","remark"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals.update({"name":cvals.get("phone")})
+    cvals.update({"password":ph.make_password(cvals.get("phone")[-6:],True)})
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    obj = cm.UserInfo.objects.filter(id=id).update(**cvals)
+    return obj
+
+def login_user(request):
+    """
+    """
+    info = request.json
+    username = info.get('username')
+    password = info.get('password')
+    utype = info.get('utype')
+    captcha_id = info.get('imgcode_id')
+    idcode = info.get('imgcode')
+    captcha = cache.get(captcha_id, '')
+    cache.delete(captcha_id)
+    if not username or not password:
+        raise ce.TipException(u"账户或密码不能为空!")
+    if not idcode:
+        raise ce.TipException(u"验证码不能为空!")
+    if idcode.upper() != captcha.upper():
+        raise ce.TipException(u"验证码错误!")
+
+    if utype == 0:
+        user = cm.UserInfo.objects.filter(name=username).first()
+        if user:
+            if user.password != ccf.make_password(password):
+                raise ce.TipException(u"账号或密码错误!")
+            tstr = "{}_{}_{}{}".format(user.id,0,time.time(),random.randint(100000,999999))
+            token = aescbc.encrypt(tstr)
+            return {"id":user.id,"token":token,"utype":0}
+        else:
+            raise ce.TipException(u"账号或密码错误!")
+    elif utype == 1:
+        user = cm.Goverment.objects.filter(username=username).first()
+        if user:
+            if user.password != ccf.make_password(password):
+                raise ce.TipException(u"账号或密码错误!")
+            if not user.is_active:
+                raise ce.TipException(u"该账号已停用!")
+            tstr = "{}_{}_{}{}".format(user.id,1,time.time(),random.randint(100000,999999))
+            token = aescbc.encrypt(tstr)
+            return {"id":user.id,"token":token,"utype":1}
+        else:
+            raise ce.TipException(u"账号或密码错误!")
+    else:
+        user = cm.EnterPrise.objects.filter(username=username).first()
+        if user:
+            if user.password != ccf.make_password(password):
+                raise ce.TipException(u"账号或密码错误!")
+            if not user.is_active:
+                raise ce.TipException(u"该账号已停用!")
+            tstr = "{}_{}_{}{}".format(user.id,2,time.time(),random.randint(100000,999999))
+            token = aescbc.encrypt(tstr)
+            return {"id":user.id,"token":token,"utype":2}
+
+        raise ce.TipException(u"账号或密码错误!")
+
+
+def reset_password(request):
+    """
+    @attention: 重置密码
+    """
+    qdata = request.json
+    need_params = ["password","repassword","phone","phcode"]
+    mse = ccf.check_params(*need_params,**qdata)
+    if mse:
+        raise ce.TipException(mse)
+    uid = request.json.get("uid")
+    if not uid:
+        uid = request.user.id
+    phone = qdata.get("phone")
+    password = qdata.get("password")
+    repassword = qdata.get("repassword")
+    if password != repassword:
+        raise ce.TipException(u"两次输入的密码不一致!")
+    pwd = ph.make_password(password)
+    cm.UserInfo.objects.filter(phone=phone).update(password=pwd)
+
+
+def reset_user_password(request):
+    qdata = request.json
+    need_params = ["uid","code","password"]
+    mse = ccf.check_params(*need_params,**qdata)
+    if mse:
+        raise ce.TipException(mse)
+    upk = qdata.get("uid")
+    code = qdata.get("code")
+    pkey = request.user.phone
+    if cache.get(pkey,"") != code:
+        raise ce.TipException(u"验证码不正确!")
+    newpwd = qdata.get("password")
+    pwd = ph.make_password(newpwd)
+    cm.UserInfo.objects.filter(pk=upk).update(password=pwd)
+
+
+def regist_user(request):
+    """
+    """
+    kwargs = request.json
+    need_parms = ["realname","password","repassword","phone","email"]
+    mse = ccf.check_params(*need_parms,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    if cm.UserInfo.objects.filter(phone=kwargs.get("phone")).exists():
+        raise ce.TipException(u"该手机号已注册!")
+    cvals = ccf.get_need_params(*need_parms,**kwargs)
+    cvals.pop("repassword")
+    cvals["name"] = cvals["phone"]
+    if kwargs["password"] != kwargs["repassword"]:
+        raise ce.TipException(u"前后输入的密码不一致!")
+    if not cvals.get("password"):
+        pwd,password = ph.make_default_password(None)
+        cvals.update({"password":password})
+    else:
+        pwd = cvals.get("password")
+        cvals.update({"password":ph.make_password(cvals.get("password"))})
+    uobj = cm.UserInfo.objects.create(**cvals)
+    return None
+
+
+def format_user(*ids):
+    """
+    """
+    eset = cm.UserInfo.objects.filter(id__in=ids,status=1)
+    if not eset.exists():
+        raise ce.TipException(u"客户不存在!")
+    data = list(eset.values())
+    return data
+
+def get_user_info(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    info = format_user(*ids)
+    info = info[0] if info else {}
+    return info
+
+def get_user_personal_info(request):
+    """
+    """
+    id = request.user.id
+    info = format_user(*[id])
+    info = info[0] if info else {}
+    return info
+
+def get_account_info(request):
+    """
+    """
+    id = request.user.id
+    print id,99999
+    info = format_user(*[id])
+    info = info[0] if info else {}
+    info["p"] = ["Product.*.*"]
+    return info
+
+def get_user_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.UserInfo.objects.filter(status=1)
+    if "name" in kwargs and kwargs.get("name"):
+        eset = eset.filter(name__icontains=kwargs.get("name"))
+    if "department_id" in kwargs and kwargs.get("department_id"):
+        eset = eset.filter(department_id=kwargs.get("department_id"))
+    if "utype" in kwargs and kwargs.get("utype"):
+        eset = eset.filter(utype=kwargs.get("utype"))
+    if "is_active" in kwargs and kwargs.get("is_active"):
+        eset = eset.filter(is_active=kwargs.get("is_active"))
+    total = eset.count()
+    edata = list(eset.values())
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+    total,data = ccf.get_page_list(edata,page,page_size)
+    return (total,data)
+
+
+def get_unaudit_user_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.UserInfo.objects.filter(status=1,is_active=0)
+    if "name" in kwargs and kwargs.get("name"):
+        eset = eset.filter(name__icontains=kwargs.get("name"))
+    if "utype" in kwargs and kwargs.get("utype"):
+        eset = eset.filter(utype=kwargs.get("utype"))
+    total = eset.count()
+    edata = list(eset.values())
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+    total,data = ccf.get_page_list(edata,page,page_size)
+    return (total,data)
+

+ 126 - 0
src/account/lock_account.py

@@ -0,0 +1,126 @@
+# coding:utf-8
+from django.core.cache import cache
+
+import common.error_info as cei
+
+MAX_ERROR_TIMES = 5
+MAX_ERROR_TIMES_IP = 20
+LOCK_IP_TMP = 'LOCK_IP_{}'
+LOCK_ACCOUNT_TMP = 'LOCK_ACCOUNT_{}'
+
+ACCOUNT_INCR_TMP = 'ACCOUNT_COUNT_{}'
+IP_INCR_TMP = 'IP_COUNT_{}'
+
+
+def is_lock(uid, ip):
+    """
+    是否锁
+    :param uid:
+    :param ip:
+    :return:
+    """
+    account_key = LOCK_ACCOUNT_TMP.format(uid)
+    ip_key = LOCK_IP_TMP.format(ip)
+
+    if cache.get(ip_key):
+        return "ip_lock"
+    if cache.get(account_key):
+        return "account_lock"
+    return False
+
+def is_lock_ip(ip):
+    """是否封禁IP
+    """
+    ip_key = LOCK_IP_TMP.format(ip)
+    if cache.get(ip_key):
+        return True
+    return False
+
+
+def increase_error_count(uid, ip):
+    """
+    5分钟内连续输错五次
+    :return:
+    """
+    ip_key = IP_INCR_TMP.format(ip)
+    ip_count = cache.get(ip_key) or 0
+
+    account_key = ACCOUNT_INCR_TMP.format(uid)
+    account_count = cache.get(account_key) or 0
+
+    if account_count + 1 >= MAX_ERROR_TIMES or ip_count + 1 >= MAX_ERROR_TIMES:
+        lock(uid, ip)
+        raise cei.TipException(u'密码连续输错五次,锁定ip和账户半个小时')
+    if not account_count:
+        cache.set(account_key, 1, 5*60)
+    else:
+        cache.incr(account_key)
+    if not ip_count:
+        cache.set(ip_count, 1, 5*60)
+    else:
+        cache.incr(ip_key)
+
+def increase_error_count_ip(ip):
+    """
+    """
+    ip_key = IP_INCR_TMP.format(ip)
+    ip_count = cache.get(ip_key) or 0
+    if ip_count + 1 >= MAX_ERROR_TIMES_IP:
+        lock(0,ip)
+        raise cei.TipException(u'密码连续输错20次,锁定ip半个小时!')
+    if not ip_count:
+        cache.set(ip_key, 1, 30*60)
+    else:
+        cache.incr(ip_key)
+
+def increase_error_count_uid(uid):
+    """
+    """
+    account_key = ACCOUNT_INCR_TMP.format(uid)
+    account_count = cache.get(account_key) or 0
+    if account_count + 1 >= MAX_ERROR_TIMES:
+        lock(uid,0)
+        raise cei.TipException(u'密码连续输错5次,锁定账户10分钟!')
+    if not account_count:
+        cache.set(account_key, 1, 10*60)
+    else:
+        cache.incr(account_key)
+
+
+
+def clear_lock_count(uid, ip):
+    """
+    清除计数,清楚锁ip,锁account的key
+    :param uid:
+    :param ip:
+    :return:
+    """
+    if uid:
+        cache.delete(ACCOUNT_INCR_TMP.format(uid))
+    if ip:
+        cache.delete(IP_INCR_TMP.format(ip))
+
+
+def lock(uid, ip):
+    """
+    锁账户,ip半个小时
+    :param uid:
+    :param ip:
+    :return:
+    """
+    clear_lock_count(uid, ip)
+    if uid:
+        key = LOCK_ACCOUNT_TMP.format(uid)
+        cache.set(key, 'lock_account', 10*60)
+    if ip:
+        key = LOCK_IP_TMP.format(ip)
+        cache.set(key, 'lock_ip', 30*60)
+
+def clear_lock(uid,ip):
+    clear_lock_count(uid, ip)
+    if uid:
+        key = LOCK_ACCOUNT_TMP.format(uid)
+        cache.delete(key)
+    if ip:
+        key = LOCK_IP_TMP.format(ip)
+        cache.delete(IP_INCR_TMP.format(ip))

+ 6 - 0
src/account/models.py

@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models
+
+# Create your models here.

+ 36 - 0
src/account/password_handle.py

@@ -0,0 +1,36 @@
+#coding=utf-8
+'''
+@attention: 密码加密验证模块
+'''
+import hashlib
+import re
+import random
+
+def check_password(new,old):
+    """
+    """
+    np = hashlib.md5(new).hexdigest().upper()
+    return np==old
+
+def make_password(pwd,isdefault=None):
+    """
+    """
+    return hashlib.md5(pwd).hexdigest().upper()
+
+def make_default_password(pwd):
+    """
+    @attention: 密码加密
+    """
+    ustr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    lstr = "abcdefghjklmnopqrstuvwxyz"
+    dstr = "0123456789"
+    sstr = "!@#$%&*"
+    pwd = "".join(random.sample(ustr,3)+random.sample(lstr,3)+random.sample(dstr,3)+random.sample(sstr,3))
+    return pwd,hashlib.md5(pwd).hexdigest().upper()
+
+if __name__ == '__main__':
+    old = "8589103"
+    op = make_password(old)
+    print op
+    new = "123456"
+    # print check_password(new, op)

+ 29 - 0
src/account/urls_backstage.py

@@ -0,0 +1,29 @@
+# coding=utf-8
+'''
+'''
+from django.conf.urls import url
+from account import views,views_backstage
+
+urlpatterns = [
+    # 运营
+    url(r'^login$', views.LoginView.as_view()),
+    url(r'^regist$', views.RegistView.as_view()),
+    url(r'^logout$', views.LogoutView.as_view()),
+    url(r'^info$', views_backstage.InfoView.as_view()),
+    url(r'^imgcode$', views.CaptchaView.as_view()),
+    url(r'^phcode$', views.GetPhoneCodeView.as_view()),
+    url(r'^user$', views_backstage.UserView.as_view()),
+    url(r'^user/info$', views_backstage.UserInfoView.as_view()),
+    url(r'^user/list$', views_backstage.UserListView.as_view()),
+    url(r'^user/unaudit$', views_backstage.UnauditUserListView.as_view()),
+    url(r'^user/bankcard$', views_backstage.UserBankCardView.as_view()),
+    url(r'^user/bankcard/list$', views_backstage.UserBankCardListView.as_view()),
+    url(r'^user/income$', views_backstage.UserIncomeView.as_view()),
+    url(r'^user/applycash$', views_backstage.UserApplyCashView.as_view()),
+    url(r'^pwd/reset$', views_backstage.ResetPwdView.as_view()),
+    url(r'^user/pwdreset$', views_backstage.ResetUserPwdView.as_view()),
+    url(r'^permission/list', views_backstage.PermissionListView.as_view()),
+    url(r'^department$', views_backstage.DepartmentView.as_view()),
+    url(r'^department/list$', views_backstage.DepartmentListView.as_view()),
+]
+

+ 104 - 0
src/account/views.py

@@ -0,0 +1,104 @@
+# coding=utf-8
+from __future__ import unicode_literals
+import random
+import json
+import uuid
+from django.contrib import auth
+from django.core.cache import cache
+from django.conf import settings
+
+from common import core_views as cv
+from common.captcha import create_idcode
+from common.models import UserInfo
+import control_user as cr
+from utils.cloopen_sms import cloopensms
+
+class GetPhoneCodeView(cv.BaseView):
+    def send_resetpwd_code_msg(self,phones,content):
+        """重置密码短信验证码
+        """
+        template_id = "401151"
+        #if settings.SEND_SMS:
+        rst,msg = cloopensms.send(phones,template_id,content)
+        return rst,msg
+
+    def post(self, request):
+        """#获取短信验证码
+        @phone:"15982456282",手机号
+        """
+        uid = request.user.id
+        qdata = request.json
+        phone = qdata.get("phone","")
+        #phone = UserInfo.objects.filter(id=uid).first().phone
+        #if not phone:
+        #    return cv.to_normal_fail(u"参数错误")
+        rcode = "".join(random.sample('1234567890',6))
+        valid_time = 60*2
+
+        #rst,msg = self.send_resetpwd_code_msg([phone],[rcode,2])
+        rst = True
+        if rst:
+            cache.set(phone,rcode,valid_time)
+            return cv.to_suc({})
+        else:
+            return cv.to_normal_fail(msg)
+
+
+class CaptchaView(cv.BaseView):
+    def get(self, request):
+        """#获取图形验证码(管理后台)
+        >imgcode_id:"",后台返回登录时和验证码一起回传给后台
+        >imgcode:"",验证码图片base64
+        """
+        captcha, buf_str = create_idcode(4)
+        uid = str(uuid.uuid4())
+        cache.set(uid, captcha, 30 * 60)
+        return cv.to_suc({'imgcode': buf_str, 'imgcode_id': uid})
+
+class LoginView(cv.BaseView):
+    def post(self, request):
+        """#账号登录(管理后台)
+        @utype:1,0/1/2(管理员/政府/企业)
+        @username:"root",str,账号
+        @password:"root",str,密码
+        @imgcode_id:"erwerkkk",图形验证码接口返回的
+        @imgcode:"erwe",图形验证码
+        """
+        try:
+            rst = cr.login_user(request)
+            return cv.to_suc(rst)
+        except Exception as e: 
+            return cv.to_fail(e)
+
+class LogoutView(cv.AuthView):
+    def post(self, request):
+        '''
+        #退出登录(管理后台)
+        '''
+        user = request.user
+        if user:
+            user_name = user.realname
+            user_email = user.name
+        else:
+            user_name = ''
+            user_email = ''
+        auth.logout(request)
+        return cv.to_suc()
+
+class RegistView(cv.BaseView):
+    def post(self,request):
+        """#用户注册
+        @utype:1/2/3,全职/兼职/企业
+        @realname:姓名
+        @phone:"15982456282",手机号
+        @phcode:"1234",短信验证码
+        @password:"123456",密码
+        @repassword:"123456",确认密码
+        """
+        try:
+            rst = cr.regist_user(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+

+ 299 - 0
src/account/views_backstage.py

@@ -0,0 +1,299 @@
+#-*-coding:utf-8-*-
+import json
+import uuid
+from django.contrib import auth
+from django.core.cache import cache
+from django.conf import settings
+
+from common import core_views as cv
+from common.models import UserInfo
+import common.common_functions as ccf
+import common.error_info as ce
+import control_user as cu
+import control_role as crol
+import control_organization as co
+import common.common_control as ccc
+import control_permission as cp
+import control_department as cd
+import control_bankcard as cb
+
+
+class InfoView(cv.AdminView):
+    def get(self, request):
+        '''
+        #获取全局账号信息(权限控制)
+        '''
+        try:
+            users = cu.get_account_info(request)
+            return cv.to_suc(users)
+        except Exception as e:
+            return cv.to_fail(e)
+
+class UserInfoView(cv.BaseView):
+    def get(self, request):
+        """
+        #获取用户个人信息
+        @id:1,用户id
+        """
+        try:
+            data = cu.get_user_personal_info(request)
+            return cv.to_suc(data)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+class UserView(cv.BaseView):
+    def get(self, request):
+        """
+        #获取用户详情
+        @id:1,用户id
+        """
+        try:
+            data = cu.get_user_info(request)
+            return cv.to_suc(data)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+    def post(self, request):
+        '''
+        #新增员工
+        @realname:"肖小肖",员工名称
+        @phone:"129823"
+        @email:"129823@qq.com"
+        @department_id:1,部门id
+        @utype:1/2/3,员工类型
+        @is_active:1/0,是否启用
+        @remark:"好员工",备注
+        '''
+        qdata = request.json
+        try:
+            rst = cu.add_user(request)
+            return cv.to_suc()
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+    def put(self, request):
+        """
+        #修改员工
+        @id:1,员工id
+        @realname:"肖小肖",员工名称
+        @phone:"129823"
+        @email:"129823@qq.com"
+        @department_id:1,部门id
+        @utype:1/2/3,员工类型
+        @is_active:1/0,是否启用
+        @remark:"好员工",备注
+        """
+        qdata = request.json
+        try:
+            data = cu.update_user(request)
+        except Exception as e:
+            return cv.to_fail(e)
+        return cv.to_suc(data)
+
+    def delete(self, request):
+        """
+        #删除员工
+        @id:1,多个id用逗号分隔
+        """
+        qdata = request.json
+        try:
+            cu.delete_user(request)
+        except Exception as e:
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+class UserListView(cv.AuthView):
+    def get(self, request):
+        """
+        #员工列表
+        @name:"用户名"
+        @department_id:1
+        @utype:1
+        @is_active:1
+        """
+        try:
+            total,res = cu.get_user_list(request)
+            return cv.to_suc({"total":total,"list":res})
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class UnauditUserListView(cv.AuthView):
+    def get(self, request):
+        """
+        #待审核员工列表
+        @name:"用户名"
+        @utype:1
+        """
+        try:
+            total,res = cu.get_unaudit_user_list(request)
+            return cv.to_suc({"total":total,"list":res})
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class PermissionListView(cv.AuthView):
+    def get(self, request):
+        """#权限列表
+        @role_id:1 角色id 可选参数 传了就只返回对应角色的权限
+        @platform:"operation" 权限归属 可选参数 传了就对权限进行平台过滤
+        """
+        qdata = request.json
+        role_id = qdata.get("role_id",None)
+        platform = qdata.get("platform",None)
+        roles = cp.get_permission_list(role_id,platform)
+
+        return cv.to_suc(roles)
+
+
+class ResetPwdView(cv.BaseView):
+    def put(self, request):
+        """
+        #重置密码(忘记密码)
+        @phone:"15982456282",手机号
+        @password:"",新密码
+        @repassword:"",确认密码
+        @phcode:"123",验证码
+        """
+        try:
+            cu.reset_password(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class ResetUserPwdView(cv.AuthView):
+    def put(self, request):
+        """
+        #修改用户密码
+        @uid:10,用户id不传则默认当前用户
+        @code:"",验证码
+        @password:"",新密码
+        """
+        try:
+            cu.reset_user_password(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class DepartmentView(cv.AuthView):
+    def post(self,request):
+        """
+        #新增部门
+        @name:"综管部",部门名称
+        @pid:1,上级部门
+        @permissions:["CusManage.*.*","CusManage.MyCus.*"]
+        """
+        try:
+            cd.add_department(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+    def put(self,request):
+        """
+        #修改部门
+        @id:1,部门id
+        @name:"综管部",部门名称
+        @pid:1,上级部门
+        @permissions:["CusManage.*.*","CusManage.MyCus.*"]
+        """
+        try:
+            cd.update_department(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+    def delete(self,request):
+        """
+        #删除部门
+        @id:1,部门id
+        """
+        try:
+            cd.delete_department(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class DepartmentListView(cv.AuthView):
+    def get(self,request):
+        """#部门列表
+        @name:"研发",部门名称
+        """
+        try:
+            total,rst = cd.get_department_list(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc({"total":total,"list":rst})
+
+
+class UserBankCardView(cv.AuthView):
+    def post(self,request):
+        """#新增银行卡
+        @name:"建设银行",银行名称
+        @cardno:"6229000",银行卡卡号
+        """
+        try:
+            rst = cb.add_bankcard(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+    def delete(self,request):
+        """#删除银行卡
+        @id:1,银行卡id
+        """
+        try:
+            rst = cb.delete_bankcard(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+
+class UserBankCardListView(cv.AuthView):
+    def get(self,request):
+        """#银行卡列表
+        """
+        try:
+            rst = cb.get_bankcard_list(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc(rst)
+
+
+class UserIncomeView(cv.AuthView):
+    def get(self,request):
+        """#我的收益
+        """
+        try:
+            rst = cb.get_user_income(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc(rst)
+
+
+class UserApplyCashView(cv.AuthView):
+    def post(self,request):
+        """#申请提现
+        @bankcard_id:1,银行卡id
+        @cashtype:"bank/alipay",提现方式
+        @cashamount:1000,提现金额
+        """
+        try:
+            rst = cb.apply_cash(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc(rst)

+ 4 - 0
src/account/views_permission.py

@@ -0,0 +1,4 @@
+#-*-coding:utf-8 -*-
+import common.core_views as cv
+
+

+ 12 - 0
src/asgi.py

@@ -0,0 +1,12 @@
+"""
+ASGI entrypoint. Configures Django and then runs the application
+defined in the ASGI_APPLICATION setting.
+"""
+
+import os
+import django
+import channels.asgi
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
+django.setup()
+application = channels.asgi.get_channel_layer()

+ 0 - 0
src/common/__init__.py


+ 89 - 0
src/common/captcha.py

@@ -0,0 +1,89 @@
+# coding:utf-8
+import base64
+import random
+
+import StringIO
+from PIL import ImageDraw, ImageFont, Image
+
+
+def create_idcode(mlen):
+    """
+    @attention: 生成验证码
+    @param mlen: 验证码长度
+    @return: [验证码字符串,验证码图片base64]
+    @note:
+    > 生成验证码
+    > 创建图片和画笔
+    > 准备验证码图片基本配置,包括
+    > 填充验证码
+    > 填充干扰线
+    > 添加滤镜/扭曲
+    """
+    code = get_random_code(mlen)
+    # 创建图片和画笔
+    width = 100
+    height = 40
+    size = (width, height)
+    #6CC4B3
+    image = Image.new("RGBA", size, "#F5F5F7")
+    draw = ImageDraw.Draw(image)
+    fill_code(code, mlen, draw, width, height)
+    draw_line(draw, width, height, 5)
+    draw_points(draw, 10, width, height)
+    #image = image.transform((width+20,height+10), Image.AFFINE, (1,-0.3,0,-0.1,1,0),Image.BILINEAR)  #创建扭曲
+    #image = image.filter(ImageFilter.EDGE_ENHANCE_MORE) #滤镜,边界加强
+    buf = StringIO.StringIO()
+    image.save(buf, 'png', quality=70)
+    buf_str = base64.b64encode(buf.getvalue())
+    return ''.join(code), "data:image/png;base64,"+buf_str
+
+############## 辅助函数 ##############
+def rndColor():
+    """
+    随机颜色
+    :return:
+    """
+    return random.randint(32, 127), random.randint(32, 127), random.randint(32, 127)
+
+def get_random_code(number):
+    """
+    @attention: 获取随机码(排除难以识别的o,0,i,1,z,2等)
+    """
+    return random.sample("abcdefghjkmnpqrstuvwxyABCDEFGHJKMNPQRSTUVWXY3456789", number)
+
+
+def fill_code(code, number, draw, width, height):
+    """
+    @attention: 填充验证码
+    @param code: 验证码
+    @param draw: 画笔
+    """
+    font_path = "common/font/consola.ttf"
+    font = ImageFont.truetype(font_path, 34)  # 验证码的字体和字体大小
+    for t in xrange(number):
+        draw.text((20 * t + 10, 3 if(t%2) else -3),  code[t], font=font, fill=rndColor())
+
+
+def draw_line(draw, width, height, number=1):
+    for i in xrange(number):
+        begin = (random.randint(0, width / 2), random.randint(0, height))
+        end = (random.randint(width / 2, width), random.randint(0, height))
+        draw.line([begin, end], fill="#6CC4B3", width=3)
+
+
+def draw_points(draw, point_chance, width, height):
+    """
+    绘制干扰点
+    :param draw: 画笔
+    :param point_chance: 干扰点出现概率:0到100
+    :param width:
+    :param height:
+    :return:
+    """
+    chance = min(100, max(0, int(point_chance)))  # 大小限制在[0, 100]
+
+    for w in xrange(width):
+        for h in xrange(height):
+            tmp = random.randint(0, 100)
+            if tmp > 100 - chance:
+                draw.point((w, h), fill=(0, 0, 0))

+ 90 - 0
src/common/common_control.py

@@ -0,0 +1,90 @@
+# coding:utf-8
+import os,time
+import sys
+import django
+import json
+from django.core.cache import cache
+from django.core.paginator import Paginator
+from django.conf import settings
+
+import common.models as cm
+import common.common_functions as ccf
+
+def cache_data(timeout=60*60):
+    def _wrapper(func):
+        def __wrapper(*args,**kwargs):
+            if args:
+                key = "cdata_{}_{}".format(func.__name__,str(args))
+            else:
+                key = "cdata_{}".format(func.__name__)
+            if not kwargs.get("cache",True) or not cache.get(key):
+                res = func(*args,**kwargs)
+                cache.set(key,res,timeout)
+                #print u"不取缓存!!!!!!!!!"
+                return res
+            else:
+                #print u"取缓存"
+                return cache.get(key)
+        return __wrapper
+    return _wrapper
+
+
+def no_cache(key="*"):
+    def _wrapper(func):
+        def __wrapper(*args,**kwargs):
+            res = func(*args,**kwargs)
+            print cache.delete_pattern("cdata_{}*".format(key))
+            return res
+        return __wrapper
+    return _wrapper
+
+
+def no_cache_list(keys=[]):
+    def _wrapper(func):
+        def __wrapper(*args,**kwargs):
+            res = func(*args,**kwargs)
+            for key in keys:
+                print cache.delete_pattern("cdata_{}*".format(key))
+            return res
+        return __wrapper
+    return _wrapper
+
+
+def get_page_qset(qset,page,page_size=20):
+    """
+    """
+    count = qset.count()
+    if page and page_size:
+        paginator = Paginator(qset,page_size)
+        object_list = paginator.page(page).object_list
+    else:
+        object_list = qset
+    return count,object_list
+
+def upload_file(request):
+    """
+    """
+    upload_file = request.FILES['file']
+    ext = os.path.splitext(upload_file.name)[-1]
+    timestamp = str(int(time.time()*1000))
+    #dest = settings.STATIC_ROOT + "/upload/"+str(int(time.time()*1000)) + upload_file.name
+    dest = settings.STATIC_ROOT + "/upload/"+ timestamp + ext
+    with open(dest,"wb+") as f:
+        for chunk in upload_file.chunks():
+            f.write(chunk)
+    f.close()
+    url = dest.replace(settings.STATIC_ROOT,settings.HOST)
+    rst = {"url":url,"type":request.POST.get("type"),"name":upload_file.name}
+    #
+    if ext == ".mp4":
+        imgpath = settings.STATIC_ROOT + "/upload/" + timestamp + ".png"
+        cmd = "ffmpeg  -i {}  -ss 1.000 -vframes 1 {}".format(dest,imgpath)
+        os.system(cmd)
+        imgurl = imgpath.replace(settings.STATIC_ROOT,settings.HOST)
+        rst["imgurl"] = imgurl
+    return rst
+
+
+if __name__ == "__main__":
+    #测试
+    print get_pparents_info(1550,[])

+ 190 - 0
src/common/common_functions.py

@@ -0,0 +1,190 @@
+# coding:utf-8
+import calendar
+import hashlib
+import datetime
+import re
+import M2Crypto
+from PIL import Image,ImageDraw
+
+def get_month_dates(month="202008"):
+    """
+    """
+    dates = []
+    now = datetime.datetime.now().date()
+    now_date_str = now.strftime("%Y%m")
+    day_end = calendar.monthrange(int(now_date_str[0:4]),int(now_date_str[4:6]))[1]
+    for i in range(1,day_end):
+        dates.append(now_date_str+"%02d" % i)
+    return dates
+
+def check_password(new,old):
+    """
+    """
+    np = hashlib.md5(new).hexdigest().upper()
+    return np==old
+
+def make_password(pwd,isdefault=None):
+    """
+    """
+    return hashlib.md5(pwd).hexdigest().upper()
+
+def addText(orgpath,string,path):
+    img = Image.open(orgpath)
+    size = img.size
+    width = size[0] - 20
+    high = size[1] - 20
+    lenth = len(string)*3
+    draw = ImageDraw.Draw(img)
+    draw.text((width-lenth,high),string,fill='black')
+    img.save(path)
+
+def list_split(items, n):
+    return [items[i:i+n] for i in range(0, len(items), n)]
+
+def str_to_datetime(tm,format="%Y-%m-%d %H:%M:%S"):
+    """
+    """
+    datetimestr = datetime.datetime.strptime(tm,format)
+    return datetimestr
+
+def datetime_to_str(tm,format="%Y-%m-%d %H:%M:%S"):
+    """
+    """
+    datetimestr = datetime.datetime.strftime(tm,format)
+    return datetimestr
+
+def get_now_str(format="%Y-%m-%d %H:%M:%S"):
+    """获取当前时间并转化成制定格式字符串
+    """
+    now = datetime.datetime.now()
+    return datetime.datetime.strftime(now,format)
+
+def check_pub_key(pub_key):
+    """检查证书有效性
+    """
+    try:
+        pub_key = M2Crypto.X509.load_cert_string(str(pub_key)) 
+        return 1
+    except:
+        return 0
+
+def check_priv_key(priv_key):
+    """检查私钥有效性
+    """
+    try:
+        M2Crypto.RSA.load_key_string(str(priv_key)) 
+        return 1
+    except:
+        return 0
+
+
+def check_pub_priv_key(pub_key, priv_key):
+    if len(pub_key) == 0 and len(priv_key) == 0:
+        return 0
+    msg = "hello"
+    try:
+        cert = M2Crypto.X509.load_cert_string(str(pub_key))
+        key = M2Crypto.RSA.load_key_string(str(priv_key))
+        encrypted = cert.get_pubkey().get_rsa().public_encrypt(msg, M2Crypto.RSA.pkcs1_padding)
+        decrypted = key.private_decrypt(encrypted, M2Crypto.RSA.pkcs1_padding)
+        if msg != decrypted:
+            return 0
+            return errno.INVALID_CERT
+    except:
+        return 0
+        return errno.INVALID_CERT
+    return 1
+
+
+def get_day_range(yesterday):
+    """
+    @attention: 获取昨天数据
+    """
+    sd = ed = yesterday.strftime("%Y%m%d")
+    return sd,ed
+
+def get_week_range(yesterday):
+    """
+    @attention: 获取最近一周数据
+    """
+    ed = yesterday.strftime("%Y%m%d")
+    sd = yesterday - datetime.timedelta(days=6)
+    sd = sd.strftime("%Y%m%d")
+    return sd,ed
+
+def get_month_range(yesterday,today_month,days):
+    """
+    @attention: 获取最近一个月数据
+    """
+    ed = yesterday.strftime("%Y%m%d")
+    temp = datetime.datetime.strptime(today_month,"%Y%m")-datetime.timedelta(days=1)
+    last_month = temp.strftime("%Y%m")
+    sd = "%s%s"%(last_month,str(days).rjust(2,"0"))
+    return sd,ed
+
+
+def list_group_by(olist,key,sort=None):
+    """
+    """
+    nlist = []
+    tmp = {}
+    for ol in olist:
+        kkey = ol[key]
+        if not tmp.has_key(kkey):
+            tmp[kkey] = [0]
+        else:
+            tmp[kkey].append(ol)
+    for k,v in tmp.items():
+        dct = {key:k,"data":v,"count":len(v)}
+        nlist.append(dct)
+    if sort:
+        nlist = sorted(nlist,key=lambda x:x["count"])
+    return nlist
+
+def get_need_params(*need_parms,**kwargs):
+    """
+    """
+    newdct = {}
+    need_parms = set(need_parms).intersection(set(kwargs.keys()))
+    for k in need_parms:
+        newdct[k] = kwargs.get(k)
+    return newdct
+
+def check_params(*need_parms,**kwargs):
+    if not set(need_parms).issubset(set(kwargs.keys())):
+        miss = list(set(need_parms)-set(kwargs.keys()))
+        miss = ",".join(miss)
+        return "缺少参数:{}".format(miss)
+    for nk in need_parms:
+        if not kwargs.get(nk):
+            return "缺少参数值:{}!".format(nk)
+    return None
+
+def get_page_list(list,page,page_size=20):
+    """
+    """
+    page = int(page)
+    page_size = int(page_size)
+    if page and page_size:
+        start = (page - 1)*page_size
+        end = page * page_size
+        count = len(list)
+        list = list[start:end]
+    else:
+        count = len(list)
+    return count,list
+
+def get_ip(request):
+    if request.META.has_key('HTTP_X_REAL_IP'):
+        ip = request.META['HTTP_X_REAL_IP']
+    elif request.META.has_key('HTTP_X_FORWARDED_FOR'):
+        ip = request.META['HTTP_X_FORWARDED_FOR']
+    else:
+        ip = request.META['REMOTE_ADDR']
+    return ip
+
+if __name__ == "__main__":
+    pass
+
+
+

+ 70 - 0
src/common/common_notice.py

@@ -0,0 +1,70 @@
+# coding:utf-8
+import os
+import sys
+import django
+import json
+from django.core.cache import cache
+from django.core.paginator import Paginator
+
+import common.models as cm
+import common.common_functions as ccf
+
+def send_audit_notice(user_id,subject_item):
+    """发送审核通知
+    """
+    title = u"报名审核通过"
+    content = u"您好,你在巴中逸沣安全培训报名的{}已审核通过,请尽快去支付!".format(subject_item)
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+def send_unauthed_notice(user_id):
+    """审核不通过短信通知
+    """
+    title = u"报名审核不通过"
+    content = u"学员您好,您在巴中逸沣安全培训报名提交的资料不符合要求,请检查后重新上传。"
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+def send_update_notice(user_id,name,subject_item):
+    """证件复审通知
+    """
+    title = u"证件复审到期通知"
+    content = u"您好:{},您的{}证件即将到复审时间 ,为避免证件被注销,请尽快报名参加复审,为节约您的时间与费用可关注我公司微信公众号(BZYF2016)在线报名上传相关资料。".format(name,subject_item)
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+def send_expired_notice(user_id,name,subject_item):
+    """证件到期通知
+    """
+    title = u"证件换证到期通知"
+    content = u"您好:{},您的{}证件即将到期 ,为避免证件被注销,请您提前3个月报名参加培训,为节约您的时间与费用可关注我公司微信公众号(BZYF2016)在线报名上传相关资料,也请您在线报名成功后模拟练习题库试题。".format(name,subject_item)
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+def send_pay_notice(user_id):
+    """支付成功通知
+    """
+    title = u"报名支付成功通知"
+    content = u"学员您好:您已支付成功,请在您手机端完成线上学习课时后才能安排考试,考试时间会提前电话通知或查看在线报名页面消息栏。"
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+def send_training_notice(user_id,subject_item,begin_time,end_time):
+    """培训通知
+    """
+    title = u"负责人、安全员、从业人员培训通知"
+    content = u"培训名称:{} 开始时间:{} 结束时间:{} 培训地点:巴中市江北车站三楼 注意事项:(计算机考试工种:网上报名成功后,不用再提交纸质资料,考试时间另行通知),(纸张考试工种:需提交本人身份证复印件1张,蓝底1寸照片2张,毕业证书复印件1张或户口薄本人显示学历页复印件1张)。 联系电话:0827-8589103".format(subject_item,begin_time,end_time)
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+def send_training_notice_special(user_id,subject_item,begin_time):
+    """培训通知
+    """
+    title = u"特种作业人员培训通知"
+    content = u"培训名称:{} 培训时间:{} 培训地点:巴中市江北车站三楼 注意事项:携带本人身份证原件,(复审、换证)人员请带上以前老证 联系电话:0827-8589102".format(subject_item,begin_time)
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+def send_exam_notice(user_id,name,subject_item,exam_time):
+    """培训通知
+    """
+    title = u"特种作业人员培训通知"
+    content = u"您好,{},您参加的{}培训即将考试,请注意。考试时间:{} 9:30 考试地点:兴文东锦社区1500米处(巴中经开区人才大楼)2楼,地图导航输入(巴中市安全生产考试中心)联系电话:15884997924 请在考试当日携带本人身份证原件与口罩准时参加考试,切勿迟到!祝考试顺利!".format(name,subject_item,exam_time)
+    cm.SysNotice.objects.create(title=title,content=content,to=user_id)
+
+if __name__ == "__main__":
+    #测试
+    pass

+ 355 - 0
src/common/core_views.py

@@ -0,0 +1,355 @@
+#coding=utf-8
+'''
+'''
+import json
+import logging
+import re
+import traceback
+import datetime
+import hashlib
+from utils.aestool import aescbc
+
+from django import http
+from django.contrib.sessions.backends.cache import SessionStore
+from django.core.cache import cache
+from django.http import HttpResponse, JsonResponse
+from django.shortcuts import render
+from django.utils.decorators import method_decorator
+from django.views import View
+from django.views.decorators.csrf import csrf_exempt
+from django.core.serializers.json import DjangoJSONEncoder
+
+from common import error_info
+from common.models import UserInfo
+import common.models as cm
+import common.error_info as ce
+
+logger = logging.getLogger(__name__)
+
+
+class CusDjangoJSONEncoder(json.JSONEncoder):
+    """
+    JSONEncoder subclass that knows how to encode date/time, decimal types and UUIDs.
+    """
+    def default(self, o):
+        # See "Date Time String Format" in the ECMA-262 specification.
+        if isinstance(o, datetime.datetime):
+            r = datetime.datetime.strftime(o,'%Y-%m-%d %H:%M:%S')
+            return r
+        elif isinstance(o, datetime.date):
+            return o.isoformat()
+        elif isinstance(o, datetime.time):
+            if is_aware(o):
+                raise ValueError("JSON can't represent timezone-aware times.")
+            r = o.isoformat()
+            if o.microsecond:
+                r = r[:12]
+            return r
+        elif isinstance(o, datetime.timedelta):
+            return duration_iso_string(o)
+        elif isinstance(o, decimal.Decimal):
+            return str(o)
+        elif isinstance(o, uuid.UUID):
+            return str(o)
+        elif isinstance(o, Promise):
+            return six.text_type(o)
+        elif isinstance(o, CallableBool):
+            return bool(o)
+        else:
+            return super(DjangoJSONEncoder, self).default(o)
+
+
+class AuthView(View):
+
+    @method_decorator(csrf_exempt)
+    def dispatch(self, request, *args, **kwargs):
+        """
+        @attention: as_view()方法使用该方法来分发不同http method,添加异常处理及登陆校验
+        """
+        if request.method.lower() in self.http_method_names:
+            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
+        else:
+            handler = self.http_method_not_allowed
+        return api_wapper(handler, request, True, *args, **kwargs)
+
+class AdminView(View):
+
+    @method_decorator(csrf_exempt)
+    def dispatch(self, request, *args, **kwargs):
+        """
+        @attention: as_view()方法使用该方法来分发不同http method,添加异常处理及登陆校验
+        """
+        self.http_method_names.append("options")
+        if request.method.lower() in self.http_method_names:
+            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
+        else:
+            handler = self.http_method_not_allowed
+        return admin_handler(handler, request, True, *args, **kwargs)
+
+class YRXView(View):
+
+    @method_decorator(csrf_exempt)
+    def dispatch(self, request, *args, **kwargs):
+        """
+        @attention: as_view()方法使用该方法来分发不同http method,添加异常处理及登陆校验
+        """
+        self.http_method_names.append("options")
+        if request.method.lower() in self.http_method_names:
+            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
+        else:
+            handler = self.http_method_not_allowed
+        return yrx_handler(handler, request, True, *args, **kwargs)
+
+
+class BaseView(View):
+
+    @method_decorator(csrf_exempt)
+    def dispatch(self, request, *args, **kwargs):
+        """
+        @attention: as_view()方法使用该方法来分发不同http method,添加异常处理及登陆校验
+        """
+        if request.method.lower() in self.http_method_names:
+            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
+        else:
+            handler = self.http_method_not_allowed
+
+        return api_wapper(handler, request, False, *args, **kwargs)
+
+
+class UploadView(View):
+    
+    @method_decorator(csrf_exempt)
+    def dispatch(self, request, *args, **kwargs):
+        """
+        @attention: as_view()方法使用该方法来分发不同http method,添加异常处理及登陆校验
+        """
+        if request.method.lower() in self.http_method_names:
+            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
+        else:
+            handler = self.http_method_not_allowed
+
+        return upload_wapper(handler,request,True, *args, **kwargs)
+
+
+class InnerView(View):
+    
+    @method_decorator(csrf_exempt)
+    def dispatch(self, request, *args, **kwargs):
+        """
+        @attention: as_view()方法使用该方法来分发不同http method,添加异常处理及登陆校验
+        """
+        if request.method.lower() in self.http_method_names:
+            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
+            if request.META.get("HTTP_TOKEN") != "7dpHIhpweckghdoSvrXwMftcjZRIzKwJ":
+                handler = self.http_method_not_allowed
+        else:
+            handler = self.http_method_not_allowed
+
+        return api_wapper(handler, request, False, *args, **kwargs)
+
+
+def show_history(request):
+    logined_history = cache.get("logined_history", {})
+    for k, v in logined_history.iteritems():
+        logger.info("k: %s, v: %s", str(k), str(v))
+    logger.info("current session: %s", str(request.session.session_key))
+    ss = SessionStore(request.session.session_key)
+    for k, v in ss.iteritems():
+        logger.info("k: %s, v: %s", str(k), str(v))
+
+
+def api_wapper(handler, request, is_vauth, *args, **kwargs):
+    """
+    @attention: 调试API时使用的装饰器
+    """
+    req_path = request.META["PATH_INFO"]
+    ip = request.META.get("HTTP_X_REAL_IP","")
+    token = request.META.get("HTTP_AUTHORIZATION")
+    if is_vauth:
+        if token:
+            dec_name = aescbc.decrypt(token)
+            name = dec_name.split("_")[0]
+            utype = dec_name.split("_")[1]
+            if utype == 1:
+                user = cm.Goverment.objects.filter(id=name).first()
+            elif utype == 2:
+                user = cm.EnterPrise.objects.filter(id=name).first()
+            else:
+                user = cm.StaffUser.objects.filter(id=name).first()
+            if not user and False:
+                return JsonResponse({"code":403,"data":{}})
+                #return HttpResponse(status=403)
+
+            setattr(request, "ip", get_ip(request))
+            setattr(request, "user", user)
+            setattr(request, "utype", utype)
+            if request.method == "OPTIONS":
+                return JsonResponse({})
+        else:
+            return JsonResponse({"code":403,"data":{}})
+
+    body = request.body if hasattr(request, "body") else ""
+    if "x-www-form-urlencoded" in request.content_type:
+        info = http.QueryDict(body).dict()
+        if not info:
+            info = request.GET.dict()
+    elif "application/json" in request.content_type:
+        info = json.loads(body) if body else {}
+        if not info:
+            info = request.GET.dict()
+    else:
+        try:
+            info = json.loads(body) if body else {}
+            if not info:
+                info = request.GET.dict()
+        except:
+            info = {}
+    setattr(request, "json", info)
+
+    try:
+        ret = handler(request, *args, **kwargs)
+        return ret
+    except Exception as e:
+        return to_fail(e)
+
+def admin_handler(handler, request, is_vauth, *args, **kwargs):
+    """
+    登录session校验
+    """
+    req_path = request.META["PATH_INFO"]
+    ip = request.META.get("HTTP_X_REAL_IP","")
+    token = request.META.get("HTTP_AUTHORIZATION")
+    if is_vauth and token:
+        dectoken = aescbc.decrypt(token)
+        name = dectoken.split("_")[0]
+        utype = dectoken.split("_")[1]
+        if str(utype) == "0":
+            user = UserInfo.objects.filter(id=name).first()
+        elif str(utype) == "1": 
+            user = cm.Goverment.objects.filter(id=name).first()
+        else:
+            user = cm.EnterPrise.objects.filter(id=name).first()
+        if not user and False:
+            #return JsonResponse({"code":403,"data":{}})
+            return HttpResponse(status=403)
+
+        setattr(request, "ip", get_ip(request))
+        setattr(request, "user", user)
+        setattr(request, "utype", utype)
+        if request.method == "OPTIONS":
+            return JsonResponse({})
+
+    body = request.body if hasattr(request, "body") else ""
+    if "x-www-form-urlencoded" in request.content_type:
+        info = http.QueryDict(body).dict()
+        if not info:
+            info = request.GET.dict()
+    elif "application/json" in request.content_type:
+        info = json.loads(body) if body else {}
+        if not info:
+            info = request.GET.dict()
+    else:
+        try:
+            info = json.loads(body) if body else {}
+            if not info:
+                info = request.GET.dict()
+        except:
+            info = {}
+
+    setattr(request, "json", info)
+
+    try:
+        ret = handler(request, *args, **kwargs)
+        return ret
+    except Exception as e:
+        return to_fail(e)
+
+def yrx_handler(handler, request, is_vauth, *args, **kwargs):
+    """
+    登录session校验
+    """
+    req_path = request.META["PATH_INFO"]
+    ip = request.META.get("HTTP_X_REAL_IP","")
+    token = request.META.get("HTTP_AUTHORIZATION")
+    if is_vauth and token:
+        dectoken = aescbc.decrypt(token)
+        name = dectoken.split("_")[0]
+        utype = dectoken.split("_")[1]
+        if str(utype) == "0":
+            user = cm.YRXUser.objects.filter(id=name).first()
+        elif str(utype) == "1": 
+            user = cm.YRXUser.objects.filter(id=name).first()
+        else:
+            user = cm.YRXUser.objects.filter(id=name).first()
+        if not user and False:
+            #return JsonResponse({"code":403,"data":{}})
+            return HttpResponse(status=403)
+
+        setattr(request, "ip", get_ip(request))
+        setattr(request, "user", user)
+        setattr(request, "utype", utype)
+        if request.method == "OPTIONS":
+            return JsonResponse({})
+
+    body = request.body if hasattr(request, "body") else ""
+    if "x-www-form-urlencoded" in request.content_type:
+        info = http.QueryDict(body).dict()
+        if not info:
+            info = request.GET.dict()
+    elif "application/json" in request.content_type:
+        info = json.loads(body) if body else {}
+        if not info:
+            info = request.GET.dict()
+    else:
+        try:
+            info = json.loads(body) if body else {}
+            if not info:
+                info = request.GET.dict()
+        except:
+            info = {}
+
+    setattr(request, "json", info)
+
+    try:
+        ret = handler(request, *args, **kwargs)
+        return ret
+    except Exception as e:
+        return to_fail(e)
+
+def to_suc(data={}):
+    info = {}
+    info["data"] = data
+    info["code"] = 0
+    return JsonResponse(info,encoder=CusDjangoJSONEncoder)
+
+def to_fail(e=None):
+    info = {}
+    info["code"] = 1000
+    if isinstance(e,ce.TipException):
+        info["message"] = e.msg
+    else:
+        info["message"] = str(e)
+    return JsonResponse(info)
+
+def tracefail():
+    traceback.print_exc()
+
+def stream_file(content, content_type, file_name):
+    """
+    输出文件
+    :param content: 内容 StringIO 类型
+    :param content_type: 类型  eg: "application/vnd.ms-excel"
+    :param file_name: 文件名(需指定后缀)
+    """
+    response = HttpResponse(content=content, content_type=content_type)
+    response['Content-Disposition'] = 'attachment; filename={}'.format(file_name)
+    return response
+
+def get_ip(request):
+    if request.META.has_key('HTTP_X_REAL_IP'):
+        ip = request.META['HTTP_X_REAL_IP']
+    elif request.META.has_key('HTTP_X_FORWARDED_FOR'):
+        ip = request.META['HTTP_X_FORWARDED_FOR']
+    else:
+        ip = request.META['REMOTE_ADDR']
+    return ip

+ 227 - 0
src/common/custom_tools.py

@@ -0,0 +1,227 @@
+#coding=utf-8
+'''
+Created on 2017年11月14日
+
+@author: bailiangjun
+'''
+def change_dict_p2m(item,p2m,ms=[],ems=[]):
+    """
+    @attention: 把指定信息的关键字换成对应的模型字段m
+    @param item: 默认为 {p:值}
+    @note: 
+    {p:值} ==> {m:值}
+    如果传入指定序列ps,则只取序列中的值
+    如果传入指定序列eps,则取除eps以外的值
+    """
+    if not item:
+        return {}
+    
+    if not ms:
+        ms = set(p2m.itervalues())
+    temp = {p:m for p,m in p2m.iteritems() if (m in ms) and (m not in ems)}
+    return {m:item.get(p,"") for p,m in temp.iteritems()}
+
+def change_dict_m2p(item,p2m,ms=[],ems=[]):
+    """
+    @attention: 把指定信息的关键字换成对应的api协议字段
+    @param item: 默认为 {m:值}
+    @note: 
+    {m:值} ==> {p:值}
+    如果传入指定序列ps,则只取序列中的值
+    如果传入指定序列eps,则取除eps以外的值
+    """
+    if not item:
+        return {}
+    
+    if not ms:
+        ms = set(p2m.itervalues())
+    
+    temp = {p:m for p,m in p2m.iteritems() if (m in ms) and (m not in ems)}
+    return {p:item.get(m,"") for p,m in temp.iteritems()}
+
+
+def change_list_p2m(item,p2m,ms=[],ems=[]):
+    """
+    @attention: 把指定信息的关键字换成对应的模型字段m,针对列表
+    @param item: 默认为 {p:值}
+    @note: 
+    {p:值} ==> {m:值}
+    如果传入指定序列ps,则只取序列中的值
+    如果传入指定序列eps,则取除eps以外的值
+    """
+    if not item:
+        return []
+    
+    if not ms:
+        ms = set(p2m.itervalues())
+    
+    temp = {p:m for p,m in p2m.iteritems() if (m in ms) and (m not in ems)}
+
+    return map(lambda x:{m:x.get(p,"") for p,m in temp.iteritems()}, item)
+
+
+def change_list_m2p(item,p2m,ms=[],ems=[]):
+    """
+    @attention: 把指定信息的关键字换成对应的api协议字段,针对列表
+    @param item: 默认为 {m:值}
+    @note: 
+    {m:值} ==> {p:值}
+    如果传入指定序列ps,则只取序列中的值
+    如果传入指定序列eps,则取除eps以外的值
+    """
+    if not item:
+        return []
+    
+    if not ms:
+        ms = set(p2m.itervalues())
+    
+    temp = {p:m for p,m in p2m.iteritems() if (m in ms) and (m not in ems)}
+    return map(lambda x:{p:x.get(m,"") for p,m in temp.iteritems()}, item)
+
+
+def change_node_m2p(item, p2m, ms=[], ems=[]):
+    """
+    @attention: 把指定信息的关键字换成对应的api协议字段,针对列表
+    @param item: 默认为 {m:值}
+    @note:
+    {m:值} ==> {p:值}
+    如果传入指定序列ps,则只取序列中的值
+    如果传入指定序列eps,则取除eps以外的值
+    """
+    if not item:
+        return []
+
+    if not ms:
+        ms = set(p2m.itervalues())
+
+    temp = {p: m for p, m in p2m.iteritems() if (m in ms) and (m not in ems)}
+    return map(lambda x: {p: x.get(m, "") for p, m in temp.iteritems()}, item)
+
+
+def transfer_top_info(info, lkey, tkey):
+    """
+    @attention: 转换top数据给前端
+    @note:
+            由 二维数组[[标签,值],[]]---> [{label:标签,"times":值}]
+    """
+    return [{"name": item[lkey], "value": item[tkey]} for item in info]
+
+
+def transfer_list_info(info, params):
+    """
+    @attention: 转换趋势数据给前端
+    """
+    if not info:
+        return {"axis_x": [], "axis_y": {}}
+
+    if isinstance(params, list):
+        params = {item: [item] for item in params}
+
+    print params
+
+    pkeys = params.keys()
+    if len(pkeys) == 1:
+        key = pkeys[0]
+        inkeys = params[key]
+        inkeys = inkeys if inkeys else [key]
+        v = info[key]
+        axis_x = [item["dt"] for item in v]
+        axis_y = {}
+        for ik in inkeys:
+            axis_y[ik] = [item[ik] for item in v]
+    else:
+        axis_y = {}
+        for key in pkeys:
+            inkeys = params[key]
+            inkeys = inkeys if inkeys else [key]
+            v = info[key]
+            axis_x = [item["dt"] for item in v]
+            for ik in inkeys:
+                axis_y[ik] = [item[ik] for item in v]
+
+    return {"axis_x": axis_x, "axis_y": axis_y}
+
+
+def classify_access_statistic_info(info):
+    """
+    @attention: 区分access统计数据项
+    """
+    total_values = []
+    list_values = []
+    top_values = {}
+    if info.has_key("total_hit_flow"):
+        total_values.append("hit_flow")
+
+    if info.has_key("total_hit_num"):
+        total_values.append("hit_total")
+
+    if info.has_key("total_req_flow"):
+        total_values.append("req_flow")
+
+    if info.has_key("total_req_num"):
+        total_values.append("req_total")
+
+    if info.has_key("tendency_pv"):
+        list_values.append("pageview")
+
+    if info.has_key("tendency_quote"):
+        list_values.append("search")
+
+    if info.has_key("tendency_req_flow"):
+        list_values.append("req_flow")
+        list_values.append("hit_flow")
+
+    if info.has_key("tendency_req_num"):
+        list_values.append("req_total")
+        list_values.append("hit_total")
+
+    if info.has_key("tendency_ip"):
+        list_values.append("ip_num")
+
+    if info.get("top_location"):
+        top_values["location"] = int(info["top_location"])
+    if info.get("top_location_flow"):
+        top_values["location"] = int(info["top_location_flow"])
+
+    return total_values, list_values, top_values
+
+
+def classify_waf_statistic_info(info):
+    """
+    @attention: 区分waf统计数据项
+    """
+    total_values = []
+    list_values = []
+    top_values = {}
+    if info.has_key("level"):
+        total_values.append("level")
+
+    if info.has_key("total_cc") or info.has_key("total_web"):
+        total_values.append("att_num")
+
+    if info.has_key("total_ip"):
+        total_values.append("ip_num")
+
+    if info.has_key("tendency_attack"):
+        list_values.append("att_num")
+
+    if info.get("top_ip"):
+        top_values["src_ip"] = int(info["top_ip"])
+
+    if info.get("top_location"):
+        top_values["location"] = int(info["top_location"])
+
+    if info.get("top_type"):
+        top_values["rule"] = int(info["top_type"])
+
+    if info.get("top_site"):
+        top_values["domain"] = int(info["top_site"])
+
+    return total_values, list_values, top_values
+
+
+def dict_unicode2str(**params):
+    item = {}
+    for k in params:
+        item[str(k)] = str(params[k])
+    return str(item)

+ 40 - 0
src/common/error_info.py

@@ -0,0 +1,40 @@
+#coding=utf-8
+'''
+@attention: 异常定义模块
+'''
+class TipException(Exception):
+    """
+    @attention: 提示类异常,用于业务阻断时,直接返回请求
+    """
+    def __init__(self,msg):
+        self.msg = msg
+        
+    def show_msg(self):
+        return self.msg
+
+class ReasonException(Exception):
+    """
+    只需要原因的日志
+    """
+
+    def __init__(self, msg, module_name, msg_template):
+        """
+
+        :param msg:
+        :param module_name:
+        :param msg_template:  必须接收 reason参数
+        """
+        self.msg = msg
+        self.module_name = module_name
+        self.msg_template = msg_template
+
+
+class SpecialReasonException(Exception):
+    """
+    特殊异常
+    """
+    def __init__(self, msg, module_name, msg_template, inner_info):
+        self.msg_template = msg_template
+        self.module_name = module_name
+        self.msg = msg
+        self.inner_info = inner_info

+ 33 - 0
src/common/excel_output.py

@@ -0,0 +1,33 @@
+# coding:utf-8
+import StringIO
+import xlwt
+import zipfile
+import datetime
+import random, string
+import os
+from ftplib import FTP
+
+def save2memory(en_cn_map, content):
+    """
+    保存内容到xls里面
+    :param en_cn_map:  英文中文对应字典 {"name": "名字"}, OrderedDict
+    :param content:
+    :return:
+    """
+    wb = xlwt.Workbook(encoding="utf-8")
+    sheet = wb.add_sheet('info')
+    sort_head = en_cn_map.keys()
+    for i, item in enumerate(en_cn_map):
+        sheet.write(0, i, en_cn_map.get(item))
+    for row, item in enumerate(content):
+        sort_key = item.keys()
+        for key in sort_key:
+            if key not in sort_head:
+                continue
+            sheet.write(row+1, sort_head.index(key), item.get(key, ''))
+    output = StringIO.StringIO()
+    wb.save(output)
+    return output.getvalue()
+
+if __name__ == '__main__':
+    pass

二進制
src/common/font/consola.ttf


+ 39 - 0
src/common/logger.py

@@ -0,0 +1,39 @@
+#coding=utf-8
+'''
+Created on 2017年10月24日
+
+@author: bailiangjun
+'''
+import logging
+
+import settings
+
+logger = logging.getLogger('cloudwaf_defense')
+
+# 设置logger的level为DEBUG
+if settings.DEBUG:
+    logger.setLevel(logging.DEBUG)
+else:
+    logger.setLevel(logging.WARN)
+
+# 创建一个输出日志到控制台的StreamHandler
+hdr = logging.StreamHandler()
+
+# str_info = ["name","levelno","levelname","pathname","filename","module","funcName","created","asctime","threadName","message"]
+# int_info = ["lineno","msecs","relativeCreated","thread","process"]
+
+formatter = logging.Formatter("[%(asctime)s %(levelname)s]<%(name)s %(pathname)s %(lineno)s>:%(message)s")
+hdr.setFormatter(formatter)
+# 给logger添加上handler
+logger.addHandler(hdr)
+    
+def critical(msg,*args):
+    """
+    @attention: 考虑添加邮件系统/短信系统通知
+    """
+    logger.critical(msg,*args)
+
+
+
+if __name__ == '__main__':
+    logger.critical("ss%s")

+ 173 - 0
src/common/models.py

@@ -0,0 +1,173 @@
+# coding=utf-8
+'''
+'''
+from django.db import models
+
+class UserInfo(models.Model):
+    """用户表
+    """
+    username = models.CharField(u"用户名", max_length=255, blank=True,null=True)
+    usercode = models.CharField(u"用户代码", max_length=255, blank=True,null=True)
+    password = models.CharField(u"密码", max_length=255, blank=True,null=True)
+    realname = models.CharField(u"真实名称", max_length=255, blank=True, null=True)
+    openid = models.CharField(u"微信openid", max_length=64, blank=True,null=True)
+    avatar = models.CharField(u"手机号", max_length=64, blank=True,null=True)
+    nickname = models.CharField(u"手机号", max_length=64, blank=True,null=True)
+
+    is_bind = models.SmallIntegerField(u"是否绑定",default=0)
+    utype = models.SmallIntegerField(u"是否激活可用",default=0)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "users"
+        verbose_name = u"用户信息"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+    def is_authenticated(self):
+        return True
+
+    def is_anonymous(self):
+        return False
+
+
+class Player(models.Model):
+    """参数选手
+    """
+    user_id = models.IntegerField(u"用户id", blank=True,null=True)
+    username = models.CharField(u"用户名", max_length=255, blank=True,null=True)
+    usercode = models.CharField(u"用户代码", max_length=255, blank=True,null=True)
+    match_id = models.IntegerField(u"比赛id", blank=True,null=True)
+    match_name = models.CharField(u"比赛名称", max_length=255,blank=True,null=True)
+    match_group = models.CharField(u"比赛分组", max_length=255,blank=True,null=True)
+    fund = models.FloatField(u"资金",blank=True,null=True)
+    match_status = models.SmallIntegerField(u"比赛状态,退赛/暂停/比赛中-1/0/1",default=0)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "player"
+        verbose_name = u"参数选手"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+
+class PlayerRecord(models.Model):
+    """参数选手数据
+    """
+    user_id = models.IntegerField(u"用户id", blank=True,null=True)
+    username = models.CharField(u"用户名", max_length=255, blank=True,null=True)
+    usercode = models.CharField(u"用户代码", max_length=255, blank=True,null=True)
+    match_id = models.IntegerField(u"比赛id", blank=True,null=True)
+    match_name = models.CharField(u"比赛名称", max_length=255,blank=True,null=True)
+    match_group = models.CharField(u"比赛分组", max_length=255,blank=True,null=True)
+    init_fund = models.FloatField(u"初始资金",blank=True,null=True)
+    yesterday_fund = models.FloatField(u"昨日资金",blank=True,null=True)
+    today_fund = models.FloatField(u"今日资金",blank=True,null=True)
+    yesterday_stock = models.TextField(u"昨日持股",blank=True,null=True)
+    today_stock = models.TextField(u"今日持股",blank=True,null=True)
+    yesterday_stock_img = models.TextField(u"昨日持股截图",blank=True,null=True)
+    today_stock_img = models.TextField(u"今日持股截图",blank=True,null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "player_record"
+        verbose_name = u"参数选手"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+
+class Match(models.Model):
+    """比赛数据
+    """
+    name = models.CharField(u"名称", max_length=255, blank=True,null=True)
+    start_time = models.CharField(u"开始时间", max_length=255, blank=True,null=True)
+    end_time = models.CharField(u"结束时间", max_length=255, blank=True,null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "match"
+        verbose_name = u"比赛数据"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+
+class MatchGroup(models.Model):
+    """比赛分组
+    """
+    match_id = models.IntegerField(u"比赛id", blank=True,null=True)
+    name = models.CharField(u"名称", max_length=255, blank=True,null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "match_group"
+        verbose_name = u"比赛分组"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+
+class Stock(models.Model):
+    """股票信息表
+    """
+    name = models.CharField(u"名称", max_length=255, blank=True,null=True)
+    code = models.CharField(u"代码", max_length=255, blank=True,null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "stock"
+        verbose_name = u"股票"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+
+class OperationLogConfig(models.Model):
+    """操作日志模板配置
+    """
+    op_view = models.CharField(u"操作模块", max_length=100,blank=True,null=True)
+    op_action_flag = models.CharField(u"操作类型", max_length=50)
+    op_module = models.CharField(u"操作模块",max_length=255,blank=True,null=True)
+    op_template = models.TextField(u"操作日志模板")
+    op_url = models.CharField(u"URL", max_length=255)
+    op_response = models.TextField(u"URL", max_length=255, blank=True, null=True)
+    order = models.IntegerField(u"排序字段",blank=True,null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "oplog_config"
+        verbose_name = u"操作日志配置"
+
+
+class OperationLog(models.Model):
+    """操作日志
+    """
+    op_user_name = models.CharField(u"操作员名称",max_length=255)
+    op_user_realname = models.CharField(u"操作员姓名",max_length=255)
+    op_user_id = models.IntegerField(u"操作员id")
+    op_user_ip = models.CharField(u"操作员ip",max_length=100)
+    op_config = models.ForeignKey(OperationLogConfig)
+    op_request = models.TextField(u"request body", default="")
+    is_suc = models.BooleanField(u"是否成功", default=True)
+    error_msg = models.TextField(u"错误信息", max_length=255, blank=True, null=True)
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "oplog"
+        verbose_name = u"操作日志"

+ 177 - 0
src/common/templates/apidoc.html

@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<title></title>
+	<style type="text/css">
+		.container{
+			width: 100%;
+		}
+		.left{
+			position:fixed;
+			width: 20%;
+			float: left;
+			border-right:1px solid #ccc;
+			height: 100%;
+            overflow:scroll;
+		}
+		.right{
+			width:79%;
+			float: right;
+			height: 100%;
+			padding-top:5px;
+		}
+		.clear{
+			clear: both;
+		}
+		label{
+			display: block;
+			margin:10px 0px;
+		}
+		a{
+			text-decoration: none;
+		}
+		.delapi{
+			float: right;
+			margin-right: 10px;
+			cursor: pointer;
+		}
+	</style>
+</head>
+<body>
+	<div class="container">
+		<div class="left">
+            {% if project_name %}
+            <h3>{{project_name}}接口文档</h3>
+            {% endif %}
+			<ol>
+				<input id="search" type="text" style="width: 95%;margin-bottom: 10px;height: 25px;border-radius: 3px;border: 1px solid #ccc;" placeholder="请输入接口名称">
+				{% for api in apis %}
+				<li draggable="true" id="{{api.id}}"><a href="#{{api.url}}{{api.method}}" >{{api.title}}</a>
+					{% if isroot %}
+					<button class="delapi">x</button>
+					{% endif %}
+				</li>
+				{% endfor %}
+			</ol>
+		</div>
+		<div class="right">
+			{% for api in apis %}
+				<div id="{{api.url}}{{api.method}}">
+					<div style="background: #ccc;margin-top:20px;">
+						<b><font class="url">{{api.url}}</font> &nbsp;&nbsp;&nbsp;&nbsp;<font class="method">{{api.method}}</font></b>
+						<!--<button style="margin-left:50px;padding:0px;">发送请求</button>-->
+					</div>
+					<label>参数:</label>
+					<div style="margin-left:25px;">
+						{% if api.params %}
+						<textarea cols="80" rows="20">{{api.params}}</textarea>
+							{% if api.request_note %}
+								<label>说明:</label>
+								<div>{{api.request_note|safe}}</div>
+							{% endif %}
+						{% else %}
+						无
+						{% endif %}
+					</div>
+					<label>响应:</label>
+					<div style="margin-left:25px;">
+						{% if api.response %}
+						<textarea class="response" cols="80" rows="20">{{api.response}}</textarea>
+							{% if api.response_note %}
+								<label>说明:</label>
+								<div>{{api.response_note|safe}}</div>
+							{% endif %}
+						{% else %}
+						无
+						{% endif %}
+					</div>
+				</div>
+			{% endfor %}
+		</div>
+		<div class="clear"></div>
+	</div>
+</body>
+<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
+<script type="text/javascript">
+    function insertAfter(newEl, targetEl)
+        {
+            var parentEl = targetEl.parentNode;
+            if(parentEl.lastChild == targetEl)
+                {
+                    parentEl.appendChild(newEl);
+                }else
+                {
+                    parentEl.insertBefore(newEl,targetEl.nextSibling);
+                }            
+        }
+    //
+    var res = document.getElementsByClassName("response")
+    for(var i=0;i<res.length;i++){
+        res[i].innerHTML = JSON.stringify(JSON.parse(res[i].value),undefined,4) 
+    }
+
+	//
+	let parent = document.getElementsByTagName("ol")[0]
+	let div = document.getElementsByTagName("li")
+    let container = null
+    for(let i = 0; i < div.length; i++) {
+        div[i].ondragstart = function() {
+            // 当拖动其中一个元素时,this的指向便是你所拖动的元素,将它存在container
+            container = this
+        }
+        // 默认的当你dragover的时候会阻止你做drop的操作,所以需要取消这个默认
+        div[i].ondragover = function() {
+            event.preventDefault()
+        }
+        // 当拖动结束时,给拖动div所在位置下面的div做drop事件,注意drop时this的指向发生改变
+        div[i].ondrop = function()
+        {
+            if(container != null && container != this)
+            {
+                insertAfter(container,this)
+                //let temp = document.createElement("li")
+                //parent.replaceChild(temp,this)
+                //parent.replaceChild(this,container)
+                //parent.replaceChild(container,temp)
+				//
+				let dataobj = []
+				for(var i=0;i<div.length;i++){
+					console.log(div[i].id)
+					let id = div[i].id
+					dataobj.push({"id":id,"order":i})
+				}
+				$(function(){
+					$.ajax({
+						type:"POST",
+						url:"/api/doc/",
+						contentType:"application/json",
+						data:JSON.stringify({"ids":dataobj}),
+						success:function(){
+							window.location.reload();
+						}
+					})
+				})
+            }
+        }
+    }
+	$(function(){
+		$(".delapi").click(function(e){
+			let id = e.target.parentNode.id;
+			$.ajax({
+				type:"DELETE",
+				url:"/api/doc/",
+				contentType:"application/json",
+				data:JSON.stringify({"id":id}),
+				success:function(){
+					window.location.reload();
+				}
+			})
+		});
+	});
+	//
+	$("#search").input(function(){
+		console.log($(this).val());
+	})
+
+</script>
+</html>

+ 181 - 0
src/common/templates/apidoc.html.bk

@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<title></title>
+	<style type="text/css">
+		.container{
+			width: 100%;
+		}
+		.left{
+			position:fixed;
+			width: 20%;
+			float: left;
+			border-right:1px solid #ccc;
+			height: 100%;
+            overflow:scroll;
+		}
+		.right{
+			width:79%;
+			float: right;
+			height: 100%;
+			padding-top:5px;
+		}
+		.clear{
+			clear: both;
+		}
+		label{
+			display: block;
+			margin:10px 0px;
+		}
+		a{
+			text-decoration: none;
+		}
+		.delapi{
+			float: right;
+			margin-right: 10px;
+			cursor: pointer;
+		}
+	</style>
+</head>
+<body>
+	<div class="container">
+		<div class="left">
+            {% if project_name %}
+            <h3>{{project_name}}接口文档</h3>
+            {% endif %}
+			<ol>
+				<input id="search" type="text" style="width: 95%;margin-bottom: 10px;height: 25px;border-radius: 3px;border: 1px solid #ccc;" placeholder="请输入接口名称">
+				{% for api in apis %}
+				<li draggable="true" id="{{api.id}}"><a href="#{{api.url}}{{api.method}}" >{{api.title}}</a>
+					{% if isroot %}
+					<button class="delapi">x</button>
+					{% endif %}
+				</li>
+				{% endfor %}
+			</ol>
+		</div>
+		<div class="right">
+			{% for api in apis %}
+				<div id="{{api.url}}{{api.method}}">
+					<div style="background: #ccc;margin-top:20px;">
+						<b><font class="url">{{api.url}}</font> &nbsp;&nbsp;&nbsp;&nbsp;<font class="method">{{api.method}}</font></b>
+						<button style="margin-left:50px;padding:0px;">发送请求</button>
+					</div>
+					<label>参数:</label>
+					<div style="margin-left:25px;">
+						{% if api.params %}
+                            <textarea class="request" cols="80" rows="20">{{api.request}}</textarea>
+						{% else %}
+						无
+						{% endif %}
+					</div>
+					<label>响应:</label>
+					<div style="margin-left:25px;">
+						{% if api.response %}
+						<textarea class="response" cols="80" rows="20">{{api.response}}</textarea>
+							{% if api.response_note %}
+								<label>说明:</label>
+								<div>{{api.response_note|safe}}</div>
+							{% endif %}
+						{% else %}
+						无
+						{% endif %}
+					</div>
+				</div>
+			{% endfor %}
+		</div>
+		<div class="clear"></div>
+	</div>
+</body>
+<script
+  src="https://code.jquery.com/jquery-1.12.4.min.js"
+  integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
+  crossorigin="anonymous"></script>
+<script type="text/javascript">
+    function insertAfter(newEl, targetEl)
+        {
+            var parentEl = targetEl.parentNode;
+            if(parentEl.lastChild == targetEl)
+                {
+                    parentEl.appendChild(newEl);
+                }else
+                {
+                    parentEl.insertBefore(newEl,targetEl.nextSibling);
+                }            
+        }
+    //
+    //var res = document.getElementsByClassName("request")
+    //for(var i=0;i<res.length;i++){
+    //    res[i].innerHTML = JSON.stringify(JSON.parse(res[i].value),undefined,4) 
+    //}
+    //
+    var res = document.getElementsByClassName("response")
+    for(var i=0;i<res.length;i++){
+        res[i].innerHTML = JSON.stringify(JSON.parse(res[i].value),undefined,4) 
+    }
+
+	//
+	let parent = document.getElementsByTagName("ol")[0]
+	let div = document.getElementsByTagName("li")
+    let container = null
+    for(let i = 0; i < div.length; i++) {
+        div[i].ondragstart = function() {
+            // 当拖动其中一个元素时,this的指向便是你所拖动的元素,将它存在container
+            container = this
+        }
+        // 默认的当你dragover的时候会阻止你做drop的操作,所以需要取消这个默认
+        div[i].ondragover = function() {
+            event.preventDefault()
+        }
+        // 当拖动结束时,给拖动div所在位置下面的div做drop事件,注意drop时this的指向发生改变
+        div[i].ondrop = function()
+        {
+            if(container != null && container != this)
+            {
+                insertAfter(container,this)
+                //let temp = document.createElement("li")
+                //parent.replaceChild(temp,this)
+                //parent.replaceChild(this,container)
+                //parent.replaceChild(container,temp)
+				//
+				let dataobj = []
+				for(var i=0;i<div.length;i++){
+					console.log(div[i].id)
+					let id = div[i].id
+					dataobj.push({"id":id,"order":i})
+				}
+				$(function(){
+					$.ajax({
+						type:"POST",
+						url:"/api/doc/",
+						contentType:"application/json",
+						data:JSON.stringify({"ids":dataobj}),
+						success:function(){
+							window.location.reload();
+						}
+					})
+				})
+            }
+        }
+    }
+	$(function(){
+		$(".delapi").click(function(e){
+			let id = e.target.parentNode.id;
+			$.ajax({
+				type:"DELETE",
+				url:"/api/doc/",
+				contentType:"application/json",
+				data:JSON.stringify({"id":id}),
+				success:function(){
+					window.location.reload();
+				}
+			})
+		});
+	});
+	//
+	$("#search").input(function(){
+		console.log($(this).val());
+	})
+
+</script>
+</html>

+ 24 - 0
src/common/views.py

@@ -0,0 +1,24 @@
+# coding=utf-8
+from __future__ import unicode_literals
+
+import json
+import uuid
+import random
+
+from django.contrib import auth
+from django.core.cache import cache
+
+from common import core_views as cv
+
+class WsNotifyView(cv.BaseView):
+    def post(self,request):
+        """通知前端ws即时信息
+        rating:安全级别
+        statistic:分析相关
+        attack:攻击相关
+        """
+        qdata = request.json
+        type = qdata.get("type","attack")
+        return cv.to_suc({})
+
+

+ 9 - 0
src/common/ws_notice.py

@@ -0,0 +1,9 @@
+#coding:utf-8
+
+import json
+from channels import Group
+
+def send_ws_msg(channel,msg=""):
+    """
+    """
+    Group(channel).send({'text': json.dumps({'type': msg})})

+ 22 - 0
src/manage.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError:
+        # The above import may fail for some other reason. Ensure that the
+        # issue is really that Django is missing to avoid masking other
+        # exceptions on Python 2.
+        try:
+            import django
+        except ImportError:
+            raise ImportError(
+                "Couldn't import Django. Are you sure it's installed and "
+                "available on your PYTHONPATH environment variable? Did you "
+                "forget to activate a virtual environment?"
+            )
+        raise
+    execute_from_command_line(sys.argv)

+ 0 - 0
src/manage/__init__.py


+ 78 - 0
src/manage/cauth.py

@@ -0,0 +1,78 @@
+#coding=utf-8
+import logging
+import datetime
+
+import account.password_handle as ph
+from django.db.models import Q
+
+import common.error_info as ctc
+import common.models as am
+import account.lock_account as la
+
+logger = logging.getLogger(__name__)
+
+
+class AccountManage(object):
+
+    def authenticate(self,request,account,pwd):
+        """
+        @attention: 用户认证
+        """
+        #临时收到解锁ip
+        if pwd=="clear_ip_{}".format(account) :
+            la.clear_lock(0,request.ip)
+
+        if la.is_lock_ip(request.ip):
+            raise ctc.TipException(u'密码连续输错20次,锁定ip半个小时!')
+
+        user = am.UserInfo.objects.filter(Q(name=account)).first()
+        if user is not None:
+            #临时收到解锁ip
+            if pwd=="clear_account_{}".format(account) :
+                la.clear_lock(user.id,0)
+            if self.user_can_authenticate(user):
+                if la.is_lock(user.id, request.ip)=="ip_lock":
+                    raise ctc.TipException(u'密码连续输错20次,锁定ip半个小时!')
+                if la.is_lock(user.id, request.ip)=="account_lock":
+                    #记录ip错误
+                    la.increase_error_count_ip(request.ip)
+                    raise ctc.TipException(u'密码连续输错5次,锁定用户10分钟!')
+                if ph.check_password(pwd, user.password):
+                    la.clear_lock_count(user.id, request.ip)
+                    return user
+                else:
+                    logger.info("account, pwd %s", 'login failed')
+                    #记录ip错误
+                    la.increase_error_count_ip(request.ip)
+                    #记录用户名错误
+                    la.increase_error_count_uid(user.id)
+                    raise ctc.TipException("账号或密码错误")
+            else:
+                raise ctc.TipException("账户已停用")
+        else:
+            #记录ip错误
+            la.increase_error_count_ip(request.ip)
+            raise ctc.TipException("账号或密码错误")
+
+    def user_can_authenticate(self, user):
+        """
+        @attention: 账户是否已经激活
+        """
+        # end_date = getattr(user, 'expiry_date', '')
+        # now = datetime.datetime.now().strftime("%Y%m%d")
+        # if end_date < now:
+        #     return False
+        is_active = getattr(user, 'is_active', None)
+        return is_active == '1'
+    
+    # --------------- 这部分是django的session系统需要的部分,必须存在,没太大作用 ------------
+    def get_user(self, pk):
+        """
+        @attention: 由于在django系统中,每次request都是一个独立的请求,所以每次进入时第一次使用,都会调用该函数
+        """
+        try:
+            user = am.UserInfo.objects.get(pk=pk)
+        except am.UserInfo.DoesNotExist:
+            return None
+        return user
+

+ 82 - 0
src/manage/control_auth.py

@@ -0,0 +1,82 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db import transaction
+import common.models as cm
+import common.error_info as ce
+import common.common_functions as ccf
+import common.common_control as ccc
+
+def add_wxauth_info(request):
+    """
+    """
+    qdata = request.json
+    need_params = ["nickname","avatar","openid"]
+    print qdata
+    print need_params
+    mse = ccf.check_params(*need_params,**qdata)
+    if mse:
+        raise ce.TipException(mse)
+    vals = ccf.get_need_params(*need_params,**qdata)
+    obj,flag = cm.UserInfo.objects.get_or_create(openid=vals.get("openid"))
+    obj.nickname = vals.get("nickname")
+    obj.avatar = vals.get("avatar")
+    obj.save()
+    return obj
+
+
+def get_wxauth_info(request):
+    """
+    """
+    #qdata = request.json
+    #need_params = ["nickname","avatar","openid"]
+    #mse = ccf.check_params(*need_params,**qdata)
+    #if mse:
+    #    raise ce.TipException(mse)
+    #vals = ccf.get_need_params(*need_params,**qdata)
+    #obj,flag = cm.UserInfo.objects.get_or_create(openid=vals.get("openid"))
+    #obj.nickname = vals.get("nickname")
+    #obj.avatar = vals.get("avatar")
+    #obj.save()
+    #
+    data = {
+        "id":1,
+        "name":"肖小肖",
+        "sex":1,
+        "idno":"12321312312",
+        "education":"本科",
+        "phone":"15982456282",
+        "class_id":12,
+        "company":"网安",
+        "subject_id":12,
+        "subject_item":"特种人员|电工作业|准操项目|培训类型",
+        "train_type":1,
+        "receive_card":"邮寄",
+        "area":"四川|巴中|巴州区",
+        "address":"回风大道15号",
+        "remark":"备注1",
+        "idnoimg_face":"https://www.scxjc.club/test.png",
+        "idnoimg_back":"https://www.scxjc.club/test2.png",
+        "halfbody_img":"https://www.scxjc.club/tes3.png",
+        "education_img":"https://www.scxjc.club/test4.png",
+        "oldcard_img":"https://www.scxjc.club/test4.png",
+        "price":1800,
+        "classhour_imgs":["https://www.scxjc.club/test4.png","https://www.scxjc.club/test4.png"]
+    }
+    uid = request.user.id
+    user = cm.UserInfo.objects.filter(id=uid).values().first()
+    print type(user)
+    signinfo = cm.SignupOrders.objects.filter(user_id=uid).values().first()
+    if signinfo:
+        signinfo["sex"] = {u"男":1,u"女":2}.get(signinfo["sex"])
+        user.update(signinfo)
+    return user
+
+
+
+
+
+
+
+

+ 97 - 0
src/manage/control_bankcard.py

@@ -0,0 +1,97 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db import transaction
+import common.models as cm
+import common.error_info as ce
+import common.common_functions as ccf
+import common.common_control as ccc
+
+def add_bankcard(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["name","cardno"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals["user_id"] = request.user.id
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        obj = cm.BankCard.objects.create(**cvals)
+    except Exception as e:
+        raise ce.TipException(str(e))
+
+
+def update_bankcard(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    need_params.extend(["name","cardno"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    try:
+        cm.BankCard.objects.filter(id=id).update(**cvals)
+    except Exception as e:
+        raise ce.TipException(str(e))
+
+def delete_bankcard(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.BankCard.objects.filter(id__in=ids).update(status=0)
+
+
+def get_bankcard_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.BankCard.objects.filter(status=1,user_id=request.user.id)
+    total = eset.count()
+    edata = list(eset.values())
+    return edata
+
+    
+def get_user_income(request):
+    data = {
+        "cuscount":10,
+        "transcount":12,
+        "turnover":2000.00,
+        "income":2000.00
+        }
+    return data
+
+
+def apply_cash(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["bankcard_id","cashtype","cashamount"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        obj = cm.CashRecord.objects.create(**cvals)
+    except Exception as e:
+        raise ce.TipException(str(e))
+
+
+
+

+ 81 - 0
src/manage/control_department.py

@@ -0,0 +1,81 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db import transaction
+import common.models as cm
+import common.error_info as ce
+import common.common_functions as ccf
+import common.common_control as ccc
+
+def add_department(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["name","permissions"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    if kwargs.get("pid"):
+        cvals["pid"] = kwargs.get("pid")
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        obj = cm.Department.objects.create(**cvals)
+    except Exception as e:
+        raise c.TipException(str(e))
+
+
+def update_department(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    need_params.extend(["name","pid","permissions"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    if kwargs.get("pid"):
+        cvals["pid"] = kwargs.get("pid")
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    try:
+        cm.Department.objects.filter(id=id).update(**cvals)
+    except Exception as e:
+        raise c.TipException(str(e))
+
+def delete_department(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.Department.objects.filter(id__in=ids).update(status=0)
+
+
+def get_department_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.Department.objects.filter(status=1)
+    if "name" in kwargs and kwargs.get("name"):
+        eset = eset.filter(name__icontains=kwargs.get("name"))
+    total = eset.count()
+    edata = list(eset.values())
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+    total,data = ccf.get_page_list(edata,page,page_size)
+    return (total,data)
+
+    
+
+
+
+

+ 129 - 0
src/manage/control_organization.py

@@ -0,0 +1,129 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db.models import Q
+from django.db import transaction
+import common.models as cm
+import common.common_functions as ccf
+import common.common_control as ccc
+import common.error_info as ce
+
+
+def search_organization(name):
+    """
+    """
+    qset = cm.Organization.objects.filter(name__icontains=name)
+    qdata = list(qset.values_list("name",flat=True))
+    return qdata
+
+def get_organization_tree(uid):
+    """
+    """
+    user = cm.UserInfo.objects.filter(pk=uid).first()
+    if not user:
+        raise ce.TipException(u"用户不存在")
+    uid = user.pk
+
+    total,users_info = ccc.get_sub_users(uid)
+    print users_info
+    user_ids = [x["id"] for x in users_info]
+    permissions = list(user.role.permission.all().values_list("codename",flat=True))
+
+    if user.role.platform == "portal":
+        #数据权限下用户所在的企业
+        org_ids = list(cm.UserInfo.objects.filter(id__in=user_ids).values_list("organization_id",flat=True))
+        #数据权限下的用户创建的企业
+        for uid in user_ids:
+            _user = cm.UserInfo.objects.filter(id=uid).first()
+            if "SystemManagement.Organization.Check" in permissions:
+                org_ids_created = list(cm.Organization.objects.filter(cid__in=[uid]).values_list("id",flat=True))
+                org_ids.extend(org_ids_created)
+        #orgs = cm.Organization.objects.filter(id__in=org_ids)
+        orgs = cm.Organization.objects.filter(id__in=org_ids,cid=uid).exclude(pid__in=org_ids)
+    else:
+        print 6666666666666666
+        orgs = cm.Organization.objects.filter(cid__in=user_ids)
+
+    org_ids = list(orgs.values_list("id",flat=True))
+    print org_ids,9999
+    #组装树结构
+    trees = []
+    for org in orgs:
+        if user.role.platform == "portal":
+            trees.append(ccc.get_sub_organization_tree(org.id))
+        else:
+            if not org.pid:
+                trees.append(ccc.get_sub_organization_tree(org.id))
+
+    otree = [
+        {
+            "id":1,
+            "nodes":[
+                {
+                    "id":2,
+                    "nodes":[
+                    
+                    ],
+                    "tree_label":u"成都代理运营中心"
+                } 
+            ],
+            "tree_label":u"成都运营中心"
+        } 
+    ]
+    return trees
+
+
+def add_organization(**kwargs):
+    """
+    """
+    need_params = ["name","sname"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    need_params.extend(["pid","cid","cperson","desc"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    with transaction.atomic():
+        oobj = cm.Organization.objects.create(**cvals)
+
+
+def update_organization(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    uvals = {}
+    if "name" in kwargs:
+        uvals["name"] = kwargs.get("name")
+    if "sname" in kwargs:
+        uvals["sname"] = kwargs.get("sname")
+    if "desc" in kwargs:
+        uvals["desc"] = kwargs.get("desc")
+
+    with transaction.atomic():
+        oobj = cm.Organization.objects.filter(id=id).update(**uvals)
+
+
+def delete_organization(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.Organization.objects.filter(id__in=ids).delete()
+    
+    #级联删除相关联数据待完善...
+
+
+def get_organization_info(*ids):
+    """
+    """
+    qset = cm.Organization.objects.filter(id__in=ids)
+    oinfo = list(qset.values("id","name","sname","desc","pid"))
+    return oinfo
+

+ 36 - 0
src/manage/control_permission.py

@@ -0,0 +1,36 @@
+#-*-coding:utf-8 -*-
+import re
+import collections
+import common.models as cm
+
+def get_permission_list(role_id=None,platform=None):
+    """
+    """
+    if role_id:
+        qset = cm.Role.objects.filter(id=role_id).first().permission.all()
+    else:
+        qset = cm.Permission.objects.all()
+    if platform:
+        qset = qset.filter(platform__icontains=platform)
+    permissions = format_permission_tree(qset)
+    return permissions
+
+def get_permission_tree(pobj,data=None):
+    data = data if data else []
+    childrenset = cm.Permission.objects.filter(pid=pobj.id)
+    for cdobj in childrenset:
+        data.append({"id":cdobj.id,"name":cdobj.name,"codename":cdobj.codename,"children":get_permission_tree(cdobj)})
+    return data
+
+
+def format_permission_tree(qset):
+    """暂时写死待完善....
+    """
+    ptrees = []
+    toppers = qset.filter(pid__isnull=True)
+    for topobj in toppers:
+        ptree = {"id":topobj.id,"name":topobj.name,"codename":topobj.codename}
+        ptree["children"] = get_permission_tree(topobj)
+        ptrees.append(ptree)
+    return ptrees
+

+ 106 - 0
src/manage/control_role.py

@@ -0,0 +1,106 @@
+#coding=utf-8
+'''
+'''
+import json
+from django.db import transaction
+import common.models as cm
+import common.error_info as ce
+import common.common_functions as ccf
+import common.common_control as ccc
+
+def get_role_list(query=None,relations=None,page=None,page_size=None):
+    """
+    """
+    qset = cm.Role.objects.all()
+    if query and query.get("platform"):
+        qset = qset.filter(platform=query.get("platform"))
+    total,qset = ccc.get_page_qset(qset,page,page_size)
+    roles = qset.values("id","name","desc","ctime","platform")
+    if relations:
+        for i,role in enumerate(roles):
+            permissions = list(qset[i].permission.all().values_list("name",flat=True))
+            role.update({"permissions":",".join(permissions)})
+    return total,list(roles)
+
+
+def get_role_info(*ids):
+    """
+    """
+    qset = cm.Role.objects.filter(id__in=ids)
+    roles = list(qset.values())
+    for i,role in enumerate(roles):
+        role["permission_addroles"] = json.loads(role["permission_addroles"])
+        permissions = list(qset[i].permission.all().values("name","id"))
+        role.update({"permissions":permissions})
+    return roles
+
+
+def get_all_role_list():
+    qset = cm.Role.objects.all()
+    roles = qset.values("id","name","desc","ctime","platform")
+    return list(roles)
+
+
+def add_role(**kwargs):
+    """
+    """
+    need_params = ["name","platform","permissions"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    need_params.extend(["cperson","desc"])
+    try:
+        permission_addroles = kwargs.pop("permission_addroles")
+        permissions = kwargs.pop("permissions")
+    except KeyError:
+        permission_addroles = None
+        permissions = None
+
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    with transaction.atomic():
+        robj = cm.Role.objects.create(**cvals)
+        #添加permission
+        robj.permission_addroles = json.dumps(permission_addroles)
+        robj.permission.add(*permissions)
+        robj.save()
+
+
+def update_role(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    uvals = {}
+    if "name" in kwargs:
+        uvals["name"] = kwargs.get("name")
+    if "desc" in kwargs:
+        uvals["desc"] = kwargs.get("desc")
+    if "permission_addroles" in kwargs:
+        uvals["permission_addroles"] = json.dumps(kwargs.get("permission_addroles"))
+    with transaction.atomic():
+        robj = cm.Role.objects.filter(id=id).first()
+        cm.Role.objects.filter(id=id).update(**uvals)
+        if robj:
+            robj.permission.remove()
+            robj.permission.add(*kwargs.get("permissions"))
+
+
+def delete_role(**kwargs):
+    """
+    """
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.Role.objects.filter(id__in=ids).delete()
+
+
+
+
+
+
+

+ 233 - 0
src/manage/control_user.py

@@ -0,0 +1,233 @@
+#coding=utf-8
+'''
+'''
+import json
+import datetime
+import logging
+import re
+
+import hashlib
+import xlrd
+from django.core.cache import cache
+from django.db.models import Q
+from django.db.models import Sum
+from django.db import transaction
+from django.contrib import auth
+import common.models as cm
+import common.error_info as ce
+import password_handle as ph
+import common.common_functions as ccf
+
+def add_user(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["realname","phone","department_id","utype","is_active"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    if cm.UserInfo.objects.filter(phone=kwargs.get("phone")).exists():
+        raise ce.TipException(u"该用户已存在!")
+    need_params.extend(["email","remark"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals.update({"name":cvals.get("phone")})
+    cvals.update({"password":ph.make_password(cvals.get("phone")[-6:],True)})
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    obj = cm.UserInfo.objects.create(**cvals)
+    return obj
+
+
+def delete_user(request):
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    cm.UserInfo.objects.filter(id__in=ids).update(status=0)
+
+
+def update_user(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    id = kwargs.get("id")
+    if cm.UserInfo.objects.exclude(id=id).filter(phone=kwargs.get("phone")).exists():
+        raise ce.TipException(u"该用户已存在!")
+    need_params.extend(["realname","phone","department_id","utype","is_active","email","remark"])
+    cvals = ccf.get_need_params(*need_params,**kwargs)
+    cvals.update({"name":cvals.get("phone")})
+    cvals.update({"password":ph.make_password(cvals.get("phone")[-6:],True)})
+    cvals["cid"] = request.user.id
+    cvals["cperson"] = request.user.realname
+    obj = cm.UserInfo.objects.filter(id=id).update(**cvals)
+    return obj
+
+def login_user(request):
+    """
+    """
+    info = request.json
+    login_info = info.get('username')
+    password = info.get('password')
+    captcha_id = info.get('captcha_id')
+    idcode = info.get('idcode')
+    captcha = cache.get(captcha_id, '')
+    cache.delete(captcha_id)
+    if not login_info or not password:
+        raise ce.TipException(u"账户或密码不能为空!")
+    #if not idcode:
+    #    raise ce.TipException(u"验证码不能为空!")
+    #if idcode.upper() != captcha.upper():
+    #    raise ce.TipException(u"验证码错误!")
+
+    user = auth.authenticate(request, account=login_info, pwd=password)
+    if user:
+        auth.login(request, user)
+        return user
+    else:
+        raise ce.TipException(u"账号或密码错误!")
+
+
+def reset_password(request):
+    """
+    @attention: 重置密码
+    """
+    qdata = request.json
+    need_params = ["password","repassword","phone","phcode"]
+    mse = ccf.check_params(*need_params,**qdata)
+    if mse:
+        raise ce.TipException(mse)
+    uid = request.json.get("uid")
+    if not uid:
+        uid = request.user.id
+    phone = qdata.get("phone")
+    password = qdata.get("password")
+    repassword = qdata.get("repassword")
+    if password != repassword:
+        raise ce.TipException(u"两次输入的密码不一致!")
+    pwd = ph.make_password(password)
+    cm.UserInfo.objects.filter(phone=phone).update(password=pwd)
+
+
+def reset_user_password(request):
+    qdata = request.json
+    need_params = ["uid","code","password"]
+    mse = ccf.check_params(*need_params,**qdata)
+    if mse:
+        raise ce.TipException(mse)
+    upk = qdata.get("uid")
+    code = qdata.get("code")
+    pkey = request.user.phone
+    if cache.get(pkey,"") != code:
+        raise ce.TipException(u"验证码不正确!")
+    newpwd = qdata.get("password")
+    pwd = ph.make_password(newpwd)
+    cm.UserInfo.objects.filter(pk=upk).update(password=pwd)
+
+
+def regist_user(request):
+    """
+    """
+    kwargs = request.json
+    need_parms = ["realname","password","repassword","phone","email"]
+    mse = ccf.check_params(*need_parms,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    if cm.UserInfo.objects.filter(phone=kwargs.get("phone")).exists():
+        raise ce.TipException(u"该手机号已注册!")
+    cvals = ccf.get_need_params(*need_parms,**kwargs)
+    cvals.pop("repassword")
+    cvals["name"] = cvals["phone"]
+    if kwargs["password"] != kwargs["repassword"]:
+        raise ce.TipException(u"前后输入的密码不一致!")
+    if not cvals.get("password"):
+        pwd,password = ph.make_default_password(None)
+        cvals.update({"password":password})
+    else:
+        pwd = cvals.get("password")
+        cvals.update({"password":ph.make_password(cvals.get("password"))})
+    uobj = cm.UserInfo.objects.create(**cvals)
+    return None
+
+
+def format_user(*ids):
+    """
+    """
+    eset = cm.UserInfo.objects.filter(id__in=ids,status=1)
+    if not eset.exists():
+        raise ce.TipException(u"客户不存在!")
+    data = list(eset.values())
+    return data
+
+def get_user_info(request):
+    """
+    """
+    kwargs = request.json
+    need_params = ["id"]
+    mse = ccf.check_params(*need_params,**kwargs)
+    if mse:
+        raise ce.TipException(mse)
+    ids = str(kwargs.get("id")).split(",")
+    info = format_user(*ids)
+    info = info[0] if info else {}
+    return info
+
+def get_user_personal_info(request):
+    """
+    """
+    id = request.user.id
+    info = format_user(*[id])
+    info = info[0] if info else {}
+    return info
+
+def get_account_info(request):
+    """
+    """
+    id = request.user.id
+    info = format_user(*[id])
+    info = info[0] if info else {}
+    info["p"] = ["Product.*.*"]
+    return info
+
+def get_user_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.UserInfo.objects.filter(status=1)
+    if "name" in kwargs and kwargs.get("name"):
+        eset = eset.filter(name__icontains=kwargs.get("name"))
+    if "department_id" in kwargs and kwargs.get("department_id"):
+        eset = eset.filter(department_id=kwargs.get("department_id"))
+    if "utype" in kwargs and kwargs.get("utype"):
+        eset = eset.filter(utype=kwargs.get("utype"))
+    if "is_active" in kwargs and kwargs.get("is_active"):
+        eset = eset.filter(is_active=kwargs.get("is_active"))
+    total = eset.count()
+    edata = list(eset.values())
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+    total,data = ccf.get_page_list(edata,page,page_size)
+    return (total,data)
+
+
+def get_unaudit_user_list(request):
+    """
+    """
+    kwargs = request.json
+    eset = cm.UserInfo.objects.filter(status=1,is_active=0)
+    if "name" in kwargs and kwargs.get("name"):
+        eset = eset.filter(name__icontains=kwargs.get("name"))
+    if "utype" in kwargs and kwargs.get("utype"):
+        eset = eset.filter(utype=kwargs.get("utype"))
+    total = eset.count()
+    edata = list(eset.values())
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+    total,data = ccf.get_page_list(edata,page,page_size)
+    return (total,data)
+

File diff suppressed because it is too large
+ 1088 - 0
src/manage/controls.py


+ 126 - 0
src/manage/lock_account.py

@@ -0,0 +1,126 @@
+# coding:utf-8
+from django.core.cache import cache
+
+import common.error_info as cei
+
+MAX_ERROR_TIMES = 5
+MAX_ERROR_TIMES_IP = 20
+LOCK_IP_TMP = 'LOCK_IP_{}'
+LOCK_ACCOUNT_TMP = 'LOCK_ACCOUNT_{}'
+
+ACCOUNT_INCR_TMP = 'ACCOUNT_COUNT_{}'
+IP_INCR_TMP = 'IP_COUNT_{}'
+
+
+def is_lock(uid, ip):
+    """
+    是否锁
+    :param uid:
+    :param ip:
+    :return:
+    """
+    account_key = LOCK_ACCOUNT_TMP.format(uid)
+    ip_key = LOCK_IP_TMP.format(ip)
+
+    if cache.get(ip_key):
+        return "ip_lock"
+    if cache.get(account_key):
+        return "account_lock"
+    return False
+
+def is_lock_ip(ip):
+    """是否封禁IP
+    """
+    ip_key = LOCK_IP_TMP.format(ip)
+    if cache.get(ip_key):
+        return True
+    return False
+
+
+def increase_error_count(uid, ip):
+    """
+    5分钟内连续输错五次
+    :return:
+    """
+    ip_key = IP_INCR_TMP.format(ip)
+    ip_count = cache.get(ip_key) or 0
+
+    account_key = ACCOUNT_INCR_TMP.format(uid)
+    account_count = cache.get(account_key) or 0
+
+    if account_count + 1 >= MAX_ERROR_TIMES or ip_count + 1 >= MAX_ERROR_TIMES:
+        lock(uid, ip)
+        raise cei.TipException(u'密码连续输错五次,锁定ip和账户半个小时')
+    if not account_count:
+        cache.set(account_key, 1, 5*60)
+    else:
+        cache.incr(account_key)
+    if not ip_count:
+        cache.set(ip_count, 1, 5*60)
+    else:
+        cache.incr(ip_key)
+
+def increase_error_count_ip(ip):
+    """
+    """
+    ip_key = IP_INCR_TMP.format(ip)
+    ip_count = cache.get(ip_key) or 0
+    if ip_count + 1 >= MAX_ERROR_TIMES_IP:
+        lock(0,ip)
+        raise cei.TipException(u'密码连续输错20次,锁定ip半个小时!')
+    if not ip_count:
+        cache.set(ip_key, 1, 30*60)
+    else:
+        cache.incr(ip_key)
+
+def increase_error_count_uid(uid):
+    """
+    """
+    account_key = ACCOUNT_INCR_TMP.format(uid)
+    account_count = cache.get(account_key) or 0
+    if account_count + 1 >= MAX_ERROR_TIMES:
+        lock(uid,0)
+        raise cei.TipException(u'密码连续输错5次,锁定账户10分钟!')
+    if not account_count:
+        cache.set(account_key, 1, 10*60)
+    else:
+        cache.incr(account_key)
+
+
+
+def clear_lock_count(uid, ip):
+    """
+    清除计数,清楚锁ip,锁account的key
+    :param uid:
+    :param ip:
+    :return:
+    """
+    if uid:
+        cache.delete(ACCOUNT_INCR_TMP.format(uid))
+    if ip:
+        cache.delete(IP_INCR_TMP.format(ip))
+
+
+def lock(uid, ip):
+    """
+    锁账户,ip半个小时
+    :param uid:
+    :param ip:
+    :return:
+    """
+    clear_lock_count(uid, ip)
+    if uid:
+        key = LOCK_ACCOUNT_TMP.format(uid)
+        cache.set(key, 'lock_account', 10*60)
+    if ip:
+        key = LOCK_IP_TMP.format(ip)
+        cache.set(key, 'lock_ip', 30*60)
+
+def clear_lock(uid,ip):
+    clear_lock_count(uid, ip)
+    if uid:
+        key = LOCK_ACCOUNT_TMP.format(uid)
+        cache.delete(key)
+    if ip:
+        key = LOCK_IP_TMP.format(ip)
+        cache.delete(IP_INCR_TMP.format(ip))

+ 6 - 0
src/manage/models.py

@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models
+
+# Create your models here.

+ 41 - 0
src/manage/password_handle.py

@@ -0,0 +1,41 @@
+#coding=utf-8
+'''
+@attention: 密码加密验证模块
+'''
+import hashlib
+import re
+import common.error_info as ceil
+import random
+
+def check_password(new,old):
+    """
+    @attention: 验证密码
+    """
+    np = hashlib.md5(new).hexdigest().upper()
+    return np==old
+
+def make_password(pwd,isdefault=None):
+    """
+    @attention: 密码加密
+    """
+    #if not re.search(r'^.*(?=.{6,15})(?=.*\d)(?=.*[A-Z]{1,})(?=.*[a-z]{1,})(?=.*[!@#$%^&*?\(\)]).*$',pwd) and not isdefault:
+    #    raise ceil.TipException(u"密码不符合符号要求!")
+    return hashlib.md5(pwd).hexdigest().upper()
+
+def make_default_password(pwd):
+    """
+    @attention: 密码加密
+    """
+    ustr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    lstr = "abcdefghjklmnopqrstuvwxyz"
+    dstr = "0123456789"
+    sstr = "!@#$%&*"
+    pwd = "".join(random.sample(ustr,3)+random.sample(lstr,3)+random.sample(dstr,3)+random.sample(sstr,3))
+    return pwd,hashlib.md5(pwd).hexdigest().upper()
+
+if __name__ == '__main__':
+    old = "123456"
+    op = make_password(old)
+    # print op
+    new = "123456"
+    # print check_password(new, op)

+ 39 - 0
src/manage/urls_backstage.py

@@ -0,0 +1,39 @@
+# coding=utf-8
+'''
+'''
+from django.conf.urls import url
+from . import views,views_backstage
+
+urlpatterns = [
+    url(r'^user$', views.UserInfoView.as_view()),
+    url(r'^user/list$', views.UserInfoListView.as_view()),
+    url(r'^goverment$', views.GovermentView.as_view()),
+    url(r'^goverment/list$', views.GovermentListView.as_view()),
+    url(r'^goverment/subent$', views.GovermentSubEntView.as_view()),
+    url(r'^enterprise$', views.EnterPriseView.as_view()),
+    url(r'^enterprise/list$', views.EnterPriseListView.as_view()),
+    url(r'^enterprise/all$', views.EnterPriseAllView.as_view()),
+    url(r'^uploadfile$', views.UploadFileView.as_view()),
+    url(r'^getdefault$', views.GetDefaultView.as_view()),
+    url(r'^department$', views.DepartmentView.as_view()),
+    url(r'^department/list$', views.DepartmentListView.as_view()),
+    url(r'^riskpoint$', views.RiskPointView.as_view()),
+    url(r'^riskpoint/list$', views.RiskPointListView.as_view()),
+    url(r'^monittask$', views.MonitTaskView.as_view()),
+    url(r'^monittask/list$', views.MonitTaskListView.as_view()),
+    url(r'^monittask/upload$', views.MonitTaskUploadView.as_view()),
+    url(r'^staffuser$', views.StaffUserView.as_view()),
+    url(r'^staffuser/list$', views.StaffUserListView.as_view()),
+    url(r'^messages$', views.MessagesView.as_view()),
+    url(r'^messages/list$', views.MessagesListView.as_view()),
+    url(r'^documention$', views.DocumentionView.as_view()),
+    url(r'^documention/list$', views.DocumentionListView.as_view()),
+    url(r'^bill$', views.BillView.as_view()),
+    url(r'^bill/list$', views.BillListView.as_view()),
+    url(r'^friendlink$', views.FriendLinkView.as_view()),
+    url(r'^friendlink/list$', views.FriendLinkListView.as_view()),
+    url(r'^dashboard/index$', views.DashboardIndexView.as_view()),
+    url(r'^monitjob/list$', views.MonitJobListView.as_view()),
+    url(r'^monitjob/download$', views.MonitJobDownloadView.as_view()),
+]
+

File diff suppressed because it is too large
+ 1205 - 0
src/manage/views.py


+ 299 - 0
src/manage/views_backstage.py

@@ -0,0 +1,299 @@
+#-*-coding:utf-8-*-
+import json
+import uuid
+from django.contrib import auth
+from django.core.cache import cache
+from django.conf import settings
+
+from common import core_views as cv
+from common.models import UserInfo
+import common.common_functions as ccf
+import common.error_info as ce
+import control_user as cu
+import control_role as crol
+import control_organization as co
+import common.common_control as ccc
+import control_permission as cp
+import control_department as cd
+import control_bankcard as cb
+
+
+class InfoView(cv.AuthView):
+    def get(self, request):
+        '''
+        #获取全局账号信息(权限控制)
+        '''
+        try:
+            users = cu.get_account_info(request)
+            return cv.to_suc(users)
+        except Exception as e:
+            return cv.to_fail(e)
+
+class UserInfoView(cv.BaseView):
+    def get(self, request):
+        """
+        #获取用户个人信息
+        @id:1,用户id
+        """
+        try:
+            data = cu.get_user_personal_info(request)
+            return cv.to_suc(data)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+class UserView(cv.BaseView):
+    def get(self, request):
+        """
+        #获取用户详情
+        @id:1,用户id
+        """
+        try:
+            data = cu.get_user_info(request)
+            return cv.to_suc(data)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+    def post(self, request):
+        '''
+        #新增员工
+        @realname:"肖小肖",员工名称
+        @phone:"129823"
+        @email:"129823@qq.com"
+        @department_id:1,部门id
+        @utype:1/2/3,员工类型
+        @is_active:1/0,是否启用
+        @remark:"好员工",备注
+        '''
+        qdata = request.json
+        try:
+            rst = cu.add_user(request)
+            return cv.to_suc()
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+    def put(self, request):
+        """
+        #修改员工
+        @id:1,员工id
+        @realname:"肖小肖",员工名称
+        @phone:"129823"
+        @email:"129823@qq.com"
+        @department_id:1,部门id
+        @utype:1/2/3,员工类型
+        @is_active:1/0,是否启用
+        @remark:"好员工",备注
+        """
+        qdata = request.json
+        try:
+            data = cu.update_user(request)
+        except Exception as e:
+            return cv.to_fail(e)
+        return cv.to_suc(data)
+
+    def delete(self, request):
+        """
+        #删除员工
+        @id:1,多个id用逗号分隔
+        """
+        qdata = request.json
+        try:
+            cu.delete_user(request)
+        except Exception as e:
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+class UserListView(cv.AuthView):
+    def get(self, request):
+        """
+        #员工列表
+        @name:"用户名"
+        @department_id:1
+        @utype:1
+        @is_active:1
+        """
+        try:
+            total,res = cu.get_user_list(request)
+            return cv.to_suc({"total":total,"list":res})
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class UnauditUserListView(cv.AuthView):
+    def get(self, request):
+        """
+        #待审核员工列表
+        @name:"用户名"
+        @utype:1
+        """
+        try:
+            total,res = cu.get_unaudit_user_list(request)
+            return cv.to_suc({"total":total,"list":res})
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class PermissionListView(cv.AuthView):
+    def get(self, request):
+        """#权限列表
+        @role_id:1 角色id 可选参数 传了就只返回对应角色的权限
+        @platform:"operation" 权限归属 可选参数 传了就对权限进行平台过滤
+        """
+        qdata = request.json
+        role_id = qdata.get("role_id",None)
+        platform = qdata.get("platform",None)
+        roles = cp.get_permission_list(role_id,platform)
+
+        return cv.to_suc(roles)
+
+
+class ResetPwdView(cv.BaseView):
+    def put(self, request):
+        """
+        #重置密码(忘记密码)
+        @phone:"15982456282",手机号
+        @password:"",新密码
+        @repassword:"",确认密码
+        @phcode:"123",验证码
+        """
+        try:
+            cu.reset_password(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class ResetUserPwdView(cv.AuthView):
+    def put(self, request):
+        """
+        #修改用户密码
+        @uid:10,用户id不传则默认当前用户
+        @code:"",验证码
+        @password:"",新密码
+        """
+        try:
+            cu.reset_user_password(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class DepartmentView(cv.AuthView):
+    def post(self,request):
+        """
+        #新增部门
+        @name:"综管部",部门名称
+        @pid:1,上级部门
+        @permissions:["CusManage.*.*","CusManage.MyCus.*"]
+        """
+        try:
+            cd.add_department(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+    def put(self,request):
+        """
+        #修改部门
+        @id:1,部门id
+        @name:"综管部",部门名称
+        @pid:1,上级部门
+        @permissions:["CusManage.*.*","CusManage.MyCus.*"]
+        """
+        try:
+            cd.update_department(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+    def delete(self,request):
+        """
+        #删除部门
+        @id:1,部门id
+        """
+        try:
+            cd.delete_department(request)
+            return cv.to_suc()
+        except Exception as e:
+            return cv.to_fail(e)
+
+
+class DepartmentListView(cv.AuthView):
+    def get(self,request):
+        """#部门列表
+        @name:"研发",部门名称
+        """
+        try:
+            total,rst = cd.get_department_list(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc({"total":total,"list":rst})
+
+
+class UserBankCardView(cv.AuthView):
+    def post(self,request):
+        """#新增银行卡
+        @name:"建设银行",银行名称
+        @cardno:"6229000",银行卡卡号
+        """
+        try:
+            rst = cb.add_bankcard(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+    def delete(self,request):
+        """#删除银行卡
+        @id:1,银行卡id
+        """
+        try:
+            rst = cb.delete_bankcard(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc()
+
+
+class UserBankCardListView(cv.AuthView):
+    def get(self,request):
+        """#银行卡列表
+        """
+        try:
+            rst = cb.get_bankcard_list(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc(rst)
+
+
+class UserIncomeView(cv.AuthView):
+    def get(self,request):
+        """#我的收益
+        """
+        try:
+            rst = cb.get_user_income(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc(rst)
+
+
+class UserApplyCashView(cv.AuthView):
+    def post(self,request):
+        """#申请提现
+        @bankcard_id:1,银行卡id
+        @cashtype:"bank/alipay",提现方式
+        @cashamount:1000,提现金额
+        """
+        try:
+            rst = cb.apply_cash(request)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+        return cv.to_suc(rst)

+ 4 - 0
src/manage/views_permission.py

@@ -0,0 +1,4 @@
+#-*-coding:utf-8 -*-
+import common.core_views as cv
+
+

+ 342 - 0
src/manage/wzhifuSDK.py

@@ -0,0 +1,342 @@
+#coding:utf-8
+"""
+Created on 2014-11-24
+
+@author: http://blog.csdn.net/yueguanghaidao,yihaibo@longtugame.com
+
+ * 微信支付帮助库
+ * ====================================================
+ * 接口分三种类型:
+ * 【请求型接口】--Wxpay_client_
+ *      统一支付接口类--UnifiedOrder
+ *      订单查询接口--OrderQuery
+ *      退款申请接口--Refund
+ *      退款查询接口--RefundQuery
+ *      对账单接口--DownloadBill
+ *      短链接转换接口--ShortUrl
+ * 【响应型接口】--Wxpay_server_
+ *      通用通知接口--Notify
+ *      Native支付——请求商家获取商品信息接口--NativeCall
+ * 【其他】
+ *      静态链接二维码--NativeLink
+ *      JSAPI支付--JsApi
+ * =====================================================
+ * 【CommonUtil】常用工具:
+ *      trimString(),设置参数时需要用到的字符处理函数
+ *      createNoncestr(),产生随机字符串,不长于32位
+ *      formatBizQueryParaMap(),格式化参数,签名过程需要用到
+ *      getSign(),生成签名
+ *      arrayToXml(),array转xml
+ *      xmlToArray(),xml转 array
+ *      postXmlCurl(),以post方式提交xml到对应的接口url
+ *      postXmlSSLCurl(),使用证书,以post方式提交xml到对应的接口url
+
+"""
+
+import json
+import time
+import random
+import urllib2
+import hashlib
+import threading
+import urllib
+from urllib import quote
+import xml.etree.ElementTree as ET
+
+try:
+    import pycurl
+    from cStringIO import StringIO
+except ImportError:
+    pycurl = None
+
+
+class WxPayConf_pub(object):
+    """配置账号信息"""
+
+    ##=======【基本信息设置】=====================================
+    #微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
+    APPID = "wx2938132b773c7b5a"
+    #JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
+    APPSECRET = "b32b08a8757cc34b1ee5490af897b065"
+    #受理商ID,身份标识
+    MCHID = "1590893081"
+    #商户支付密钥Key。审核通过后,在微信发送的邮件中查看
+    KEY = "kAHuCc2g4MINcLRk3o0lxT6J1Z04WuZq"
+
+   
+
+    #=======【异步通知url设置】===================================
+    #异步通知url,商户根据实际开发过程设定
+    NOTIFY_URL = "http://baoming.siyusai.com/wxjspay/weixin_qrcode_notify/"
+
+    #=======【JSAPI路径设置】===================================
+    #获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
+    #JS_API_CALL_URL = "http://www.huodongjia.com/pay/?showwxpaytitle=1"
+    JS_API_CALL_URL = "http://baoming.siyusai.com/wxjspay/forwxjspay/"
+
+    #=======【证书路径设置】=====================================
+    #证书路径,注意应该填写绝对路径
+    SSLCERT_PATH = "/data/web/m_website_dev/m_web/weixinpay/cert/apiclient_cert.pem"
+    SSLKEY_PATH = "/data/web/m_website_dev/m_web/weixinpay/cert/apiclient_key.pem"
+
+    #=======【curl超时设置】===================================
+    CURL_TIMEOUT = 30
+
+    #=======【HTTP客户端设置】===================================
+    HTTP_CLIENT = "URLLIB"  # ("URLLIB", "CURL")
+
+
+class Singleton(object):
+    """单例模式"""
+
+    _instance_lock = threading.Lock()
+
+    def __new__(cls, *args, **kwargs):
+        if not hasattr(cls, "_instance"):
+            with cls._instance_lock:
+                if not hasattr(cls, "_instance"):
+                    impl = cls.configure() if hasattr(cls, "configure") else cls
+                    instance = super(Singleton, cls).__new__(impl, *args, **kwargs)
+                    if not isinstance(instance, cls):
+                        instance.__init__(*args, **kwargs)
+                    cls._instance = instance
+        return cls._instance
+
+
+class UrllibClient(object):
+    """使用urlib2发送请求"""
+
+    def get(self, url, second=30):
+        return self.postXml(None, url, second)
+
+    def post(self,url,data):
+        req = urllib2.Request(url)
+        data = urllib.urlencode(data)
+        opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
+        response = opener.open(req, data) 
+        return response.read()
+
+    def postXml(self, xml, url, second=30):
+        """不使用证书"""
+        data = urllib2.urlopen(url, xml, timeout=second).read()
+        return data
+
+    def postXmlSSL(self, xml, url, second=30):
+        """使用证书"""
+        raise TypeError("please use CurlClient")
+
+
+class CurlClient(object):
+    """使用Curl发送请求"""
+    def __init__(self):
+        self.curl = pycurl.Curl()
+        self.curl.setopt(pycurl.SSL_VERIFYHOST, False)
+        self.curl.setopt(pycurl.SSL_VERIFYPEER, False)
+        #设置不输出header
+        self.curl.setopt(pycurl.HEADER, False)
+
+    def get(self, url, second=30):
+        return self.postXmlSSL(None, url, second=second, cert=False, post=False)
+
+    def postXml(self, xml, url, second=30):
+        """不使用证书"""
+        return self.postXmlSSL(xml, url, second=second, cert=False, post=True)
+        
+
+    def postXmlSSL(self, xml, url, second=30, cert=True, post=True):
+        """使用证书"""
+        self.curl.setopt(pycurl.URL, url)
+        self.curl.setopt(pycurl.TIMEOUT, second)
+        #设置证书
+        #使用证书:cert 与 key 分别属于两个.pem文件
+        #默认格式为PEM,可以注释
+        if cert:
+            self.curl.setopt(pycurl.SSLKEYTYPE, "PEM")
+            self.curl.setopt(pycurl.SSLKEY, WxPayConf_pub.SSLKEY_PATH)
+            self.curl.setopt(pycurl.SSLCERTTYPE, "PEM")
+            self.curl.setopt(pycurl.SSLCERT, WxPayConf_pub.SSLCERT_PATH)
+        #post提交方式
+        if post:
+            self.curl.setopt(pycurl.POST, True)
+            self.curl.setopt(pycurl.POSTFIELDS, xml)
+        buff = StringIO()
+        self.curl.setopt(pycurl.WRITEFUNCTION, buff.write)
+
+        self.curl.perform()
+        return buff.getvalue()
+
+
+class HttpClient(Singleton):
+    @classmethod
+    def configure(cls):
+        if pycurl is not None and WxPayConf_pub.HTTP_CLIENT != "URLLIB":
+            return CurlClient
+        else:
+            return UrllibClient
+            
+
+class Common_util_pub(object):
+    """所有接口的基类"""
+
+    def trimString(self, value):
+        if value is not None and len(value) == 0:
+            value = None
+        return value
+
+    def createNoncestr(self, length = 32):
+        """产生随机字符串,不长于32位"""
+        chars = "abcdefghijklmnopqrstuvwxyz0123456789"
+        strs = []
+        for x in range(length):
+            strs.append(chars[random.randrange(0, len(chars))])
+        return "".join(strs)
+
+    def formatBizQueryParaMap(self, paraMap, urlencode):
+        """格式化参数,签名过程需要使用"""
+        slist = sorted(paraMap)
+        buff = []
+        for k in slist:
+            v = quote(paraMap[k]) if urlencode else paraMap[k]
+            buff.append("{0}={1}".format(k, v))
+
+        return "&".join(buff)
+
+    def getSign(self, obj):
+        """生成签名"""
+        #签名步骤一:按字典序排序参数,formatBizQueryParaMap已做
+        String = self.formatBizQueryParaMap(obj, False)
+        #签名步骤二:在string后加入KEY
+        String = "{0}&key={1}".format(String,WxPayConf_pub.KEY)
+        #签名步骤三:MD5加密
+        String = hashlib.md5(String).hexdigest()
+        #签名步骤四:所有字符转为大写
+        result_ = String.upper()
+        return result_
+
+    def arrayToXml(self, arr):
+        """array转xml"""
+        xml = ["<xml>"]
+        for k, v in arr.iteritems():
+            if v.isdigit():
+                xml.append("<{0}>{1}</{0}>".format(k, v))
+            else:
+                xml.append("<{0}>{1}</{0}>".format(k, v))
+        xml.append("</xml>")
+        return "".join(xml)
+
+    def xmlToArray(self, xml):
+        """将xml转为array"""
+        array_data = {}
+        root = ET.fromstring(xml)
+        for child in root:
+            value = child.text
+            array_data[child.tag] = value
+        return array_data
+
+    def postXmlCurl(self, xml, url, second=30):
+        """以post方式提交xml到对应的接口url"""
+        return HttpClient().postXml(xml, url, second=second)
+
+    def postXmlSSLCurl(self, xml, url, second=30):
+        """使用证书,以post方式提交xml到对应的接口url"""
+        return HttpClient().postXmlSSL(xml, url, second=second)
+
+
+class Wxpay_client_pub(Common_util_pub):
+    """请求型接口的基类"""
+    response = None  #微信返回的响应
+    url = None       #接口链接
+    curl_timeout = None #curl超时时间
+
+    def __init__(self):
+        self.parameters = {} #请求参数,类型为关联数组
+        self.result = {}     #返回参数,类型为关联数组
+
+
+    def setParameter(self, parameter, parameterValue):
+        """设置请求参数"""
+        self.parameters[self.trimString(parameter)] = self.trimString(parameterValue)
+
+    def createXml(self):
+        """设置标配的请求参数,生成签名,生成接口参数xml"""
+        return  self.arrayToXml(self.parameters)
+
+    def postXml(self):
+        """post请求xml"""
+        xml = self.createXml()
+        self.response = self.postXmlCurl(xml, self.url, self.curl_timeout)
+        return self.response
+
+    def postXmlSSL(self):
+        """使用证书post请求xml"""
+        xml = self.createXml()
+        self.response = self.postXmlSSLCurl(xml, self.url, self.curl_timeout)
+        return self.response
+
+    def getResult(self):
+        """获取结果,默认不使用证书"""
+        self.postXml()
+        self.result = self.xmlToArray(self.response)
+        return self.result
+
+
+class UnifiedOrder_pub(Wxpay_client_pub):
+    """统一支付接口类"""
+
+    def __init__(self, timeout=WxPayConf_pub.CURL_TIMEOUT):
+        #设置接口链接
+        self.url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
+        #设置curl超时时间
+        self.curl_timeout = timeout
+        super(UnifiedOrder_pub, self).__init__()
+
+
+    def createXml(self):
+        """生成接口参数xml"""
+        #检测必填参数
+        if any(self.parameters[key] is None for key in ("out_trade_no", "total_fee")):
+            raise ValueError("missing parameter")
+        if self.parameters["trade_type"] == "JSAPI" and self.parameters["openid"] is None:
+            raise ValueError("JSAPI need openid parameters")
+
+        self.parameters["appid"] = WxPayConf_pub.APPID  #公众账号ID
+        self.parameters["mch_id"] = WxPayConf_pub.MCHID  #商户号
+        self.parameters["spbill_create_ip"] = "127.0.0.1"  #终端ip      
+        self.parameters["nonce_str"] = self.createNoncestr()  #随机字符串
+        self.parameters["notify_url"] = WxPayConf_pub.NOTIFY_URL  #随机字符串
+        self.parameters["body"] = "培训报名费"  #随机字符串
+        if self.parameters.has_key("sign"):
+            self.parameters.pop("sign")
+        sign = self.getSign(self.parameters)
+        print self.parameters
+        self.parameters["sign"] = sign  #签名
+        return  self.arrayToXml(self.parameters)
+
+    def getPrepayId(self):
+        """获取prepay_id"""
+        self.postXml()
+        self.result = self.xmlToArray(self.response)
+        print self.result
+        return self.result
+
+    def geth5url(self):
+        """获取prepay_id"""
+        self.postXml()
+        self.result = self.xmlToArray(self.response)
+        prepay_id = self.result["mweb_url"]
+        return prepay_id
+
+def get_wx_unifiedorder(out_trade_no,total_fee,openid,trade_type="JSAPI"):
+    par_obj = UnifiedOrder_pub()
+    par_obj.setParameter('out_trade_no',out_trade_no)
+    par_obj.setParameter('total_fee',total_fee)
+    par_obj.setParameter('openid',openid)
+    par_obj.setParameter('trade_type',trade_type)
+    par_obj.createXml()
+    return par_obj.getPrepayId()
+
+
+
+
+if __name__ == "__main__":
+    pass

+ 87 - 0
src/oplog/OpLogMiddleware.py

@@ -0,0 +1,87 @@
+#-*-coding:utf-8 -*-
+"""
+"""
+import re,json
+import common.models as cm
+import common.core_views as cv
+
+class OpLogMiddleware(object):
+    def __init__(self,get_response):
+        '''
+        '''
+        self.get_response = get_response
+
+    def __call__(self,request):
+        '''
+        '''
+        response = self.get_response(request)
+        path = request.path.strip()
+        if path not in ["/api/doc/","/favicon.ico","/api/hook/"] and "/api/report/download" not in path:
+            self.record_oplog(request,response)
+        return response
+
+    def record_oplog(self,request,response):
+        """
+        """
+        try:
+            op_view = re.findall(r'func=([\.\w]+)\b',str(request.resolver_match))[0]
+        except:
+            op_view = "testview"
+        op_action_flag = request.method
+        op_url = request.path.strip()
+        #op_url = op_url.split("?")[0]
+        if request.META.get("CONTENT_TYPE","") == "application/json":
+            reqdata = request.body if request.body else {}
+        else:
+            if op_action_flag == "POST":
+                reqdata = request.POST.dict()
+            elif op_action_flag == "GET":
+                reqdata = request.GET.dict()
+            else:
+                reqdata = request.body if request.body else {}
+        reqdata = json.dumps(reqdata)
+        try:
+            op_user_name = request.user.name if request.user and request.user.id else reqdata.get("name",u"匿名")
+            op_user_realname = request.user.realname if request.user and request.user.id else reqdata.get("realname",u"匿名")
+        except:
+            op_user_name = ""
+            op_user_realname = ""
+        op_user_id = request.user.id if request.user else 0 
+        op_user_id = op_user_id if op_user_id else 0
+        op_user_ip = cv.get_ip(request)
+        op_request = json.dumps(reqdata)
+        try:
+            response_data = json.loads(response.getvalue())
+        except:
+            response_data = {}
+        if response_data.get("status") == "suc" or response_data.get("code") == 0:
+            is_suc = 1
+            error_msg = ""
+        else:
+            is_suc = 0
+            error_msg = response_data.get("message")
+        #
+        last = cm.OperationLogConfig.objects.order_by("order").last()
+        last_order = last.order if last else 0
+        obj,flag = cm.OperationLogConfig.objects\
+                .get_or_create(**{"op_view":op_view,"op_action_flag":op_action_flag,"op_url":op_url})
+        if flag:
+            obj.order = last_order
+        if not obj.op_response:
+            if response_data.get("status") == "suc" or response_data.get("code") == 0:
+                obj.op_response = json.dumps(response_data)
+                obj.save()
+        #if not obj.op_request:
+        #        obj.op_request = json.dumps(request.json)
+        #        obj.save()
+        cm.OperationLog.objects.create(
+            op_user_name = op_user_name,
+            op_user_realname = op_user_realname,
+            op_user_id = op_user_id,
+            op_user_ip = op_user_ip,
+            op_request = op_request,
+            op_config = obj, 
+            is_suc = is_suc,
+            error_msg = error_msg
+        )
+

+ 0 - 0
src/oplog/__init__.py


+ 45 - 0
src/oplog/control_oplog.py

@@ -0,0 +1,45 @@
+# -*-coding:utf-8-*-
+import datetime
+
+import common.error_info as ce
+import common.models as cm
+import common.common_functions as ccf
+import common.common_control as ccc
+
+
+def get_oplog_list(request):
+    filter_info = request.json
+    qset = cm.OperationLog.objects.all()
+    if filter_info.get("op_user_name"):
+        qset = qset.filter(op_user_name__icontains=filter_info.get("op_user_name"))
+    if filter_info.get("op_user_ip"):
+        qset = qset.filter(op_user_ip=filter_info.get("op_user_ip"))
+    if filter_info.get("op_content"):
+        qset = qset.filter(op_content=filter_info.get("op_content"))
+    # if filter_info.get("stime"):
+    #     qset = qset.filter(ctime__gte=filter_info.get("stime"))
+    # if filter_info.get("etime"):
+    #     qset = qset.filter(ctime__lte=filter_info.get("etime"))
+    if filter_info.get("ctime", ""):
+        import web_site.tools as wst
+        query = wst.datetime_filter("ctime", {}, filter_info["ctime"])
+        qset = qset.filter(**query)
+    count = qset.count()
+    page = filter_info.get("page")
+    page_size = filter_info.get("page_size")
+    if page and page_size:
+        count,qset = ccc.get_page_qset(qset,page,page_size)
+    qdata = list(qset.values("op_user_name","op_user_realname","op_user_ip","ctime","is_suc"))
+    for qd in qdata:
+        qd["op_module"] = "系统管理"
+        qd["op_content"] = "删除root用户成功"
+
+    return count,qdata
+
+
+def get_warning_notice(*ids):
+    """
+    """
+    qset = cm.WarningNotice.objects.filter(id__in=ids)
+    qdata = qset.values()
+    return qdata

+ 11 - 0
src/oplog/urls_backstage.py

@@ -0,0 +1,11 @@
+# coding=utf-8
+'''
+'''
+from django.conf.urls import url
+from operation_log import views_oplog
+
+urlpatterns = [
+    #任务
+    url(r'^list$', views_oplog.OPlogListView.as_view()),
+]
+

+ 30 - 0
src/oplog/views_oplog.py

@@ -0,0 +1,30 @@
+#-*-coding:utf-8-*-
+import json
+import uuid
+from django.contrib import auth
+from django.core.cache import cache
+from django.conf import settings
+
+from common import core_views as cv
+from common.models import UserInfo
+import common.common_functions as ccf
+import common.error_info as ce
+import operation_log.control_oplog as cop
+
+
+class OPlogListView(cv.AuthView):
+    def get(self, request):
+        """
+        #获取操作日志列表
+        @op_user_name:"名称",
+        @op_user_ip:"称",ip
+        @op_content:"称",操作详情
+        @ctime:"2020-03-04 00:00:00,2020-03-05 00:00:00" 时间范围
+        """
+        try:
+            count,res = cop.get_oplog_list(request)
+            return cv.to_suc({"total":count,"list":res})
+        except Exception as e:
+            return cv.to_fail(e)
+
+

+ 3 - 0
src/settings/__init__.py

@@ -0,0 +1,3 @@
+#coding=utf-8
+from settings_dev import *
+

+ 124 - 0
src/settings/base.py

@@ -0,0 +1,124 @@
+#coding=utf-8
+"""
+Django settings for wzbapi project.
+
+Generated by 'django-admin startproject' using Django 1.11.1.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.11/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.11/ref/settings/
+"""
+
+import os
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '19r&eh*ykwhtyg@zr0zvo(wnr_5y8qg5-1!0=a*!!$!pf3smi6'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = False
+
+ALLOWED_HOSTS = [
+    "*"
+]
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'common',
+    'account',
+    'weixin',
+    'manage',
+    'wzbapi'
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    #'django.middleware.cache.CacheMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    #'oplog.OpLogMiddleware.OpLogMiddleware'
+]
+
+ROOT_URLCONF = 'urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [os.path.join(BASE_DIR,"../templates"),],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'wsgi.application'
+
+# Password validation
+# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+LANGUAGE_CODE = 'zh-hans'
+
+TIME_ZONE = 'Asia/Shanghai'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = False
+DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
+
+STATIC_URL = '/static/'
+
+STATICFILES_DIRS = (
+    (os.path.join(BASE_DIR, '../static')),
+)
+STATIC_ROOT = '/mnt/wzbapi/static'
+
+# 节点上报超时配置(单位:秒)
+SERVER_REPORT_TIMEOUT = 60 * 10
+
+AUTHENTICATION_BACKENDS = [
+    "account.cauth.AccountManage",
+]
+

+ 63 - 0
src/settings/settings_dev.py

@@ -0,0 +1,63 @@
+# coding=utf-8
+from base import *
+
+# redis配置
+CACHES = {
+    'default': {
+        'BACKEND': 'django_redis.cache.RedisCache',
+        'LOCATION': 'redis://127.0.0.1:6379/0',
+        "OPTIONS": {
+            "CLIENT_CLASS": "django_redis.client.default.DefaultClient",
+        },
+    },
+}
+
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.mysql',
+        'NAME': 'wanzb',
+        'USER': 'root',
+        'PASSWORD': 'xjc890*()',
+        'HOST': '127.0.0.1',
+        'PORT': '3306',
+    }
+}
+
+# 验证码字体库位置
+FONT_PATH = os.path.join(BASE_DIR, "../static/font", "consola.ttf")
+
+AUTHENTICATION_BACKENDS = [
+    "account.cauth.AccountManage",
+]
+
+# session 过期设置
+SESSION_COOKIE_AGE = 60 * 30
+SESSION_SAVE_EVERY_REQUEST = True
+SESSION_COOKIE_HTTPONLY = False
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'formatters': {
+        'standard': {
+            'format': '%(asctime)s [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'
+        }
+    },
+    'handlers': {
+        'console': {
+            'class': 'logging.StreamHandler',
+            'level': 'INFO',
+            'formatter': 'standard'
+        },
+    },
+    'loggers': {
+        '': {
+            'handlers': ['console'],
+            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
+        }
+    },
+}
+
+HOST = "http://www.baianxi.com"
+PROJECT_NAME = u"白安兮"

+ 80 - 0
src/settings/settings_online.py

@@ -0,0 +1,80 @@
+# coding=utf-8
+from base import *
+
+# redis配置
+CACHES = {
+    'default': {
+        'BACKEND': 'django_redis.cache.RedisCache',
+        'LOCATION': 'redis://127.0.0.1:6379/0',
+        "OPTIONS": {
+            "CLIENT_CLASS": "django_redis.client.default.DefaultClient",
+        },
+    },
+}
+
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.mysql',
+        'NAME': 'xeshop',
+        'USER': 'root',
+        'PASSWORD': 'xjc890*()',
+        'HOST': '127.0.0.1',
+        'PORT': '3306',
+    }
+}
+
+# 短信配置  common.sms.py使用
+SMS_ACCOUNT_SID = "8a216da8588b296f01588ecd0a0001ab"
+SMS_AUTH_TOKEN = "f0d2b53782374ebc8a76fa8dd06bb4d2"
+SMS_APP_ID = "8a216da8589ae4840158a89b5c8f0272"
+SMS_URL = "https://app.cloopen.com:8883/2013-12-26/Accounts/%s/SMS/TemplateSMS" % SMS_ACCOUNT_SID
+SMS_LOG_PATH = os.path.join(BASE_DIR, "../logs", "sms")
+SEND_SMS = False
+
+# 验证码字体库位置
+FONT_PATH = os.path.join(BASE_DIR, "../static/font", "consola.ttf")
+
+AUTHENTICATION_BACKENDS = [
+    "account.cauth.AccountManage",
+]
+
+# session 过期设置
+SESSION_COOKIE_AGE = 60 * 30
+SESSION_SAVE_EVERY_REQUEST = True
+SESSION_COOKIE_HTTPONLY = False
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'formatters': {
+        'standard': {
+            'format': '%(asctime)s [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'
+        }
+    },
+    'handlers': {
+        'console': {
+            'class': 'logging.StreamHandler',
+            'level': 'INFO',
+            'formatter': 'standard'
+        },
+    },
+    'loggers': {
+        '': {
+            'handlers': ['console'],
+            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
+        }
+    },
+}
+
+
+#channels                                                                          
+CHANNEL_LAYERS = {                                                                 
+    "default": {                                                                   
+        "BACKEND": "asgi_redis.RedisChannelLayer",                                     
+        "CONFIG": {                                                                    
+                    "hosts": [os.environ.get('REDIS_URL', 'redis://localhost:6379')],          
+                },                                                                             
+            "ROUTING": "dashboard.routings.channel_routing",                         
+        },                                                                             
+} 

二進制
src/templates/157883436884.docx


二進制
src/templates/18920987654.docx


二進制
src/templates/24.docx


二進制
src/templates/9.docx


二進制
src/templates/apply_template.docx


二進制
src/templates/apply_template_aqxy.docx


二進制
src/templates/apply_template_cyry.docx


二進制
src/templates/apply_template_tzzy.docx


二進制
src/templates/classhour.png


二進制
src/templates/font/consola.ttf


二進制
src/templates/font/simkai.ttf


二進制
src/templates/font/simsun.ttc


二進制
src/templates/kqqd.xls


二進制
src/templates/kqqd.xlsx


二進制
src/templates/ksqd.xls


二進制
src/templates/pxqd.xls


二進制
src/templates/qtcy.xls


二進制
src/templates/szksqd.xls


二進制
src/templates/test.xlsx


二進制
src/templates/tzzy.xls


二進制
src/templates/tzzy_bk.xls


二進制
src/templates/tzzykssbb.xls


二進制
src/templates/xxkqqd.xls


二進制
src/templates/zyfzr.xls


二進制
src/templates/肖小肖_低压电工.docx


二進制
src/templates/谭燕飞.docx


+ 38 - 0
src/urls.py

@@ -0,0 +1,38 @@
+#coding=utf-8
+"""cloud_defense URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/1.11/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.conf.urls import url, include
+    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
+"""
+import os
+
+from django.conf import settings
+from django.conf.urls import url, include
+from django import views
+
+
+import wzbapi.views as wview
+
+
+urlpatterns = [
+    url(r'^api/doc/', wview.DocView.as_view()),
+    url(r'^api/account/', include('account.urls_backstage')),
+    url(r'^api/wx/', include('weixin.urls_backstage')),
+    url(r'^api/admin/', include('manage.urls_backstage'))
+]
+
+urlpatterns += [
+    #url(r'^static/(?P<path>.*)$', views.static.serve, { 'document_root': settings.STATIC_ROOT})
+]
+
+

+ 0 - 0
src/utils/__init__.py


+ 79 - 0
src/utils/aestool.py

@@ -0,0 +1,79 @@
+#-*-coding:utf-8 -*-
+from cryptography.hazmat.primitives import padding
+from cryptography.hazmat.primitives.ciphers import algorithms
+from Crypto.Cipher import AES
+from binascii import b2a_hex, a2b_hex
+from urllib import urlencode
+from collections import OrderedDict
+import base64
+import json
+
+class AESCBCCrypt(object):
+
+    def __init__(self, key='c1a5fd9f724143e8'):
+        self.key = key.encode('utf-8')
+        self.mode = AES.MODE_CBC
+        self.iv = b'81dc198a449eb47f'
+        # block_size 128位
+
+    # 加密函数,如果text不足16位就用空格补足为16位,
+    # 如果大于16但是不是16的倍数,那就补足为16的倍数。
+    def encrypt(self, text):
+        cryptor = AES.new(self.key, self.mode, self.iv)
+        text = text.encode('utf-8')
+
+        # 这里密钥key 长度必须为16(AES-128),24(AES-192),或者32 (AES-256)Bytes 长度
+        # 目前AES-128 足够目前使用
+
+        text=self.pkcs7_padding(text)
+
+        self.ciphertext = cryptor.encrypt(text)
+
+        # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
+        # 所以这里统一把加密后的字符串转化为16进制字符串
+        return b2a_hex(self.ciphertext).decode().upper()
+        #return base64.b64encode(self.ciphertext)
+
+    @staticmethod
+    def pkcs7_padding(data):
+        if not isinstance(data, bytes):
+            data = data.encode()
+
+        padder = padding.PKCS7(algorithms.AES.block_size).padder()
+
+        padded_data = padder.update(data) + padder.finalize()
+
+        return padded_data
+
+    @staticmethod
+    def pkcs7_unpadding(padded_data):
+        unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
+        data = unpadder.update(padded_data)
+
+        try:
+            uppadded_data = data + unpadder.finalize()
+        except ValueError:
+            raise Exception('无效的加密信息!')
+        else:
+            return uppadded_data
+
+    # 解密后,去掉补足的空格用strip() 去掉
+    def decrypt(self, text):
+        #  偏移量'iv'
+        cryptor = AES.new(self.key, self.mode, self.iv)
+        plain_text = cryptor.decrypt(a2b_hex(text))
+        # return plain_text.rstrip('\0')
+        return bytes.decode(plain_text).rstrip("\x01").\
+            rstrip("\x02").rstrip("\x03").rstrip("\x04").rstrip("\x05").\
+            rstrip("\x06").rstrip("\x07").rstrip("\x08").rstrip("\x09").\
+            rstrip("\x0a").rstrip("\x0b").rstrip("\x0c").rstrip("\x0d").\
+            rstrip("\x0e").rstrip("\x0f").rstrip("\x10")
+
+    def dict_json(self, d):
+        '''python字典转json字符串, 去掉一些空格'''
+        j = json.dumps(d).replace('": ', '":').replace(', "', ',"').replace(", {", ",{")
+        return j
+
+aescbc = AESCBCCrypt()
+print aescbc.encrypt("root")
+

+ 97 - 0
src/utils/aliyun_email.py

@@ -0,0 +1,97 @@
+#-*-coding:utf-8 -*-
+import hmac
+import base64
+import requests
+import datetime,time
+import urllib
+import uuid
+from hashlib import sha1
+
+class AliEmailClient(object):
+    """阿里云邮件推送
+    """
+    def __init__(self):
+        self.url = "http://dm.aliyuncs.com"
+        self.AccessKeyId = "LTAI6puCBe6A1lOa"
+        self.AccessKeySecret = "VeWxSWEWM8xULzbnbCHDkSn7QPvasO"
+
+    def percent_encode(self,encodeStr):
+        """
+        """
+        encodeStr = str(encodeStr)
+        res = urllib.quote(encodeStr.decode("utf-8").encode("utf-8"),"")
+        res = res.replace("+","%20")
+        res = res.replace("*","%2A")
+        res = res.replace("%7E","~")
+
+        return res
+
+    def gen_signature(self,params):
+        """
+        """
+        sortedParams = sorted(params.items(),key=lambda x:x[0])
+        canonicalizedQueryString = ''
+        for k,v in sortedParams:
+            canonicalizedQueryString += '&' + self.percent_encode(k) \
+                + '=' + self.percent_encode(v)
+        stringToSign = 'GET&%2F&' + self.percent_encode(canonicalizedQueryString[1:])
+        hmc = hmac.new(self.AccessKeySecret + "&",stringToSign,sha1)
+        signature = base64.encodestring(hmc.digest()).strip()
+        
+        return signature
+
+    def gen_params(self,params={}):
+        """
+        """
+        pub_param = {
+            "Format":"JSON", 
+            "Version":"2015-11-23",
+            "AccessKeyId":self.AccessKeyId,
+            "SignatureMethod":"HMAC-SHA1",
+            "Timestamp":time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),
+            "SignatureVersion":"1.0",
+            "SignatureNonce":str(uuid.uuid1()),
+        }
+        for key in pub_param:
+            params.update({key:pub_param[key]})
+        signature = self.gen_signature(params)
+        params["Signature"] = signature
+
+        return params
+        
+
+    def send_mail(self,to,subject,content):
+        """
+        """
+        params = {
+            "Action":"SingleSendMail",
+            "AccountName":"swad-services@mail.365gcd.com",
+            "ReplyToAddress":True,
+            "AddressType":1,
+            "ToAddress":to,
+            "FromAlias":"中国网安云安全".decode("utf-8").encode("utf-8"),
+            "Subject":unicode(subject).encode("utf-8"),
+            "HtmlBody":unicode(content).encode("utf-8")
+        }
+        url = self.url + "/?" + urllib.urlencode(self.gen_params(params))
+        res = requests.get(url)
+        print res
+        return res.json() if res else {}
+
+    def batch_send_mail(self,to,subject,content):
+        """批量发送
+        """
+if __name__ == "__main__":
+    aliemail_client = AliEmailClient()
+    to = "scxiaojincai@163.com"
+    to = "496498291@qq.com"
+    subject = u"测试"
+    content = u"测试"
+    res = aliemail_client.send_mail(to,subject,content)
+    print res
+
+
+
+
+
+

+ 158 - 0
src/utils/aliyun_sms.py

@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+#coding=utf-8
+import json
+from aliyunsdkcore.client import AcsClient
+from aliyunsdkcore.request import CommonRequest
+client = AcsClient('LTAIbY5V8m3zBjrT', 'H0UrXv6cVYoQLRUdD9ZR7DvF2Sr0FX', 'cn-hangzhou')
+
+def send_audit_notice(phone,subject_item):
+    """发送审核通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_192150140")
+    request.add_query_param('TemplateParam', json.dumps({"subject_item":subject_item}))
+    response = client.do_action(request)
+    return True,u"success"
+
+def send_unauthed_notice(phone):
+    """审核不通过短信通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_192770033")
+    response = client.do_action(request)
+    return True,u"success"
+
+def send_update_notice(phone,name,subject_item):
+    """证件复审通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_192820850")
+    request.add_query_param('TemplateParam', json.dumps({"subject_item":subject_item,"name":name}))
+    response = client.do_action(request)
+    return True,u"success"
+
+def send_expired_notice(phone,name,subject_item):
+    """证件到期通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_192820847")
+    request.add_query_param('TemplateParam', json.dumps({"subject_item":subject_item,"name":name}))
+    response = client.do_action(request)
+    return True,u"success"
+
+def send_pay_notice(phone):
+    """支付成功通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_193240726")
+    response = client.do_action(request)
+    return True,u"success"
+
+def send_training_notice(phone,subject_item,begin_time,end_time):
+    """培训通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_193240727")
+    request.add_query_param('TemplateParam', json.dumps({"subject_item":subject_item,"begin_time":begin_time,"end_time":end_time}))
+    response = client.do_action(request)
+    return True,u"success"
+
+def send_training_notice_special(phone,subject_item,begin_time):
+    """特种作业培训通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_193230747")
+    request.add_query_param('TemplateParam', json.dumps({"subject_item":subject_item,"begin_time":begin_time}))
+    response = client.do_action(request)
+    return True,u"success"
+
+
+def send_exam_notice(phone,name,subject_item,exam_time):
+    """考试通知
+    """
+    request = CommonRequest()
+    request.set_accept_format('json')
+    request.set_domain('dysmsapi.aliyuncs.com')
+    request.set_method('POST')
+    request.set_protocol_type('https') # https | http
+    request.set_version('2017-05-25')
+    request.set_action_name('SendSms')
+
+    request.add_query_param('RegionId', "cn-hangzhou")
+    request.add_query_param('PhoneNumbers', phone)
+    request.add_query_param('SignName', "逸沣安全培训")
+    request.add_query_param('TemplateCode', "SMS_193235744")
+    request.add_query_param('TemplateParam', json.dumps({"name":name,"subject_item":subject_item,
+        "exam_time":exam_time,"phone":"15884997924"}))
+    response = client.do_action(request)
+    return True,u"success"

+ 164 - 0
src/utils/cloopen_sms.py

@@ -0,0 +1,164 @@
+#coding=utf-8
+'''
+Created on 2018年12月11日
+@author: xiaojincai
+'''
+import os
+import json
+import random
+import datetime
+from hashlib import md5
+import threading
+import logging
+
+import base64
+import requests
+
+logger = logging.getLogger(__name__)
+
+SMS_TEMPLATE_DCT = {
+    "version":"v2.4",
+    "sign":u"【网安云防御】",
+    "396732":{
+        "template_id":"396732",
+        "title":u"用户信息邮件变更通知",
+        "content":u"您的注册邮箱地址在{}由{}变更为{}。如有疑问,请及时与运营人员联系!" 
+    },
+    "400033":{
+        "template_id":"400033",
+        "title":u"用户信息手机号变更通知", 
+        "content":u"您的注册手机号码在{}由{}变更为{}。如有疑问,请及时与运营人员联系!" 
+    },
+    "396735":{
+        "template_id":"396735",
+        "title":u"账号到期提醒通知", 
+        "content":u"您的账号{}将于{}到期,届时该账号下的网站将被停止安全防护服务,请及时与运营人员联系!" 
+    },
+    "396737":{
+        "template_id":"396737",
+        "title":u"账号到期提醒通知(运营)", 
+        "content":u"{}账号将于{}到期,请及时处理!" 
+    },
+    "396739":{
+        "template_id":"396739",
+        "title":u"网站迁出提醒通知(用户)", 
+        "content":u"经检测发现,您的网站{}在{}已迁出云防御系统,处于未防御状态,请予以关注!" 
+    },
+    "396740":{
+        "template_id":"396740",
+        "title":u"网站迁出提醒通知(运营)", 
+        "content":u"经检测发现,网站{}在{}已迁出云防御系统,处于未防御状态,请及时处理!" 
+    },
+    "396742":{
+        "template_id":"396742",
+        "title":u"防御状态变更通知(用户)", 
+        "content":u"您的网站{}在{}变更为{}状态,请予以关注!" 
+    },
+    "396744":{
+        "template_id":"396744",
+        "title":u"防御状态变更通知(运营)", 
+        "content":u"网站{}在{}变更为{}状态,请及时处理!" 
+    },
+    "396746":{
+        "template_id":"396746",
+        "title":u"网站删除通知", 
+        "content":u"网站{}在{}被用户{}删除,云防御系统将无法继续提供安全防护服务,请予以关注!" 
+    },
+    "397198":{
+        "template_id":"397198",
+        "title":u"网站防护策略修改通知", 
+        "content":u"网站{}在{}被用户{}修改了{}策略,请予以关注!" 
+    },
+    "400981":{
+        "template_id":"400981",
+        "title":u"网站到期提醒", 
+        "content":u"您的网站{}将于{}到期,届时该网站将会被自动回源,停止安全防护服务,请及时与运营人员联系!" 
+    },
+    "400984":{
+        "template_id":"400984",
+        "title":u"网站到期提醒(运营)", 
+        "content":u"{}网站将于{}到期,请及时处理!" 
+    },
+    "401151":{
+        "template_id":"401151",
+        "title":u"重置密码短信验证码", 
+        "content":u"您正在进行重置密码操作,验证码是{},请于{}分钟内正确输入!" 
+    },
+    "423122":{
+        "template_id":"423122",
+        "title":u"网站可用状态变更", 
+        "content":u"您的网站{}在{}{}为{}状态,请予以关注!" 
+    }
+}
+
+class CloopenSMS(object):
+    """融联短信接口
+    """
+    def __init__(self):
+        self.sid = "8a216da8588b296f01588ecd0a0001ab"
+        self.token = "f0d2b53782374ebc8a76fa8dd06bb4d2"
+        self.appId = "8a216da8589ae4840158a89b5c8f0272"
+        self.base_url = "https://app.cloopen.com:8883/2013-12-26/Accounts/%s/SMS/TemplateSMS" % self.sid
+         
+    def send(self,phones,template_id,content):
+        """
+        @attention: 发送短信
+        @param content: 短信内容模板变量数组
+        @param phones: 电话号码集合,格式为数组
+        """
+        #构造url
+        now = datetime.datetime.now()
+        batch = now.strftime("%Y%m%d%H%M%S")
+        signature = self.sid + self.token + batch
+        sig = md5(signature).hexdigest().upper()
+        url = self.base_url + "?sig=" + sig
+        
+        #构造header
+        src = "%s:%s"%(self.sid,batch)
+        auth = base64.encodestring(src).strip()
+        headers = {"Accept": "application/json",
+                   "Content-Type": "application/json;charset=utf-8",
+                   "Authorization": auth}
+        
+        #构造body
+        content = map(lambda x:x if isinstance(x, unicode) else str(x).decode("utf8"), content)
+
+        print "send sms >>>:",phones,template_id,content
+        body = {"to": ','.join(phones),
+                "appId": self.appId,
+                "templateId": template_id,
+                "datas": content
+                }
+            
+        #成功直接返回1,失败记录日志,并返回0
+        status_code = ""
+        status_msg = ""
+        response = requests.post(url, headers=headers, data=json.dumps(body))
+        response_code = response.status_code
+        if response_code==200:
+            data = response.json()
+            if data["statusCode"]=="000000":
+                return 1,data
+            else:
+                status_code = data["statusCode"]
+                status_msg = data["statusMsg"]
+                return 0,data
+                
+        #内容,模板ID,号码,http错误码,定义的错误码,操作时间,url
+        now_time = now.strftime("%Y-%m-%d %H:%M:%S")
+        msg = "<<(%s_%s_%s) %s>>:url=%s;\n"%(response_code,status_code,status_msg,now_time,url)
+        sc = ",".join(content)
+        sp = ",".join(phones)
+        msg += "content=[%s];template_id=%s;phones=[%s]\n"%(sc,template_id,sp)
+        return 0,u"未知错误(短信接口报错)"
+
+cloopensms = CloopenSMS()
+
+if __name__ == '__main__':
+    #测试
+    phones = ['15982456282']
+    template_id = '396732'
+    content = ["2018-12-11 14:00:00","496498291@qq.com","496498291@qq.com"]
+
+    cloopensms.send(phones,template_id,content)
+

+ 29 - 0
src/utils/constant.py

@@ -0,0 +1,29 @@
+# coding:utf-8
+# 常用的常量
+DATETIME_FORMAT = "%Y%m%d%H%M%S"
+DATE_FORMAT = "%Y%m%d"
+TIME_FORMAT = "%H%M%S"
+
+DATETIME_FORMAT_DEFAULT = "%Y-%m-%d %H:%M:%S"
+DATE_FORMAT_DEFAULT = "%Y-%m-%d"
+TIME_FORMAT_DEFAULT = "%H:%M:%S"
+
+DATE_FORMAT_SPOT = "%Y.%m.%d"
+
+EVENT_TYPE_CHO = (
+    (1,u"可用性事件"),
+    (2,u"篡改事件"),
+    (3,u"敏感词事件"),
+    (4,u"非法外链事件"),
+    (5,u"非法外链事件"),
+    (6,u"漏洞事件")
+)
+
+EVENT_TYPE_DCT = {
+    "avaible":u"可用性事件",
+    "tamp":u"篡改事件",
+    "keyword":u"敏感词事件",
+    "hidden":u"非法外链事件",
+    "bug":u"漏洞事件",
+    "webshell":u"webshell"
+}

+ 134 - 0
src/utils/email_client.py

@@ -0,0 +1,134 @@
+# coding:utf-8
+# !/user/bin/python2
+"""
+邮件发送模块
+"""
+import time
+import json
+import logging
+from functools import partial
+import threading
+import requests
+import traceback
+
+from email.header import Header
+from email.MIMEText import MIMEText
+from email.utils import parseaddr,formataddr
+import smtplib,time,os
+
+from aliyun_email import AliEmailClient
+
+
+logger = logging.getLogger(__name__)
+
+
+
+Settings = type('Settings', (object, ), 
+                {'EMAIL_URL': 'https://182.138.102.104/push-gateway/v1/push', 
+                 'EMAIL_USER': 'mail.cetcsc.com',
+                 'EMAIL_PASSWD': '30sanpush'})
+
+
+class EmailClient(object):
+    """
+    邮件客户端
+    """
+
+    def __init__(self, url, user, passwd):
+        self.url = url
+        self.user = user
+        self.passwd = passwd
+
+    #def send(self, to, subject, content):
+    #    """
+    #    发送邮件
+    #    :params
+    #    to:   邮件列表 
+    #    subject: 主题
+    #    content: 内容
+    #    """
+    #    auth = requests.auth.HTTPDigestAuth(self.user, self.passwd)
+    #    data = self._gen_content(to, subject, content)
+    #    logger.info("send email, raw data: %s", str(data))
+    #    try:
+    #        r = requests.post(self.url, json=data, auth=auth, verify=False)
+    #        print r.json()
+    #    except Exception as e:
+    #        print e
+    #        return False,str(e)
+    #    if r.status_code != requests.codes.OK:
+    #        return False,r.json()
+    #    try:
+    #        logger.info('send email response: %s', str(r.text))
+    #        ret = r.json()
+    #        if ret['mail']['code'] != '0':
+    #            logger.error("send email failed, reason: %s ", str(ret))
+    #            return False,ret
+    #    except Exception as e:
+    #        return False,str(e)
+    #    return True,"success"
+
+    #def send(self,to,subject,content):
+    #    """
+    #    """
+    #    from_addr = "cetcsc_swad@163.com"
+    #    password = "AXN4zwIoCd"
+    #    smtp_server = "smtp.163.com"
+    #    #自定义处理邮件收发地址的显示内容
+    #    def _format_addr(s):
+    #        name,addr = parseaddr(s)
+    #        #将邮件的name转换成utf-8格式,addr如果是unicode,则转换utf-8输出,否则直接输出addr
+    #        return formataddr((\
+    #            Header(name,'utf-8').encode(),\
+    #            addr.encode("utf-8") if isinstance(addr,unicode) else addr))
+
+    #    #邮件正文是MIMEText
+    #    msg = MIMEText(content,'html','utf-8')
+    #    #邮件对象
+    #    msg['From'] = _format_addr(u'网络监测预警事业部 <%s>'%from_addr)
+    #    #msg['to'] = _format_addr(u'管理员<%s>'%to)
+    #    msg['Subject'] = Header(subject,'utf-8').encode()
+    #    msg['date'] = time.strftime("%a,%d %b %Y %H:%M:%S %z")
+    #    #发送邮件
+    #    try:
+    #        server = smtplib.SMTP(smtp_server,25)
+    #        #server.set_debuglevel(1)
+    #        server.login(from_addr,password)
+    #        server.sendmail(from_addr,to,msg.as_string())
+    #        server.quit()
+    #    except Exception as e:
+    #        return False,str(e)
+    #    return True,"success"
+
+    def send(self,to,subject,content):
+        """
+        """
+        aliemail_client = AliEmailClient()
+        to = to[0] if isinstance(to,type([])) else to
+        res = aliemail_client.send_mail(to,subject,content)
+        if res and res.get("RequestId") and res.get("EnvId"):
+            return True,"success"
+        else:
+            return False,res.get("Message","fail") if res else "fail"
+
+
+    def _gen_content(self, to, subject, content):
+        data = {
+                    "emails": to,
+                    "title": subject,
+                    "body": {
+                        "textHTML": content
+                    }
+                }
+        return data
+
+
+email_client = EmailClient(Settings.EMAIL_URL, Settings.EMAIL_USER, Settings.EMAIL_PASSWD)
+
+if __name__ == '__main__':
+    #测试
+    to = ["scxiaojincai@163.com"]
+    to = "496498291@qq.com"
+    subject = u"删除提醒"
+    content = u"网站{www.test1.com}在2018-08-30 15:30:10 被用户{xxx}删除,云防御系统将无法继续提供安全防护服务,请予以关注!"
+    email_client.send(to,subject,content)

+ 33 - 0
src/utils/excel_output.py

@@ -0,0 +1,33 @@
+# coding:utf-8
+import StringIO
+import xlwt
+import zipfile
+import datetime
+import random, string
+import os
+from ftplib import FTP
+
+def save2memory(en_cn_map, content):
+    """
+    保存内容到xls里面
+    :param en_cn_map:  英文中文对应字典 {"name": "名字"}, OrderedDict
+    :param content:
+    :return:
+    """
+    wb = xlwt.Workbook(encoding="utf-8")
+    sheet = wb.add_sheet('info')
+    sort_head = en_cn_map.keys()
+    for i, item in enumerate(en_cn_map):
+        sheet.write(0, i, en_cn_map.get(item))
+    for row, item in enumerate(content):
+        sort_key = item.keys()
+        for key in sort_key:
+            if key not in sort_head:
+                continue
+            sheet.write(row+1, sort_head.index(key), item.get(key, ''))
+    output = StringIO.StringIO()
+    wb.save(output)
+    return output.getvalue()
+
+if __name__ == '__main__':
+    pass

+ 46 - 0
src/utils/exceltool.py

@@ -0,0 +1,46 @@
+#-*-coding:utf-8 -*-
+import StringIO
+import xlwt
+import xlrd
+
+class ExcelTool(object):
+    """
+    """
+    def __init__(self,filename=None):
+        self.filename = filename
+        self.book = xlwt.Workbook(encoding="utf-8",style_compression=0)
+        self.rbook = xlrd.open_workbook(filename)
+        self.sheet = self.rbook.sheet_by_index(0)
+
+    def save_data(self,sheet,header,data):
+        """
+        """
+        sheet = self.book.add_sheet(sheet,cell_overwrite_ok=True)
+        #添加表头
+        for i in range(0,len(header)):
+            sheet.write(0,i,header[i])
+
+        #添加数据
+        for i in range(0,len(data)):
+            for j in range(0,len(data[i])): 
+                sheet.write(i+1,j,data[i][j])
+        output = StringIO.StringIO()
+        self.book.save(output)
+        self.book.save("/tmp/demo.xls")
+        return output.getvalue()
+
+    def get_data(self):
+        """
+        """
+        dct = {}
+        data = []
+        for i in range(1, self.sheet.nrows):
+            row_list = self.sheet.row_values(i)
+            data.append(row_list)
+        return data
+
+
+#if __name__ == "__main__":
+#    mexcel = ExcelTool("/tmp/demo.xls")
+#    mexcel.save_data(u"测试",[u"事件类型"],[[u"漏洞事件"]])
+

+ 13 - 0
src/utils/imagetool.py

@@ -0,0 +1,13 @@
+#-*-coding:utf-8 -*-
+import os
+from PIL import Image
+
+def thumbnail_pic(fpath):
+    """
+    """
+    im=Image.open(fpath)
+    im.thumbnail((240,240))
+    thumb_name = os.path.splitext(fpath)[0]+"_thumb"+os.path.splitext(fpath)[-1]
+    im.save(thumb_name,'JPEG')
+    return thumb_name
+

+ 26 - 0
src/utils/jgpush.py

@@ -0,0 +1,26 @@
+#-*-coding:utf-8 -*-
+import jpush
+app_key = "6aba55e8e8dacb49a5290b6e"
+master_secret = "257f2f6f8aa62add95accd86"
+_jpush = jpush.JPush(app_key, master_secret)
+_jpush.set_logging("DEBUG")
+push = _jpush.create_push()
+
+def send_notification_by_registration_ids(regids=["171976fa8a0d3dd7c0b"],msg="测试",title=None):
+    """给指定regid发送消息
+    """
+    push.platform = jpush.all_
+    android_msg = jpush.android(alert=msg,title=title)
+    ios_msg = jpush.ios(alert={"title":title,"body":msg}, badge="+1", sound=None, extras={'k1':'v1'})
+    push.notification = jpush.notification(alert=msg,android=android_msg,ios=ios_msg)
+    push.options = {"time_to_live":86400, "sendno":12345,"apns_production":False}
+    push.audience = jpush.audience(
+        jpush.registration_id(*regids)
+    )
+    response = push.send()
+    print response
+    return response
+
+if __name__ == "__main__":
+    send_notification_by_registration_ids()
+

+ 0 - 0
src/utils/qrcodetool.py


Some files were not shown because too many files changed in this diff