From cce10d39ea011126ffac9b890ff2f1e477a6d550 Mon Sep 17 00:00:00 2001
From: pycook <pycook@126.com>
Date: Thu, 7 Nov 2019 19:17:10 +0800
Subject: [PATCH] code format

---
 api/app.py                         |  8 +--
 api/commands/common.py             |  2 +-
 api/extensions.py                  |  4 +-
 api/flask_cas/__init__.py          |  2 +-
 api/flask_cas/cas_urls.py          |  6 +-
 api/flask_cas/routing.py           | 10 ++-
 api/lib/cmdb/attribute.py          | 11 ++--
 api/lib/cmdb/cache.py              | 86 +++++++++++++++-----------
 api/lib/cmdb/ci.py                 | 12 ++--
 api/lib/cmdb/ci_type.py            | 27 ++++----
 api/lib/cmdb/const.py              | 17 +++---
 api/lib/cmdb/history.py            | 15 ++---
 api/lib/cmdb/preference.py         | 11 ++--
 api/lib/cmdb/search.py             |  2 +-
 api/lib/cmdb/value.py              | 17 +++---
 api/lib/http_cli.py                |  4 +-
 api/lib/mail.py                    | 30 ++++-----
 api/lib/perm/{ => acl}/acl.py      |  0
 api/lib/perm/auth.py               |  6 +-
 api/lib/utils.py                   | 10 +--
 api/models/__init__.py             |  1 +
 api/models/account.py              | 98 ++++++------------------------
 api/models/cmdb.py                 | 16 ++---
 api/tasks/test.py                  |  3 +-
 api/views/account.py               |  6 +-
 api/views/cmdb/attribute.py        | 13 ++--
 api/views/cmdb/ci.py               |  4 +-
 api/views/cmdb/ci_type.py          | 14 ++---
 api/views/cmdb/ci_type_relation.py |  4 +-
 api/views/cmdb/preference.py       |  7 +--
 api/views/cmdb/relation_type.py    |  8 +--
 api/views/permission.py            |  4 +-
 32 files changed, 205 insertions(+), 253 deletions(-)
 rename api/lib/perm/{ => acl}/acl.py (100%)

diff --git a/api/app.py b/api/app.py
index a63f3bf..1774f0d 100644
--- a/api/app.py
+++ b/api/app.py
@@ -1,10 +1,10 @@
 # -*- coding: utf-8 -*-
 """The app module, containing the app factory function."""
+import logging
 import os
 import sys
-import logging
-from logging.handlers import RotatingFileHandler
 from inspect import getmembers
+from logging.handlers import RotatingFileHandler
 
 from flask import Flask
 from flask import make_response, jsonify
@@ -12,8 +12,6 @@ from flask.blueprints import Blueprint
 from flask.cli import click
 
 import api.views
-from api.models.account import User
-from api.flask_cas import CAS
 from api.extensions import (
     bcrypt,
     cors,
@@ -24,6 +22,8 @@ from api.extensions import (
     celery,
     rd,
 )
+from api.flask_cas import CAS
+from api.models.account import User
 
 HERE = os.path.abspath(os.path.dirname(__file__))
 PROJECT_ROOT = os.path.join(HERE, os.pardir)
diff --git a/api/commands/common.py b/api/commands/common.py
index 1abe98b..526543f 100644
--- a/api/commands/common.py
+++ b/api/commands/common.py
@@ -110,7 +110,7 @@ def urls(url, order):
             column_length = 1
     else:
         rules = sorted(
-            current_app.url_map.iter_rules(), key=lambda rule: getattr(rule, order)
+            current_app.url_map.iter_rules(), key=lambda x: getattr(x, order)
         )
         for rule in rules:
             rows.append((rule.rule, rule.endpoint, None))
diff --git a/api/extensions.py b/api/extensions.py
index 02706db..bec8ea6 100644
--- a/api/extensions.py
+++ b/api/extensions.py
@@ -1,13 +1,13 @@
 # -*- coding:utf-8 -*-
 
 
+from celery import Celery
 from flask_bcrypt import Bcrypt
 from flask_caching import Cache
+from flask_cors import CORS
 from flask_login import LoginManager
 from flask_migrate import Migrate
 from flask_sqlalchemy import SQLAlchemy
-from flask_cors import CORS
-from celery import Celery
 
 from api.lib.utils import RedisHandler
 
diff --git a/api/flask_cas/__init__.py b/api/flask_cas/__init__.py
index dc31cf5..70dc5fe 100644
--- a/api/flask_cas/__init__.py
+++ b/api/flask_cas/__init__.py
@@ -75,4 +75,4 @@ class CAS(object):
     @property
     def token(self):
         return flask.session.get(
-            self.app.config['CAS_TOKEN_SESSION_KEY'], None)
\ No newline at end of file
+            self.app.config['CAS_TOKEN_SESSION_KEY'], None)
diff --git a/api/flask_cas/cas_urls.py b/api/flask_cas/cas_urls.py
index 34e15d3..6d460eb 100644
--- a/api/flask_cas/cas_urls.py
+++ b/api/flask_cas/cas_urls.py
@@ -68,7 +68,7 @@ def create_cas_login_url(cas_url, cas_route, service,
         ('service', service),
         ('renew', renew),
         ('gateway', gateway),
-        )
+    )
 
 
 def create_cas_logout_url(cas_url, cas_route, url=None):
@@ -91,7 +91,7 @@ def create_cas_logout_url(cas_url, cas_route, url=None):
         cas_url,
         cas_route,
         ('service', url),
-        )
+    )
 
 
 def create_cas_validate_url(cas_url, cas_route, service, ticket,
@@ -119,4 +119,4 @@ def create_cas_validate_url(cas_url, cas_route, service, ticket,
         ('service', service),
         ('ticket', ticket),
         ('renew', renew),
-        )
\ No newline at end of file
+    )
diff --git a/api/flask_cas/routing.py b/api/flask_cas/routing.py
index e726f32..41c0086 100644
--- a/api/flask_cas/routing.py
+++ b/api/flask_cas/routing.py
@@ -3,18 +3,16 @@
 import json
 
 import bs4
+from flask import Blueprint
+from flask import current_app, session, request, url_for, redirect
+from flask_login import login_user, logout_user
 from six.moves.urllib_request import urlopen
 
-from flask import Blueprint
-from flask_login import login_user, logout_user
-from flask import current_app, session, request, url_for, redirect
-
+from api.models.account import UserCache
 from .cas_urls import create_cas_login_url
 from .cas_urls import create_cas_logout_url
 from .cas_urls import create_cas_validate_url
 
-from api.models.account import UserCache
-
 blueprint = Blueprint('cas', __name__)
 
 
diff --git a/api/lib/cmdb/attribute.py b/api/lib/cmdb/attribute.py
index efe235c..82bce55 100644
--- a/api/lib/cmdb/attribute.py
+++ b/api/lib/cmdb/attribute.py
@@ -1,15 +1,15 @@
 # -*- coding:utf-8 -*- 
 
-from flask import current_app
 from flask import abort
+from flask import current_app
 
 from api.extensions import db
-from api.models.cmdb import Attribute
-from api.models.cmdb import CITypeAttribute
-from api.models.cmdb import PreferenceShowAttributes
 from api.lib.cmdb.cache import AttributeCache
 from api.lib.cmdb.const import type_map
 from api.lib.decorator import kwargs_required
+from api.models.cmdb import Attribute
+from api.models.cmdb import CITypeAttribute
+from api.models.cmdb import PreferenceShowAttributes
 
 
 class AttributeManager(object):
@@ -97,7 +97,8 @@ class AttributeManager(object):
         alias = kwargs.pop("alias", "")
         alias = name if not alias else alias
         Attribute.get_by(name=name, first=True) and abort(400, "attribute name <{0}> is already existed".format(name))
-        Attribute.get_by(alias=alias, first=True) and abort(400, "attribute alias <{0}> is already existed".format(name))
+        Attribute.get_by(alias=alias, first=True) and abort(400,
+                                                            "attribute alias <{0}> is already existed".format(name))
 
         attr = Attribute.create(flush=True,
                                 name=name,
diff --git a/api/lib/cmdb/cache.py b/api/lib/cmdb/cache.py
index 629463e..45a6ee2 100644
--- a/api/lib/cmdb/cache.py
+++ b/api/lib/cmdb/cache.py
@@ -10,73 +10,84 @@ from api.models.cmdb import RelationType
 
 
 class AttributeCache(object):
+    PREFIX_ID = 'Field::ID::{0}'
+    PREFIX_NAME = 'Field::Name::{0}'
+    PREFIX_ALIAS = 'Field::Alias::{0}'
+
     @classmethod
     def get(cls, key):
         if key is None:
             return
-        attr = cache.get('Field::Name::{0}'.format(key)) \
-            or cache.get('Field::ID::{0}'.format(key)) \
-            or cache.get('Field::Alias::{0}'.format(key))
+        attr = cache.get(cls.PREFIX_NAME.format(key))
+        attr = attr or cache.get(cls.PREFIX_ID.format(key))
+        attr = attr or cache.get(cls.PREFIX_ALIAS.format(key))
 
         if attr is None:
-            attr = Attribute.get_by(name=key, first=True, to_dict=False) \
-                   or Attribute.get_by_id(key) \
-                   or Attribute.get_by(alias=key, first=True, to_dict=False)
+            attr = Attribute.get_by(name=key, first=True, to_dict=False)
+            attr = attr or Attribute.get_by_id(key)
+            attr = attr or Attribute.get_by(alias=key, first=True, to_dict=False)
             if attr is not None:
                 cls.set(attr)
         return attr
 
     @classmethod
     def set(cls, attr):
-        cache.set('Field::ID::{0}'.format(attr.id), attr)
-        cache.set('Field::Name::{0}'.format(attr.name), attr)
-        cache.set('Field::Alias::{0}'.format(attr.alias), attr)
+        cache.set(cls.PREFIX_ID.format(attr.id), attr)
+        cache.set(cls.PREFIX_NAME.format(attr.name), attr)
+        cache.set(cls.PREFIX_ALIAS.format(attr.alias), attr)
 
     @classmethod
     def clean(cls, attr):
-        cache.delete('Field::ID::{0}'.format(attr.id))
-        cache.delete('Field::Name::{0}'.format(attr.name))
-        cache.delete('Field::Alias::{0}'.format(attr.alias))
+        cache.delete(cls.PREFIX_ID.format(attr.id))
+        cache.delete(cls.PREFIX_NAME.format(attr.name))
+        cache.delete(cls.PREFIX_ALIAS.format(attr.alias))
 
 
 class CITypeCache(object):
+    PREFIX_ID = "CIType::ID::{0}"
+    PREFIX_NAME = "CIType::Name::{0}"
+    PREFIX_ALIAS = "CIType::Alias::{0}"
+
     @classmethod
     def get(cls, key):
         if key is None:
             return
-        ct = cache.get("CIType::ID::{0}".format(key)) or \
-            cache.get("CIType::Name::{0}".format(key)) or \
-            cache.get("CIType::Alias::{0}".format(key))
+        ct = cache.get(cls.PREFIX_NAME.format(key))
+        ct = ct or cache.get(cls.PREFIX_ID.format(key))
+        ct = ct or cache.get(cls.PREFIX_ALIAS.format(key))
         if ct is None:
-            ct = CIType.get_by(name=key, first=True, to_dict=False) or \
-                 CIType.get_by_id(key) or \
-                 CIType.get_by(alias=key, first=True, to_dict=False)
+            ct = CIType.get_by(name=key, first=True, to_dict=False)
+            ct = ct or CIType.get_by_id(key)
+            ct = ct or CIType.get_by(alias=key, first=True, to_dict=False)
             if ct is not None:
                 cls.set(ct)
         return ct
 
     @classmethod
     def set(cls, ct):
-        cache.set("CIType::Name::{0}".format(ct.name), ct)
-        cache.set("CIType::ID::{0}".format(ct.id), ct)
-        cache.set("CIType::Alias::{0}".format(ct.alias), ct)
+        cache.set(cls.PREFIX_NAME.format(ct.name), ct)
+        cache.set(cls.PREFIX_ID.format(ct.id), ct)
+        cache.set(cls.PREFIX_ALIAS.format(ct.alias), ct)
 
     @classmethod
     def clean(cls, key):
         ct = cls.get(key)
         if ct is not None:
-            cache.delete("CIType::Name::{0}".format(ct.name))
-            cache.delete("CIType::ID::{0}".format(ct.id))
-            cache.delete("CIType::Alias::{0}".format(ct.alias))
+            cache.delete(cls.PREFIX_NAME.format(ct.name))
+            cache.delete(cls.PREFIX_ID.format(ct.id))
+            cache.delete(cls.PREFIX_ALIAS.format(ct.alias))
 
 
 class RelationTypeCache(object):
+    PREFIX_ID = "RelationType::ID::{0}"
+    PREFIX_NAME = "RelationType::Name::{0}"
+
     @classmethod
     def get(cls, key):
         if key is None:
             return
-        ct = cache.get("RelationType::ID::{0}".format(key)) or \
-            cache.get("RelationType::Name::{0}".format(key))
+        ct = cache.get(cls.PREFIX_NAME.format(key))
+        ct = ct or cache.get(cls.PREFIX_ID.format(key))
         if ct is None:
             ct = RelationType.get_by(name=key, first=True, to_dict=False) or RelationType.get_by_id(key)
             if ct is not None:
@@ -85,15 +96,15 @@ class RelationTypeCache(object):
 
     @classmethod
     def set(cls, ct):
-        cache.set("RelationType::Name::{0}".format(ct.name), ct)
-        cache.set("RelationType::ID::{0}".format(ct.id), ct)
+        cache.set(cls.PREFIX_NAME.format(ct.name), ct)
+        cache.set(cls.PREFIX_ID.format(ct.id), ct)
 
     @classmethod
     def clean(cls, key):
         ct = cls.get(key)
         if ct is not None:
-            cache.delete("RelationType::Name::{0}".format(ct.name))
-            cache.delete("RelationType::ID::{0}".format(ct.id))
+            cache.delete(cls.PREFIX_NAME.format(ct.name))
+            cache.delete(cls.PREFIX_ID.format(ct.id))
 
 
 class CITypeAttributeCache(object):
@@ -101,13 +112,16 @@ class CITypeAttributeCache(object):
     key is type_id or type_name
     """
 
+    PREFIX_ID = "CITypeAttribute::ID::{0}"
+    PREFIX_NAME = "CITypeAttribute::Name::{0}"
+
     @classmethod
     def get(cls, key):
         if key is None:
             return
 
-        attrs = cache.get("CITypeAttribute::Name::{0}".format(key)) \
-            or cache.get("CITypeAttribute::ID::{0}".format(key))
+        attrs = cache.get(cls.PREFIX_NAME.format(key))
+        attrs = attrs or cache.get(cls.PREFIX_ID.format(key))
         if not attrs:
             attrs = CITypeAttribute.get_by(type_id=key, to_dict=False)
             if not attrs:
@@ -122,13 +136,13 @@ class CITypeAttributeCache(object):
     def set(cls, key, values):
         ci_type = CITypeCache.get(key)
         if ci_type is not None:
-            cache.set("CITypeAttribute::ID::{0}".format(ci_type.id), values)
-            cache.set("CITypeAttribute::Name::{0}".format(ci_type.name), values)
+            cache.set(cls.PREFIX_ID.format(ci_type.id), values)
+            cache.set(cls.PREFIX_NAME.format(ci_type.name), values)
 
     @classmethod
     def clean(cls, key):
         ci_type = CITypeCache.get(key)
         attrs = cls.get(key)
         if attrs is not None and ci_type:
-            cache.delete("CITypeAttribute::ID::{0}".format(ci_type.id))
-            cache.delete("CITypeAttribute::Name::{0}".format(ci_type.name))
+            cache.delete(cls.PREFIX_ID.format(ci_type.id))
+            cache.delete(cls.PREFIX_NAME.format(ci_type.name))
diff --git a/api/lib/cmdb/ci.py b/api/lib/cmdb/ci.py
index e62e675..ffaabdb 100644
--- a/api/lib/cmdb/ci.py
+++ b/api/lib/cmdb/ci.py
@@ -167,10 +167,10 @@ class CIManager(object):
 
         unique_key = AttributeCache.get(ci_type.unique_id) or abort(400, 'illegality unique attribute')
 
-        unique_value = ci_dict.get(unique_key.name) or \
-            ci_dict.get(unique_key.alias) or \
-            ci_dict.get(unique_key.id) or \
-            abort(400, '{0} missing'.format(unique_key.name))
+        unique_value = ci_dict.get(unique_key.name)
+        unique_value = unique_value or ci_dict.get(unique_key.alias)
+        unique_value = unique_value or ci_dict.get(unique_key.id)
+        unique_value = unique_value or abort(400, '{0} missing'.format(unique_key.name))
 
         existed = cls.ci_is_exist(unique_key, unique_value)
         if existed is not None:
@@ -425,8 +425,8 @@ class CIRelationManager(object):
 
     def get_second_cis(self, first_ci_id, relation_type_id=None, page=1, per_page=None, **kwargs):
         second_cis = db.session.query(CI.id).filter(CI.deleted.is_(False)).join(
-                CIRelation, CIRelation.second_ci_id == CI.id).filter(
-                    CIRelation.first_ci_id == first_ci_id)
+            CIRelation, CIRelation.second_ci_id == CI.id).filter(
+            CIRelation.first_ci_id == first_ci_id)
 
         if relation_type_id is not None:
             second_cis = second_cis.filter(CIRelation.relation_type_id == relation_type_id)
diff --git a/api/lib/cmdb/ci_type.py b/api/lib/cmdb/ci_type.py
index c4b2b23..f0b4e29 100644
--- a/api/lib/cmdb/ci_type.py
+++ b/api/lib/cmdb/ci_type.py
@@ -1,21 +1,21 @@
 # -*- coding:utf-8 -*- 
 
 
-from flask import current_app
 from flask import abort
+from flask import current_app
 
-from api.models.cmdb import CITypeAttribute
-from api.models.cmdb import CIType
-from api.models.cmdb import CITypeGroup
-from api.models.cmdb import CITypeGroupItem
-from api.models.cmdb import CITypeRelation
-from api.models.cmdb import CITypeAttributeGroup
-from api.models.cmdb import CITypeAttributeGroupItem
+from api.lib.cmdb.attribute import AttributeManager
 from api.lib.cmdb.cache import AttributeCache
 from api.lib.cmdb.cache import CITypeAttributeCache
 from api.lib.cmdb.cache import CITypeCache
-from api.lib.cmdb.attribute import AttributeManager
 from api.lib.decorator import kwargs_required
+from api.models.cmdb import CIType
+from api.models.cmdb import CITypeAttribute
+from api.models.cmdb import CITypeAttributeGroup
+from api.models.cmdb import CITypeAttributeGroupItem
+from api.models.cmdb import CITypeGroup
+from api.models.cmdb import CITypeGroupItem
+from api.models.cmdb import CITypeRelation
 
 
 class CITypeManager(object):
@@ -54,8 +54,7 @@ class CITypeManager(object):
         unique_key = kwargs.pop("unique_key", None)
         unique_key = AttributeCache.get(unique_key) or abort(404, "Unique key is not defined")
 
-        CIType.get_by(name=kwargs['name'], first=True) and \
-            abort(404, "CIType <{0}> is already existed".format(kwargs.get("name")))
+        CIType.get_by(name=kwargs['name']) and abort(404, "CIType <{0}> is already existed".format(kwargs.get("name")))
 
         kwargs["alias"] = kwargs["name"] if not kwargs.get("alias") else kwargs["alias"]
 
@@ -349,8 +348,8 @@ class CITypeAttributeGroupManager(object):
         :param attr_order:
         :return:
         """
-        existed = CITypeAttributeGroup.get_by(type_id=type_id, name=name, first=True, to_dict=False) \
-            or CITypeAttributeGroup.create(type_id=type_id, name=name, order=group_order)
+        existed = CITypeAttributeGroup.get_by(type_id=type_id, name=name, first=True, to_dict=False)
+        existed = existed or CITypeAttributeGroup.create(type_id=type_id, name=name, order=group_order)
         existed.update(order=group_order)
         attr_order = dict(attr_order)
         current_app.logger.info(attr_order)
@@ -382,7 +381,7 @@ class CITypeAttributeGroupManager(object):
     @staticmethod
     def delete(group_id):
         group = CITypeAttributeGroup.get_by_id(group_id) \
-            or abort(404, "AttributeGroup <{0}> does not exist".format(group_id))
+                or abort(404, "AttributeGroup <{0}> does not exist".format(group_id))
         group.soft_delete()
 
         items = CITypeAttributeGroupItem.get_by(group_id=group_id, to_dict=False)
diff --git a/api/lib/cmdb/const.py b/api/lib/cmdb/const.py
index f8bcbc3..a55d665 100644
--- a/api/lib/cmdb/const.py
+++ b/api/lib/cmdb/const.py
@@ -5,19 +5,19 @@ import datetime
 import six
 from markupsafe import escape
 
+from api.lib.cmdb.cache import AttributeCache
 from api.models.cmdb import Attribute
-from api.models.cmdb import TextChoice
-from api.models.cmdb import FloatChoice
-from api.models.cmdb import IntegerChoice
-from api.models.cmdb import CIValueText
-from api.models.cmdb import CIValueInteger
-from api.models.cmdb import CIValueFloat
-from api.models.cmdb import CIValueDateTime
 from api.models.cmdb import CIIndexValueDateTime
 from api.models.cmdb import CIIndexValueFloat
 from api.models.cmdb import CIIndexValueInteger
 from api.models.cmdb import CIIndexValueText
-from api.lib.cmdb.cache import AttributeCache
+from api.models.cmdb import CIValueDateTime
+from api.models.cmdb import CIValueFloat
+from api.models.cmdb import CIValueInteger
+from api.models.cmdb import CIValueText
+from api.models.cmdb import FloatChoice
+from api.models.cmdb import IntegerChoice
+from api.models.cmdb import TextChoice
 
 
 def string2int(x):
@@ -144,5 +144,6 @@ class PermEnum(object):
 class RoleEnum(object):
     CONFIG = "admin"
 
+
 CMDB_QUEUE = "cmdb_async"
 REDIS_PREFIX = "CMDB_CI"
diff --git a/api/lib/cmdb/history.py b/api/lib/cmdb/history.py
index 2116370..ed2ba6f 100644
--- a/api/lib/cmdb/history.py
+++ b/api/lib/cmdb/history.py
@@ -1,22 +1,20 @@
 # -*- coding:utf-8 -*- 
 
 
-from flask import g
 from flask import abort
-
+from flask import g
 
 from api.extensions import db
-from api.models.cmdb import Attribute
-from api.models.cmdb import OperationRecord
-from api.models.cmdb import AttributeHistory
-from api.models.cmdb import CIRelationHistory
-from api.models.account import UserCache
 from api.lib.cmdb.cache import AttributeCache
 from api.lib.cmdb.cache import RelationTypeCache
+from api.models.account import UserCache
+from api.models.cmdb import Attribute
+from api.models.cmdb import AttributeHistory
+from api.models.cmdb import CIRelationHistory
+from api.models.cmdb import OperationRecord
 
 
 class AttributeHistoryManger(object):
-
     @staticmethod
     def get_records(start, end, username, page, page_size):
         records = db.session.query(OperationRecord).filter(OperationRecord.deleted.is_(False))
@@ -113,7 +111,6 @@ class AttributeHistoryManger(object):
 
 
 class CIRelationHistoryManager(object):
-
     @staticmethod
     def add(rel_obj, operate_type=CIRelationHistory.ADD):
         record = OperationRecord.create(uid=g.user.uid)
diff --git a/api/lib/cmdb/preference.py b/api/lib/cmdb/preference.py
index 0fabe64..ae18acd 100644
--- a/api/lib/cmdb/preference.py
+++ b/api/lib/cmdb/preference.py
@@ -2,22 +2,21 @@
 
 import six
 import toposort
-from flask import g
 from flask import abort
+from flask import g
 
 from api.extensions import db
+from api.lib.cmdb.attribute import AttributeManager
 from api.lib.cmdb.cache import AttributeCache
-from api.lib.cmdb.cache import CITypeCache
 from api.lib.cmdb.cache import CITypeAttributeCache
+from api.lib.cmdb.cache import CITypeCache
+from api.models.cmdb import CITypeAttribute
+from api.models.cmdb import PreferenceRelationView
 from api.models.cmdb import PreferenceShowAttributes
 from api.models.cmdb import PreferenceTreeView
-from api.models.cmdb import PreferenceRelationView
-from api.models.cmdb import CITypeAttribute
-from api.lib.cmdb.attribute import AttributeManager
 
 
 class PreferenceManager(object):
-
     @staticmethod
     def get_types(instance=False, tree=False):
         types = db.session.query(PreferenceShowAttributes.type_id).filter(
diff --git a/api/lib/cmdb/search.py b/api/lib/cmdb/search.py
index df46d9f..3f3a12c 100644
--- a/api/lib/cmdb/search.py
+++ b/api/lib/cmdb/search.py
@@ -8,7 +8,6 @@ import time
 from flask import current_app
 
 from api.extensions import db
-from api.lib.utils import handle_arg_list
 from api.lib.cmdb.cache import AttributeCache
 from api.lib.cmdb.cache import CITypeCache
 from api.lib.cmdb.ci import CIManager
@@ -17,6 +16,7 @@ from api.lib.cmdb.const import TableMap
 from api.lib.cmdb.query_sql import FACET_QUERY
 from api.lib.cmdb.query_sql import QUERY_CI_BY_ATTR_NAME
 from api.lib.cmdb.query_sql import QUERY_CI_BY_TYPE
+from api.lib.utils import handle_arg_list
 from api.models.cmdb import Attribute
 from api.models.cmdb import CI
 
diff --git a/api/lib/cmdb/value.py b/api/lib/cmdb/value.py
index af16f39..c320644 100644
--- a/api/lib/cmdb/value.py
+++ b/api/lib/cmdb/value.py
@@ -2,18 +2,17 @@
 
 
 import markupsafe
-
 from flask import abort
 
 from api.extensions import db
-from api.lib.utils import handle_arg_list
-from api.lib.cmdb.cache import AttributeCache
 from api.lib.cmdb.attribute import AttributeManager
-from api.lib.cmdb.const import type_map
-from api.lib.cmdb.const import TableMap
+from api.lib.cmdb.cache import AttributeCache
 from api.lib.cmdb.const import ExistPolicy
 from api.lib.cmdb.const import OperateType
+from api.lib.cmdb.const import TableMap
+from api.lib.cmdb.const import type_map
 from api.lib.cmdb.history import AttributeHistoryManger
+from api.lib.utils import handle_arg_list
 from api.models.cmdb import Attribute
 
 
@@ -87,10 +86,10 @@ class AttributeValueManager(object):
 
     @staticmethod
     def __check_is_unique(value_table, attr_id, ci_id, value):
-        db.session.query(value_table.attr_id).filter(
+        existed = db.session.query(value_table.attr_id).filter(
             value_table.attr_id == attr_id).filter(value_table.deleted.is_(False)).filter(
-            value_table.value == value).filter(value_table.ci_id != ci_id).first() \
-            and abort(400, "attribute <{0}> value {1} must be unique".format(attr_id, value))
+            value_table.value == value).filter(value_table.ci_id != ci_id).first()
+        existed and abort(400, "attribute <{0}> value {1} must be unique".format(attr_id, value))
 
     def _validate(self, attr, value, value_table, ci_id):
         v = self.__deserialize_value(attr.value_type, value)
@@ -131,7 +130,7 @@ class AttributeValueManager(object):
         value_list = handle_arg_list(value) if attr.is_list else [value]
         if not isinstance(value, list):
             value_list = [value]
-        
+
         for v in value_list:
             v = self._validate(attr, v, value_table, ci_id)
             if not v and attr.value_type != Attribute.TEXT:
diff --git a/api/lib/http_cli.py b/api/lib/http_cli.py
index 6c59777..4d9e519 100644
--- a/api/lib/http_cli.py
+++ b/api/lib/http_cli.py
@@ -4,10 +4,10 @@
 import hashlib
 
 import requests
-from future.moves.urllib.parse import urlparse
 from flask import abort
-from flask import g
 from flask import current_app
+from flask import g
+from future.moves.urllib.parse import urlparse
 
 
 def build_api_key(path, params):
diff --git a/api/lib/mail.py b/api/lib/mail.py
index 0fbf25d..5c5c785 100644
--- a/api/lib/mail.py
+++ b/api/lib/mail.py
@@ -1,40 +1,40 @@
 # -*- coding:utf-8 -*- 
 
 
-from flask import current_app
-
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-from email.header import Header
-from email.mime.image import MIMEImage
 import smtplib
 import time
 from email import Utils
+from email.header import Header
+from email.mime.image import MIMEImage
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+
+from flask import current_app
 
 
 def send_mail(sender, receiver, subject, content, ctype="html", pics=()):
     """subject and body are unicode objects"""
     if not sender:
         sender = current_app.config.get("DEFAULT_MAIL_SENDER")
-    smtpserver = current_app.config.get("MAIL_SERVER")
+    smtp_server = current_app.config.get("MAIL_SERVER")
     if ctype == "html":
         msg = MIMEText(content, 'html', 'utf-8')
     else:
         msg = MIMEText(content, 'plain', 'utf-8')
 
     if len(pics) != 0:
-        msgRoot = MIMEMultipart('related')
-        msgText = MIMEText(content, 'html', 'utf-8')
-        msgRoot.attach(msgText)
+        msg_root = MIMEMultipart('related')
+        msg_text = MIMEText(content, 'html', 'utf-8')
+        msg_root.attach(msg_text)
         i = 1
         for pic in pics:
             fp = open(pic, "rb")
             image = MIMEImage(fp.read())
             fp.close()
             image.add_header('Content-ID', '<img%02d>' % i)
-            msgRoot.attach(image)
+            msg_root.attach(image)
             i += 1
-        msg = msgRoot
+        msg = msg_root
 
     msg['Subject'] = Header(subject, 'utf-8')
     msg['From'] = sender
@@ -43,7 +43,9 @@ def send_mail(sender, receiver, subject, content, ctype="html", pics=()):
     msg['date'] = time.strftime('%a, %d %b %Y %H:%M:%S %z')
 
     smtp = smtplib.SMTP()
-    smtp.connect(smtpserver, 25)
-    # smtp.login(username, password)
+    smtp.connect(smtp_server, 25)
+    username, password = current_app.config.get("MAIL_USERNAME"), current_app.config.get("MAIL_PASSWORD")
+    if username and password:
+        smtp.login(username, password)
     smtp.sendmail(sender, receiver, msg.as_string())
     smtp.quit()
diff --git a/api/lib/perm/acl.py b/api/lib/perm/acl/acl.py
similarity index 100%
rename from api/lib/perm/acl.py
rename to api/lib/perm/acl/acl.py
diff --git a/api/lib/perm/auth.py b/api/lib/perm/auth.py
index e1637f4..d28d3fa 100644
--- a/api/lib/perm/auth.py
+++ b/api/lib/perm/auth.py
@@ -4,11 +4,11 @@
 from functools import wraps
 
 import jwt
+from flask import abort
 from flask import current_app
+from flask import g
 from flask import request
 from flask import session
-from flask import g
-from flask import abort
 from flask_login import login_user
 
 from api.models.account import User
@@ -54,7 +54,7 @@ def _auth_with_token():
         return True
     except jwt.ExpiredSignatureError:
         return False
-    except (jwt.InvalidTokenError, Exception) as e:
+    except (jwt.InvalidTokenError, Exception):
         return False
 
 
diff --git a/api/lib/utils.py b/api/lib/utils.py
index dd00fb1..7031f84 100644
--- a/api/lib/utils.py
+++ b/api/lib/utils.py
@@ -1,7 +1,7 @@
 # -*- coding:utf-8 -*- 
 
-import six
 import redis
+import six
 from flask import current_app
 
 
@@ -52,7 +52,7 @@ class RedisHandler(object):
         try:
             value = self.r.hmget(self.prefix, key_ids)
         except Exception as e:
-            current_app.logger.error("get redis error, %s" % str(e))
+            current_app.logger.error("get redis error, {0}".format(str(e)))
             return
         return value
 
@@ -60,7 +60,7 @@ class RedisHandler(object):
         try:
             self.r.hmset(self.prefix, obj)
         except Exception as e:
-            current_app.logger.error("set redis error, %s" % str(e))
+            current_app.logger.error("set redis error, {0}".format(str(e)))
 
     def add(self, obj):
         self._set(obj)
@@ -69,6 +69,6 @@ class RedisHandler(object):
         try:
             ret = self.r.hdel(self.prefix, key_id)
             if not ret:
-                current_app.logger.warn("[%d] is not in redis" % key_id)
+                current_app.logger.warn("[%d] is not in redis".format(key_id))
         except Exception as e:
-            current_app.logger.error("delete redis key error, %s" % str(e))
+            current_app.logger.error("delete redis key error, {0}".format(str(e)))
diff --git a/api/models/__init__.py b/api/models/__init__.py
index fabbe66..c10c68e 100644
--- a/api/models/__init__.py
+++ b/api/models/__init__.py
@@ -3,3 +3,4 @@
 
 from .account import User
 from .cmdb import *
+from .acl import *
diff --git a/api/models/account.py b/api/models/account.py
index 15bb04c..4311bbd 100644
--- a/api/models/account.py
+++ b/api/models/account.py
@@ -4,16 +4,17 @@ import copy
 import hashlib
 from datetime import datetime
 
-import six
 from flask import current_app
 from flask_sqlalchemy import BaseQuery
 
-from api.extensions import db
 from api.extensions import cache
+from api.extensions import db
 from api.lib.database import CRUDModel
 
 
 class UserQuery(BaseQuery):
+    def _join(self, *args, **kwargs):
+        super(UserQuery, self)._join(*args, **kwargs)
 
     def authenticate(self, login, password):
         user = self.filter(db.or_(User.username == login,
@@ -60,9 +61,6 @@ class User(CRUDModel):
     __bind_key__ = "user"
     query_class = UserQuery
 
-    ADMIN = 1
-    OP = 2
-
     uid = db.Column(db.Integer, primary_key=True, autoincrement=True)
     username = db.Column(db.String(32), unique=True)
     nickname = db.Column(db.String(20), nullable=True)
@@ -79,6 +77,7 @@ class User(CRUDModel):
     has_logined = db.Column(db.Boolean, default=False)
     wx_id = db.Column(db.String(32))
     avatar = db.Column(db.String(128))
+    is_admin = db.Column(db.Boolean, default=False)
 
     def __str__(self):
         return self.username
@@ -108,91 +107,34 @@ class User(CRUDModel):
             return False
         return self.password == password
 
-    @property
-    def roles(self):
-        urs = db.session.query(UserRole.rid).filter(
-            UserRole.uid == self.uid).all()
-        return [x.rid for x in urs]
-
-    @property
-    def rolenames(self):
-        roles = list()
-        for rid in self.roles:
-            role = db.session.query(Role).filter(Role.rid == rid).first()
-            roles.append(role.role_name)
-        return roles
-
-    @property
-    def is_admin(self):
-        return self.ADMIN in self.roles
-
-
-class Role(CRUDModel):
-    __tablename__ = 'roles'
-    __bind_key__ = "user"
-
-    rid = db.Column(db.Integer, primary_key=True, autoincrement=True)
-    role_name = db.Column(db.String(64), nullable=False, unique=True)
-
-
-class UserRole(CRUDModel):
-    __tablename__ = 'users_roles'
-    __bind_key__ = "user"
-
-    uid = db.Column(db.Integer, db.ForeignKey('users.uid'), primary_key=True)
-    rid = db.Column(db.Integer, db.ForeignKey('roles.rid'), primary_key=True)
-
 
 class UserCache(object):
+    PREFIX_ID = "User::uid::{0}"
+    PREFIX_NAME = "User::username::{0}"
+    PREFIX_NICK = "User::nickname::{0}"
+
     @classmethod
     def get(cls, key):
-        user = cache.get("User::uid::%s" % key) or \
-            cache.get("User::username::%s" % key) or \
-            cache.get("User::nickname::%s" % key)
+        user = cache.get(cls.PREFIX_ID.format(key)) or \
+               cache.get(cls.PREFIX_NAME.format(key)) or \
+               cache.get(cls.PREFIX_NICK.format(key))
         if not user:
             user = User.query.get(key) or \
-                User.query.get_by_username(key) or \
-                User.query.get_by_nickname(key)
+                   User.query.get_by_username(key) or \
+                   User.query.get_by_nickname(key)
         if user:
             cls.set(user)
+
         return user
 
     @classmethod
     def set(cls, user):
-        cache.set("User::uid::%s" % user.uid, user)
-        cache.set("User::username::%s" % user.username, user)
-        cache.set("User::nickname::%s" % user.nickname, user)
+        cache.set(cls.PREFIX_ID.format(user.uid, user))
+        cache.set(cls.PREFIX_NAME.format(user.username, user))
+        cache.set(cls.PREFIX_NICK.format(user.nickname, user))
 
     @classmethod
     def clean(cls, user):
-        cache.delete("User::uid::%s" % user.uid)
-        cache.delete("User::username::%s" % user.username)
-        cache.delete("User::nickname::%s" % user.nickname)
-
-
-class RoleCache(object):
-    @classmethod
-    def get(cls, rid):
-        role = None
-        if isinstance(rid, six.integer_types):
-            role = cache.get("Role::rid::%s" % rid)
-            if not role:
-                role = db.session.query(Role).filter(Role.rid == rid).first()
-                cls.set(role)
-        elif isinstance(rid, six.string_types):
-            role = cache.get("Role::role_name::%s" % rid)
-            if not role:
-                role = db.session.query(Role).filter(
-                    Role.role_name == rid).first()
-                cls.set(role)
-        return role
-
-    @classmethod
-    def set(cls, role):
-        cache.set("Role::rid::%s" % role.rid, role)
-        cache.set("Role::role_name::%s" % role.role_name, role)
-
-    @classmethod
-    def clean(cls, role):
-        cache.delete("Role::rid::%s" % role.rid, role)
-        cache.delete("Role::role_name::%s" % role.role_name, role)
+        cache.delete(cls.PREFIX_ID.format(user.uid))
+        cache.delete(cls.PREFIX_NAME.format(user.username))
+        cache.delete(cls.PREFIX_NICK.format(user.nickname))
diff --git a/api/models/cmdb.py b/api/models/cmdb.py
index 37251c5..c9d4834 100644
--- a/api/models/cmdb.py
+++ b/api/models/cmdb.py
@@ -3,8 +3,8 @@
 
 import datetime
 
-from api.lib.database import Model
 from api.extensions import db
+from api.lib.database import Model
 
 
 # template
@@ -57,7 +57,7 @@ class CITypeRelation(Model):
 
 class Attribute(Model):
     __tablename__ = "c_attributes"
-    
+
     INT = "0"
     FLOAT = "1"
     TEXT = "2"
@@ -76,8 +76,8 @@ class Attribute(Model):
     is_link = db.Column(db.Boolean, default=False)
     is_password = db.Column(db.Boolean, default=False)
     is_sortable = db.Column(db.Boolean, default=False)
-    
-    
+
+
 class CITypeAttribute(Model):
     __tablename__ = "c_ci_type_attributes"
 
@@ -171,7 +171,7 @@ class CIIndexValueInteger(Model):
     ci = db.relationship("CI", backref="c_value_index_integers.ci_id")
     attr = db.relationship("Attribute", backref="c_value_index_integers.attr_id")
 
-    __table_args__ = (db.Index("integer_attr_value_index", "attr_id", "value"), )
+    __table_args__ = (db.Index("integer_attr_value_index", "attr_id", "value"),)
 
 
 class CIIndexValueFloat(Model):
@@ -184,7 +184,7 @@ class CIIndexValueFloat(Model):
     ci = db.relationship("CI", backref="c_value_index_floats.ci_id")
     attr = db.relationship("Attribute", backref="c_value_index_floats.attr_id")
 
-    __table_args__ = (db.Index("float_attr_value_index", "attr_id", "value"), )
+    __table_args__ = (db.Index("float_attr_value_index", "attr_id", "value"),)
 
 
 class CIIndexValueText(Model):
@@ -197,7 +197,7 @@ class CIIndexValueText(Model):
     ci = db.relationship("CI", backref="c_value_index_texts.ci_id")
     attr = db.relationship("Attribute", backref="c_value_index_texts.attr_id")
 
-    __table_args__ = (db.Index("text_attr_value_index", "attr_id", "value"), )
+    __table_args__ = (db.Index("text_attr_value_index", "attr_id", "value"),)
 
 
 class CIIndexValueDateTime(Model):
@@ -210,7 +210,7 @@ class CIIndexValueDateTime(Model):
     ci = db.relationship("CI", backref="c_value_index_datetime.ci_id")
     attr = db.relationship("Attribute", backref="c_value_index_datetime.attr_id")
 
-    __table_args__ = (db.Index("datetime_attr_value_index", "attr_id", "value"), )
+    __table_args__ = (db.Index("datetime_attr_value_index", "attr_id", "value"),)
 
 
 class CIValueInteger(Model):
diff --git a/api/tasks/test.py b/api/tasks/test.py
index a19d362..d920ad1 100644
--- a/api/tasks/test.py
+++ b/api/tasks/test.py
@@ -1,8 +1,9 @@
 # -*- coding:utf-8 -*-
 
-from api.extensions import celery
 from flask import current_app
 
+from api.extensions import celery
+
 
 @celery.task(queue="ticket_web")
 def test_task():
diff --git a/api/views/account.py b/api/views/account.py
index f6d7dbc..21cc2f1 100644
--- a/api/views/account.py
+++ b/api/views/account.py
@@ -3,15 +3,15 @@
 import datetime
 
 import jwt
-from flask import request
-from flask import current_app
 from flask import abort
+from flask import current_app
+from flask import request
 from flask_login import login_user, logout_user
 
-from api.resource import APIView
 from api.lib.decorator import args_required
 from api.lib.perm.auth import auth_abandoned
 from api.models.account import User
+from api.resource import APIView
 
 
 class LoginView(APIView):
diff --git a/api/views/cmdb/attribute.py b/api/views/cmdb/attribute.py
index b09e3df..8089aae 100644
--- a/api/views/cmdb/attribute.py
+++ b/api/views/cmdb/attribute.py
@@ -1,19 +1,18 @@
 # -*- coding:utf-8 -*- 
 
 
-from flask import request
 from flask import abort
 from flask import current_app
+from flask import request
 
-from api.resource import APIView
-from api.lib.perm.acl import role_required
-from api.lib.cmdb.const import RoleEnum
 from api.lib.cmdb.attribute import AttributeManager
+from api.lib.cmdb.const import RoleEnum
 from api.lib.decorator import args_required
-from api.lib.utils import handle_arg_list
+from api.lib.perm.acl.acl import role_required
 from api.lib.utils import get_page
 from api.lib.utils import get_page_size
-
+from api.lib.utils import handle_arg_list
+from api.resource import APIView
 
 
 class AttributeSearchView(APIView):
@@ -72,4 +71,4 @@ class AttributeView(APIView):
     @role_required(RoleEnum.CONFIG)
     def delete(self, attr_id):
         attr_name = AttributeManager.delete(attr_id)
-        return self. jsonify(message="attribute {0} deleted".format(attr_name))
+        return self.jsonify(message="attribute {0} deleted".format(attr_name))
diff --git a/api/views/cmdb/ci.py b/api/views/cmdb/ci.py
index 0f6bd16..210f86c 100644
--- a/api/views/cmdb/ci.py
+++ b/api/views/cmdb/ci.py
@@ -7,14 +7,14 @@ from flask import abort
 from flask import current_app
 from flask import request
 
-from api.lib.perm.acl import has_perm_from_args
-from api.lib.cmdb.const import ResourceType, PermEnum
 from api.lib.cmdb.cache import CITypeCache
 from api.lib.cmdb.ci import CIManager
 from api.lib.cmdb.const import ExistPolicy
+from api.lib.cmdb.const import ResourceType, PermEnum
 from api.lib.cmdb.const import RetKey
 from api.lib.cmdb.search import Search
 from api.lib.cmdb.search import SearchError
+from api.lib.perm.acl.acl import has_perm_from_args
 from api.lib.perm.auth import auth_abandoned
 from api.lib.utils import get_page
 from api.lib.utils import get_page_size
diff --git a/api/views/cmdb/ci_type.py b/api/views/cmdb/ci_type.py
index 14b6153..554655d 100644
--- a/api/views/cmdb/ci_type.py
+++ b/api/views/cmdb/ci_type.py
@@ -5,17 +5,17 @@ from flask import abort
 from flask import current_app
 from flask import request
 
-from api.resource import APIView
-from api.lib.perm.acl import role_required
-from api.lib.cmdb.const import RoleEnum
 from api.lib.cmdb.cache import AttributeCache
 from api.lib.cmdb.cache import CITypeCache
-from api.lib.cmdb.ci_type import CITypeAttributeManager
-from api.lib.cmdb.ci_type import CITypeManager
-from api.lib.cmdb.ci_type import CITypeGroupManager
 from api.lib.cmdb.ci_type import CITypeAttributeGroupManager
+from api.lib.cmdb.ci_type import CITypeAttributeManager
+from api.lib.cmdb.ci_type import CITypeGroupManager
+from api.lib.cmdb.ci_type import CITypeManager
+from api.lib.cmdb.const import RoleEnum
 from api.lib.decorator import args_required
+from api.lib.perm.acl.acl import role_required
 from api.lib.utils import handle_arg_list
+from api.resource import APIView
 
 
 class CITypeView(APIView):
@@ -128,7 +128,7 @@ class CITypeAttributeView(APIView):
     def post(self, type_id=None):
         attr_id_list = handle_arg_list(request.values.get("attr_id"))
         params = request.values
-        params.pop("attr_id",  "")
+        params.pop("attr_id", "")
 
         CITypeAttributeManager.add(type_id, attr_id_list, **params)
         return self.jsonify(attributes=attr_id_list)
diff --git a/api/views/cmdb/ci_type_relation.py b/api/views/cmdb/ci_type_relation.py
index 613d1ba..ead8ed2 100644
--- a/api/views/cmdb/ci_type_relation.py
+++ b/api/views/cmdb/ci_type_relation.py
@@ -3,10 +3,10 @@
 
 from flask import request
 
-from api.lib.perm.acl import role_required
-from api.lib.cmdb.const import RoleEnum
 from api.lib.cmdb.ci_type import CITypeRelationManager
+from api.lib.cmdb.const import RoleEnum
 from api.lib.decorator import args_required
+from api.lib.perm.acl.acl import role_required
 from api.resource import APIView
 
 
diff --git a/api/views/cmdb/preference.py b/api/views/cmdb/preference.py
index d09437f..e54b7d4 100644
--- a/api/views/cmdb/preference.py
+++ b/api/views/cmdb/preference.py
@@ -3,14 +3,13 @@
 
 from flask import request
 
-from api.resource import APIView
-from api.lib.perm.acl import has_perm_from_args
+from api.lib.cmdb.ci_type import CITypeManager
 from api.lib.cmdb.const import ResourceType, PermEnum
 from api.lib.cmdb.preference import PreferenceManager
-from api.lib.cmdb.ci import CIManager
-from api.lib.cmdb.ci_type import CITypeManager
 from api.lib.decorator import args_required
+from api.lib.perm.acl.acl import has_perm_from_args
 from api.lib.utils import handle_arg_list
+from api.resource import APIView
 
 
 class PreferenceShowCITypesView(APIView):
diff --git a/api/views/cmdb/relation_type.py b/api/views/cmdb/relation_type.py
index df96302..9ff310b 100644
--- a/api/views/cmdb/relation_type.py
+++ b/api/views/cmdb/relation_type.py
@@ -1,14 +1,14 @@
 # -*- coding:utf-8 -*-
 
 
-from flask import request
 from flask import abort
+from flask import request
 
-from api.resource import APIView
-from api.lib.perm.acl import role_required
 from api.lib.cmdb.const import RoleEnum
-from api.lib.decorator import args_required
 from api.lib.cmdb.relation_type import RelationTypeManager
+from api.lib.decorator import args_required
+from api.lib.perm.acl.acl import role_required
+from api.resource import APIView
 
 
 class RelationTypeView(APIView):
diff --git a/api/views/permission.py b/api/views/permission.py
index 70cb5b2..3eb67d8 100644
--- a/api/views/permission.py
+++ b/api/views/permission.py
@@ -5,8 +5,8 @@ from flask import session
 from flask_login import current_user
 
 from api.lib.decorator import args_required
-from api.lib.perm.acl import ACLManager
-from api.lib.perm.acl import validate_permission
+from api.lib.perm.acl.acl import ACLManager
+from api.lib.perm.acl.acl import validate_permission
 from api.resource import APIView