user.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # @Author: wushuiyong
  4. # @Created Time : 日 1/ 1 23:43:12 2017
  5. # @Description:
  6. from flask_login import UserMixin
  7. from sqlalchemy import String, Integer, DateTime, or_
  8. from werkzeug.security import check_password_hash, generate_password_hash
  9. # from flask_cache import Cache
  10. from datetime import datetime
  11. from walle.service.extensions import login_manager
  12. from walle.model.database import SurrogatePK, db, Model
  13. from walle.model.tag import TagModel
  14. from sqlalchemy.orm import aliased
  15. from walle.service.rbac.access import Access as AccessRbac
  16. from flask import current_app, session, abort
  17. from walle.service.rbac.role import *
  18. from walle.service.error import WalleError
  19. from flask_login import current_user as g
  20. from walle.service.extensions import permission
  21. import walle.model
  22. class UserModel(UserMixin, SurrogatePK, Model):
  23. # 表的名字:
  24. __tablename__ = 'users'
  25. status_active = 1
  26. status_blocked = 2
  27. current_time = datetime.now()
  28. password_hash = 'sadfsfkk'
  29. # 表的结构:
  30. id = db.Column(Integer, primary_key=True, autoincrement=True)
  31. username = db.Column(String(50))
  32. is_email_verified = db.Column(Integer, default=0)
  33. email = db.Column(String(50), unique=True, nullable=False)
  34. password = db.Column(String(50), nullable=False)
  35. avatar = db.Column(String(100))
  36. role = db.Column(String(10))
  37. status = db.Column(Integer, default=1)
  38. last_space = db.Column(Integer, default=0)
  39. # role_info = relationship("walle.model.user.RoleModel", back_populates="users")
  40. created_at = db.Column(DateTime, default=current_time)
  41. updated_at = db.Column(DateTime, default=current_time, onupdate=current_time)
  42. status_mapping = {
  43. -1: '删除',
  44. 0: '新建',
  45. 1: '正常',
  46. 2: '冻结',
  47. }
  48. '''
  49. current_user 基础方法
  50. "__abstract__",
  51. "__class__",
  52. "__delattr__",
  53. "__dict__",
  54. "__doc__",
  55. "__eq__",
  56. "__format__",
  57. "__getattribute__",
  58. "__hash__",
  59. "__init__",
  60. "__mapper__",
  61. "__module__",
  62. "__ne__",
  63. "__new__",
  64. "__reduce__",
  65. "__reduce_ex__",
  66. "__repr__",
  67. "__setattr__",
  68. "__sizeof__",
  69. "__str__",
  70. "__subclasshook__",
  71. "__table__",
  72. "__table_args__",
  73. "__tablename__",
  74. "__weakref__",
  75. "_cached_tablename",
  76. "_decl_class_registry",
  77. "_sa_class_manager",
  78. "_sa_instance_state",
  79. "avatar",
  80. "avatar_url",
  81. "block_active",
  82. "column_name_set",
  83. "create",
  84. "create_from_dict",
  85. "create_or_update",
  86. "created_at",
  87. "current_time",
  88. "delete",
  89. "dump_schema",
  90. "email",
  91. "enable",
  92. "fetch_access_list_by_role_id",
  93. "fetch_by_uid",
  94. "general_password",
  95. "get_by_id",
  96. "get_common_fields",
  97. "get_id",
  98. "id",
  99. "is_active",
  100. "is_anonymous",
  101. "is_authenticated",
  102. "is_email_verified",
  103. "item",
  104. "list",
  105. "metadata",
  106. "password",
  107. "password_hash",
  108. "query",
  109. "query_class",
  110. "query_paginate",
  111. "query_paginate_and_dump_schema",
  112. "remove",
  113. "save",
  114. "set_password",
  115. "status",
  116. "status_active",
  117. "status_available",
  118. "status_blocked",
  119. "status_default",
  120. "status_mapping",
  121. "status_remove",
  122. "to_dict",
  123. "to_json",
  124. "uid2name",
  125. "update",
  126. "update_avatar",
  127. "update_name_pwd",
  128. "updated_at",
  129. "username",
  130. "verify_password"
  131. '''
  132. def add(self, *args, **kwargs):
  133. data = dict(*args)
  134. user = UserModel(**data)
  135. db.session.add(user)
  136. db.session.commit()
  137. return user
  138. def item(self, user_id=None):
  139. """
  140. 获取单条记录
  141. :param role_id:
  142. :return:
  143. """
  144. data = self.query.filter_by(id=self.id).filter(UserModel.status.notin_([self.status_remove])).first()
  145. return data.to_json() if data else []
  146. def update(self, *args, **kwargs):
  147. # todo permission_ids need to be formated and checked
  148. # a new type to update a model
  149. update_data = dict(*args)
  150. return super(UserModel, self).update(**update_data)
  151. def update_avatar(self, avatar):
  152. d = {'avatar': avatar}
  153. user = self.query.get(self.id).update(**d)
  154. current_app.logger.info(user)
  155. def update_name_pwd(self, username, password=None):
  156. # todo permission_ids need to be formated and checked
  157. user = self.query.filter_by(id=self.id).first()
  158. user.username = username
  159. if password:
  160. self.set_password(password)
  161. db.session.commit()
  162. return user.to_json()
  163. def block_active(self, status):
  164. user = self.query.filter_by(id=self.id).first()
  165. user.status = status
  166. db.session.commit()
  167. return user.to_json()
  168. def remove(self):
  169. """
  170. :param role_id:
  171. :return:
  172. """
  173. self.query.filter_by(id=self.id).update({'status': self.status_remove})
  174. ret = db.session.commit()
  175. return ret
  176. def verify_password(self, password):
  177. """
  178. 检查密码是否正确
  179. :param password:
  180. :return:
  181. """
  182. if self.password is None:
  183. return False
  184. return check_password_hash(self.password, password)
  185. def set_password(self, password):
  186. """Set password."""
  187. self.password = generate_password_hash(password)
  188. def general_password(self, password):
  189. """
  190. 检查密码是否正确
  191. :param password:
  192. :return:
  193. """
  194. self.password = generate_password_hash(password)
  195. return generate_password_hash(password)
  196. def fetch_access_list_by_role_id(self, role_id):
  197. module = aliased(MenuModel)
  198. controller = aliased(MenuModel)
  199. action = aliased(MenuModel)
  200. role = RoleModel.query.get(role_id)
  201. access_ids = role.access_ids.split(',')
  202. data = db.session \
  203. .query(controller.name_en, controller.name_cn,
  204. action.name_en, action.name_cn) \
  205. .outerjoin(action, action.pid == controller.id) \
  206. .filter(module.type == MenuModel.type_module) \
  207. .filter(controller.id.in_(access_ids)) \
  208. .filter(action.id.in_(access_ids)) \
  209. .all()
  210. return [AccessRbac.resource(a_en, c_en) for c_en, c_cn, a_en, a_cn in data if c_en and a_en]
  211. def is_authenticated(self):
  212. return True
  213. def is_active(self):
  214. return True
  215. def is_anonymous(self):
  216. return False
  217. def get_id(self):
  218. try:
  219. return unicode(self.id) # python 2
  220. except NameError:
  221. return str(self.id) # python 3
  222. def list(self, uids=[], page=0, size=10, kw=None):
  223. """
  224. 获取分页列表
  225. :param page:
  226. :param size:
  227. :return:
  228. """
  229. query = UserModel.query.filter(UserModel.status.notin_([self.status_remove]))
  230. if kw:
  231. query = query.filter(or_(UserModel.username.like('%' + kw + '%'), UserModel.email.like('%' + kw + '%')))
  232. if uids:
  233. query = query.filter(UserModel.id.in_(uids))
  234. count = query.count()
  235. data = query.order_by('id desc').offset(int(size) * int(page)).limit(size).all()
  236. user_list = [p.to_json() for p in data]
  237. return user_list, count
  238. def has_spaces(self):
  239. return MemberModel().spaces(user_id=self.id)
  240. @classmethod
  241. def fresh_session(cls):
  242. spaces = current_user.has_spaces()
  243. # 1.无空间权限
  244. if not spaces:
  245. raise WalleError(Code.space_empty)
  246. default_space = spaces.keys()[0]
  247. # 2.第一次登录无空间
  248. if not current_user.last_space:
  249. current_user.last_space = default_space
  250. current_user.save()
  251. session['space_id'] = default_space
  252. session['space_info'] = spaces[session['space_id']]
  253. # 3.空间权限有修改
  254. if current_user.last_space and current_user.last_space not in spaces.keys():
  255. raise WalleError(Code.space_error)
  256. session['space_id'] = current_user.last_space
  257. session['space_info'] = spaces[current_user.last_space]
  258. session['space_list'] = spaces.values()
  259. current_app.logger.info('============ SecurityResource.__init__ ============')
  260. @classmethod
  261. def avatar_url(cls, avatar):
  262. avatar = avatar if avatar else 'default.jpg'
  263. return '/' + current_app.config['AVATAR_PATH'] + avatar
  264. @classmethod
  265. def fetch_by_uid(cls, uids=None):
  266. """
  267. 用户列表
  268. :param uids: []
  269. :return:
  270. """
  271. if not uids:
  272. return []
  273. query = UserModel.query.filter(UserModel.id.in_(uids)).filter(UserModel.status.notin_([cls.status_remove]))
  274. data = query.order_by('id desc').all()
  275. return [p.to_json() for p in data]
  276. @classmethod
  277. def uid2name(cls, data):
  278. """
  279. 把uid转换成名字
  280. :param data: [{'user_id':1, 'xx':'yy'}] 至少包含user_id
  281. :return:
  282. """
  283. user_ids = []
  284. uid2name = {}
  285. for items in data:
  286. user_ids.append(items.user_id)
  287. user_info = cls.fetch_by_uid(uids=user_ids)
  288. for user in user_info:
  289. uid2name[user['id']] = user['username']
  290. return uid2name
  291. def to_json(self):
  292. item = {
  293. 'id': int(self.id),
  294. 'user_id': int(self.id),
  295. 'username': self.username,
  296. 'is_email_verified': self.is_email_verified,
  297. 'email': self.email,
  298. 'avatar': self.avatar_url(self.avatar),
  299. # TODO 当前登录用户的空间
  300. # 'role_id': self.role_id,
  301. 'status': self.status_mapping[self.status],
  302. 'last_space': self.last_space,
  303. # 'status': self.status,
  304. # 'role_name': self.role_id,
  305. 'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
  306. 'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S'),
  307. }
  308. item.update(self.enable())
  309. return item
  310. def enable(self):
  311. return {
  312. 'enable_update': permission.enable_role(DEVELOPER),
  313. 'enable_delete': permission.enable_role(DEVELOPER),
  314. 'enable_create': False,
  315. 'enable_online': False,
  316. 'enable_audit': False,
  317. 'enable_block': False,
  318. }
  319. class MenuModel(SurrogatePK, Model):
  320. __tablename__ = 'menus'
  321. type_module = 'module'
  322. type_controller = 'controller'
  323. type_action = 'action'
  324. status_open = 1
  325. status_close = 2
  326. current_time = datetime.now()
  327. # 表的结构:
  328. id = db.Column(Integer, primary_key=True, autoincrement=True)
  329. name_cn = db.Column(String(30))
  330. name_en = db.Column(String(30))
  331. pid = db.Column(Integer)
  332. type = db.Column(String(30))
  333. sequence = db.Column(Integer)
  334. archive = db.Column(Integer)
  335. icon = db.Column(String(30))
  336. url = db.Column(String(30))
  337. visible = db.Column(Integer)
  338. role = db.Column(Integer)
  339. created_at = db.Column(DateTime, default=current_time)
  340. updated_at = db.Column(DateTime, default=current_time, onupdate=current_time)
  341. def menu(self, role):
  342. data = {}
  343. filters = {
  344. MenuModel.visible == 1,
  345. MenuModel.role >= role
  346. }
  347. query = self.query \
  348. .filter(*filters) \
  349. .order_by('sequence asc') \
  350. .all()
  351. for item in query:
  352. if item.type == self.type_module:
  353. module = {
  354. 'title': item.name_cn,
  355. 'icon': item.icon,
  356. 'sub_menu': [],
  357. }
  358. if item.url:
  359. module['url'] = RoleModel.menu_url(item.url)
  360. data[item.id] = module
  361. elif item.type == self.type_controller:
  362. data[item.pid]['sub_menu'].append({
  363. 'title': item.name_cn,
  364. 'icon': item.icon,
  365. 'url': RoleModel.menu_url(item.url),
  366. })
  367. return data.values()
  368. def list(self):
  369. """
  370. 获取分页列表
  371. :param page:
  372. :param size:
  373. :param kw:
  374. :return:
  375. """
  376. menus_module = {}
  377. menus_controller = {}
  378. module = aliased(MenuModel)
  379. controller = aliased(MenuModel)
  380. action = aliased(MenuModel)
  381. data = db.session.query(module.id, module.name_cn, controller.id, controller.name_cn, action.id, action.name_cn) \
  382. .outerjoin(controller, controller.pid == module.id) \
  383. .outerjoin(action, action.pid == controller.id) \
  384. .filter(module.type == self.type_module) \
  385. .all()
  386. for m_id, m_name, c_id, c_name, a_id, a_name in data:
  387. # module
  388. if not menus_module.has_key(m_id):
  389. menus_module[m_id] = {
  390. 'id': m_id,
  391. 'title': m_name,
  392. 'sub_menu': {},
  393. }
  394. # controller
  395. if not menus_module[m_id]['sub_menu'].has_key(c_id) and c_name:
  396. menus_module[m_id]['sub_menu'][c_id] = {
  397. 'id': c_id,
  398. 'title': c_name,
  399. 'sub_menu': {},
  400. }
  401. # action
  402. if not menus_controller.has_key(c_id):
  403. menus_controller[c_id] = []
  404. if a_name:
  405. menus_controller[c_id].append({
  406. 'id': a_id,
  407. 'title': a_name,
  408. })
  409. menus = []
  410. for m_id, m_info in menus_module.items():
  411. for c_id, c_info in m_info['sub_menu'].items():
  412. m_info['sub_menu'][c_id]['sub_menu'] = menus_controller[c_id]
  413. menus.append({
  414. 'id': m_id,
  415. 'title': m_info['title'],
  416. 'sub_menu': m_info['sub_menu'].values(),
  417. })
  418. return menus
  419. def to_json(self):
  420. return {
  421. 'id': self.id,
  422. 'name_cn': self.name_cn,
  423. 'name_en': self.name_en,
  424. 'pid': self.pid,
  425. 'type': self.type,
  426. 'sequence': self.sequence,
  427. 'archive': self.archive,
  428. 'icon': self.icon,
  429. 'url': self.url,
  430. 'visible': self.visible,
  431. 'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
  432. 'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S'),
  433. }
  434. class RoleModel(object):
  435. _role_super = 'SUPER'
  436. _role_owner = 'OWNER'
  437. _role_master = 'MASTER'
  438. _role_developer = 'DEVELOPER'
  439. _role_reporter = 'REPORTER'
  440. @classmethod
  441. def list(cls):
  442. roles = [
  443. {'id': cls._role_super, 'name': '超级管理员'},
  444. {'id': cls._role_owner, 'name': '空间所有者'},
  445. {'id': cls._role_master, 'name': '项目管理员'},
  446. {'id': cls._role_developer, 'name': '开发者'},
  447. {'id': cls._role_reporter, 'name': '访客'},
  448. ]
  449. return roles, len(roles)
  450. @classmethod
  451. def item(cls, role_id):
  452. return None
  453. @classmethod
  454. def menu_url(cls, url):
  455. if url == '/':
  456. return url
  457. prefix = 'admin' if g.role == SUPER else session['space_info']['name']
  458. return '/' + prefix + url
  459. # 项目配置表
  460. class MemberModel(SurrogatePK, Model):
  461. __tablename__ = 'members'
  462. current_time = datetime.now()
  463. group_id = None
  464. project_id = None
  465. source_type_project = 'project'
  466. source_type_group = 'group'
  467. # 表的结构:
  468. id = db.Column(Integer, primary_key=True, autoincrement=True)
  469. user_id = db.Column(Integer, db.ForeignKey('users.id'))
  470. source_id = db.Column(Integer)
  471. source_type = db.Column(String(10))
  472. access_level = db.Column(String(10))
  473. status = db.Column(Integer)
  474. created_at = db.Column(DateTime, default=current_time)
  475. updated_at = db.Column(DateTime, default=current_time, onupdate=current_time)
  476. group_name = None
  477. # TODO group id全局化
  478. def spaces(self, user_id=None):
  479. """
  480. 获取分页列表
  481. :param page:
  482. :param size:
  483. :return:
  484. """
  485. filters = {
  486. MemberModel.status.notin_([self.status_remove]),
  487. MemberModel.source_type == self.source_type_group
  488. }
  489. query = self.query.filter(*filters).with_labels().with_entities(MemberModel.source_id, MemberModel.access_level, SpaceModel.name)
  490. if user_id:
  491. query = query.filter_by(user_id=user_id)
  492. query = query.join(SpaceModel, SpaceModel.id==MemberModel.source_id)
  493. spaces = query.all()
  494. current_app.logger.info(spaces)
  495. return {space[0]: {'id': space[0], 'role': space[1], 'name': space[2]} for space in spaces}
  496. def projects(self, user_id=None, space_id=None):
  497. """
  498. 获取分页列表
  499. :param page:
  500. :param size:
  501. :return:
  502. """
  503. filters = {
  504. MemberModel.status.notin_([self.status_remove]),
  505. MemberModel.source_type == self.source_type_project
  506. }
  507. query = self.query.filter(*filters)
  508. if user_id:
  509. query = query.filter_by(user_id=user_id)
  510. # if project_id:
  511. # query = query.filter_by(source_id=project_id)
  512. projects = query.all()
  513. current_app.logger.info(projects)
  514. return projects
  515. group, count = MemberModel.query_paginate(page=page, limit=size, filter_name_dict=filters)
  516. list = [p.to_json() for p in group]
  517. return list, count
  518. def add(self, space_name, members):
  519. """
  520. :param space_name:
  521. :param members: [{'user_id': 1, 'project_id': 2}]
  522. :return:
  523. """
  524. tag = TagModel(name=space_name, label='user_group')
  525. db.session.add(tag)
  526. db.session.commit()
  527. for member in members:
  528. user_group = MemberModel(group_id=tag.id, user_id=member['user_id'], project_id=member['project_id'])
  529. db.session.add(user_group)
  530. db.session.commit()
  531. if tag.id:
  532. self.group_id = tag.id
  533. return tag.id
  534. def update_group(self, members, group_name=None):
  535. # 修复空间名称
  536. if group_name:
  537. SpaceModel(id=self.group_id).update({'name': group_name})
  538. # # 修改tag信息
  539. # if group_name:
  540. # tag_model = TagModel.query.filter_by(label='user_group').filter_by(id=self.group_id).first()
  541. # if tag_model.name != group_name:
  542. # tag_model.name = group_name
  543. # 修改用户组成员
  544. # clean up
  545. filters = {
  546. MemberModel.source_id == self.group_id,
  547. MemberModel.source_type == self.source_type_group,
  548. }
  549. MemberModel.query.filter(*filters).delete()
  550. # insert all
  551. for member in members:
  552. update = {
  553. 'user_id': member['user_id'],
  554. 'source_id': self.group_id,
  555. 'source_type': self.source_type_group,
  556. 'access_level': member['role'].upper(),
  557. 'status': self.status_available,
  558. }
  559. m = MemberModel(**update)
  560. db.session.add(m)
  561. ret = db.session.commit()
  562. return ret
  563. def update_project(self, project_id, members, group_name=None):
  564. space_info = walle.model.deploy.ProjectModel.query.filter_by(id=project_id).first().to_json()
  565. group_model = self.members(group_id=space_info['space_id'])
  566. user_update = []
  567. for member in members:
  568. user_update.append(member['user_id'])
  569. # project新增用户是否在space's group中,无则抛出
  570. if list(set(user_update).difference(set(group_model['user_ids']))):
  571. raise ValueError('用户不存在')
  572. # 修改用户组成员
  573. # clean up
  574. filters = {
  575. MemberModel.source_id == project_id,
  576. MemberModel.source_type == self.source_type_project,
  577. }
  578. MemberModel.query.filter(*filters).delete()
  579. # insert all
  580. for member in members:
  581. insert = {
  582. 'user_id': member['user_id'],
  583. 'source_id': project_id,
  584. 'source_type': self.source_type_project,
  585. 'access_level': member['role'].upper(),
  586. 'status': self.status_available,
  587. }
  588. group = MemberModel(**insert)
  589. db.session.add(group)
  590. ret = db.session.commit()
  591. return ret
  592. def members(self, group_id=None, project_id=None):
  593. """
  594. 获取单条记录
  595. :param role_id:
  596. :return:
  597. """
  598. group_id = group_id if group_id else self.group_id
  599. project_id = project_id if project_id else self.project_id
  600. source_id = group_id if group_id else project_id
  601. source_type = self.source_type_group if group_id else self.source_type_project
  602. filters = {
  603. 'status': {'nin': [self.status_remove]},
  604. 'source_id': {'=': source_id},
  605. 'source_type': {'=': source_type},
  606. }
  607. # TODO
  608. page = 1
  609. size = 10
  610. groups, count = MemberModel.query_paginate(page=page, limit=size, filter_name_dict=filters)
  611. user_ids = []
  612. user_role = members = {}
  613. current_app.logger.info(groups)
  614. for group_info in groups:
  615. user_ids.append(group_info.user_id)
  616. # TODO
  617. user_role[group_info.user_id] = group_info.access_level
  618. current_app.logger.info(user_ids)
  619. user_model = UserModel()
  620. user_info = user_model.fetch_by_uid(uids=set(user_ids))
  621. if user_info:
  622. for user in user_info:
  623. if user_role.has_key(user['id']):
  624. user['role'] = user_role[user['id']]
  625. members['user_ids'] = user_ids
  626. members['members'] = user_info
  627. members['users'] = len(user_ids)
  628. return members
  629. def remove(self, group_id=None, user_id=None, project_id=None):
  630. """
  631. :param role_id:
  632. :return:
  633. """
  634. if group_id:
  635. MemberModel.query.filter_by(group_id=group_id).update({'status': self.status_remove})
  636. elif user_id:
  637. MemberModel.query.filter_by(user_id=user_id).update({'status': self.status_remove})
  638. elif self.group_id:
  639. MemberModel.query.filter_by(group_id=self.group_id).update({'status': self.status_remove})
  640. elif project_id:
  641. MemberModel.query.filter_by(project_id=project_id).update({'status': self.status_remove})
  642. ret = db.session.commit()
  643. return ret
  644. def to_json(self):
  645. return {
  646. 'id': self.id,
  647. 'user_id': self.user_id,
  648. 'group_id': self.group_id,
  649. 'group_name': self.group_name,
  650. 'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
  651. 'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S'),
  652. }
  653. # 项目配置表
  654. class SpaceModel(SurrogatePK, Model):
  655. # 表的名字:
  656. __tablename__ = 'spaces'
  657. current_time = datetime.now()
  658. status_close = 0
  659. status_open = 1
  660. # 表的结构:
  661. id = db.Column(Integer, primary_key=True, autoincrement=True)
  662. user_id = db.Column(Integer)
  663. name = db.Column(String(100))
  664. status = db.Column(Integer)
  665. created_at = db.Column(DateTime, default=current_time)
  666. updated_at = db.Column(DateTime, default=current_time, onupdate=current_time)
  667. def list(self, page=0, size=10, kw=None):
  668. """
  669. 获取分页列表
  670. :param page:
  671. :param size:
  672. :return:
  673. """
  674. query = self.query.filter(SpaceModel.status.notin_([self.status_remove]))
  675. if kw:
  676. query = query.filter(SpaceModel.name.like('%' + kw + '%'))
  677. # TODO 如果是超管,可以全量,否则需要过滤自己有权限的空间列表
  678. if g.role <> SUPER:
  679. query = query.filter_by(user_id=g.id)
  680. count = query.count()
  681. data = query.order_by('id desc').offset(int(size) * int(page)).limit(size).all()
  682. uid2name = UserModel.uid2name(data=data)
  683. list = [p.to_json(uid2name) for p in data]
  684. return list, count
  685. def item(self, id=None):
  686. """
  687. 获取单条记录
  688. :param role_id:
  689. :return:
  690. """
  691. id = id if id else self.id
  692. data = self.query.filter_by(id=id).first()
  693. members = MemberModel(group_id=id).members()
  694. if not data:
  695. return []
  696. data = data.to_json()
  697. return dict(data, **members)
  698. def add(self, *args, **kwargs):
  699. # todo permission_ids need to be formated and checked
  700. data = dict(*args)
  701. # tag = TagModel(name=data['name'], label='user_group')
  702. # db.session.add(tag)
  703. # db.session.commit()
  704. data = dict(*args)
  705. space = SpaceModel(**data)
  706. db.session.add(space)
  707. db.session.commit()
  708. self.id = space.id
  709. return self.id
  710. def update(self, *args, **kwargs):
  711. # todo permission_ids need to be formated and checked
  712. # a new type to update a model
  713. update_data = dict(*args)
  714. return super(SpaceModel, self).update(**update_data)
  715. def remove(self, space_id=None):
  716. """
  717. :param space_id:
  718. :return:
  719. """
  720. space_id = space_id if space_id else self.id
  721. SpaceModel.query.filter_by(id=space_id).update({'status': self.status_remove})
  722. ret = db.session.commit()
  723. return ret
  724. def to_json(self, uid2name=None):
  725. item = {
  726. 'id': self.id,
  727. 'user_id': self.user_id,
  728. 'user_name': uid2name[self.user_id] if uid2name and uid2name.has_key(self.user_id) else '',
  729. # TODO
  730. 'group_id': 'self.group_id',
  731. 'name': self.name,
  732. 'status': self.status,
  733. 'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
  734. 'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S'),
  735. }
  736. item.update(self.enable())
  737. return item
  738. def enable(self):
  739. return {
  740. 'enable_update': permission.enable_uid(self.user_id) or permission.enable_role(OWNER),
  741. 'enable_delete': permission.enable_uid(self.user_id) or permission.enable_role(OWNER),
  742. 'enable_create': False,
  743. 'enable_online': False,
  744. 'enable_audit': False,
  745. 'enable_block': permission.enable_role(MASTER),
  746. }