Advertisement
Guest User

Untitled

a guest
Apr 20th, 2016
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.74 KB | None | 0 0
  1. import pickle
  2. import phonenumbers
  3. from phonenumbers.phonenumberutil import PhoneNumberFormat
  4. from sqlalchemy import func
  5. from sqlalchemy import func, text
  6. from sqlalchemy.sql.expression import select
  7.  
  8. import pinn
  9. from pinn.name import Name
  10. from pinn.roles.role import Role, RoleType
  11. import pinn.storage.postgresql.schema
  12. from pinn.storage.postgresql.schema import roles, user_roles, users
  13. from pinn.storage.user import UserStore, NonExistingUserError
  14. from pinn.users.password import PasswordHash
  15. from pinn.users.user import User
  16. from pinn.users.user import UserValidationError
  17. from pinn.util import generate_into
  18. from pinn.validation import ValidationError
  19. from zope.interface import implementer
  20. from datetime import datetime
  21. from dateutil import relativedelta
  22.  
  23.  
  24. @implementer(UserStore)
  25. class PostgreSQLUserStore:
  26. def __init__(self, db):
  27. self._db = db
  28.  
  29. @generate_into(list)
  30. def fetch_all_users(self):
  31. rows = self._db.execute(select([users])).fetchall()
  32. for row in rows:
  33. yield self._row_to_user(row)
  34.  
  35. @generate_into(list)
  36. def fetch_all_users_with_role(self, role_name):
  37. query = select([users, user_roles, roles], use_labels=True) \
  38. .where(users.c.id == user_roles.c.user_id) \
  39. .where(roles.c.id == user_roles.c.role_id) \
  40. .where(roles.c.name == role_name)
  41. rows = self._db.execute(query).fetchall()
  42. for row in rows:
  43. yield self._row_to_user(row)
  44.  
  45. @generate_into(list)
  46. def fetch_all_loggedin_users(self):
  47. current_datetime = datetime.now()
  48. query = select([users]).where(users.c.last_heartbeat - current_datetime < relativedelta(minutes=10))
  49. rows = self._db.execute(query).fetchall()
  50. for row in rows:
  51. yield self._row_to_user(row)
  52.  
  53. def update_user_last_heartbeat(self, user):
  54. if self.fetch_user_by_id(user.id) is None:
  55. raise NonExistingUserError()
  56. last_heartbeat = self.user.last_heartbeat
  57. query = users.update().values(last_heartbeat=last_heartbeat).where(users.c.id == user.id)
  58. self._db.execute(query)
  59.  
  60. def fetch_user_by_id(self, id):
  61. query = select([users]).where(users.c.id == id)
  62. row = self._db.execute(query).first()
  63. return row and self._row_to_user(row)
  64.  
  65. def fetch_wps_key_by_user_id(self, id):
  66. query = select([users.c.wps_key]).where(users.c.id == id)
  67. return self._db.execute(query).scalar()
  68.  
  69. def fetch_user_by_email_address(self, email_address):
  70. query = select([users]).where(func.lower(email_address) == func.lower(users.c.email_address))
  71. row = self._db.execute(query).first()
  72. return row and self._row_to_user(row)
  73.  
  74. def insert_user(self, user):
  75. first_name, tussenvoegsel, last_name = self._separate_name(user.name)
  76. formatted_phone_numbers = self._format_phone_numbers(user.phone_numbers)
  77. password_recovery_hash, password_recovery_rounds, password_recovery_salt = \
  78. self._get_password_recovery_hash(user)
  79.  
  80. query = users.insert().values(
  81. first_name=first_name,
  82. tussenvoegsel=tussenvoegsel,
  83. last_name=last_name,
  84.  
  85. password_hash=user.password_hash.hash,
  86. password_salt=user.password_hash.salt,
  87. password_rounds=user.password_hash.rounds,
  88.  
  89. email_address=user.email_address,
  90. phone_numbers=formatted_phone_numbers,
  91.  
  92. password_recovery_hash=password_recovery_hash,
  93. password_recovery_salt=password_recovery_salt,
  94. password_recovery_rounds=password_recovery_rounds,
  95.  
  96. must_change_password=user.must_change_password,
  97.  
  98. created_at=user.created_at,
  99. active=user.active,
  100. )
  101. return self._db.execute(query).inserted_primary_key[0]
  102.  
  103. def update_user(self, user):
  104. if self.fetch_user_by_id(user.id) is None:
  105. raise NonExistingUserError()
  106.  
  107. first_name, tussenvoegsel, last_name = self._separate_name(user.name)
  108. formatted_phone_numbers = self._format_phone_numbers(user.phone_numbers)
  109. password_recovery_hash, password_recovery_rounds, password_recovery_salt = \
  110. self._get_password_recovery_hash(user)
  111.  
  112. query = users.update().values(
  113. first_name=first_name,
  114. tussenvoegsel=tussenvoegsel,
  115. last_name=last_name,
  116.  
  117. password_hash=user.password_hash.hash,
  118. password_salt=user.password_hash.salt,
  119. password_rounds=user.password_hash.rounds,
  120.  
  121. email_address=user.email_address,
  122. phone_numbers=formatted_phone_numbers,
  123.  
  124. password_recovery_hash=password_recovery_hash,
  125. password_recovery_salt=password_recovery_salt,
  126. password_recovery_rounds=password_recovery_rounds,
  127.  
  128. must_change_password=user.must_change_password,
  129. active=user.active,
  130. ).where(users.c.id == user.id)
  131. self._db.execute(query)
  132.  
  133. def delete_user_by_id(self, id):
  134. query = users.delete().where(users.c.id == id)
  135. self._db.execute(query)
  136.  
  137. def fetch_user_id_by_api_key(self, api_key):
  138. query = text("""
  139. SELECT id
  140. FROM users
  141. WHERE api_key = :api_key
  142. """)
  143. return self._db.execute(query, api_key=api_key).scalar()
  144.  
  145. def fetch_api_key_by_user_id(self, user_id):
  146. query = text("""
  147. SELECT api_key
  148. FROM users
  149. WHERE id = :id
  150. """)
  151. return self._db.execute(query, id=user_id).scalar()
  152.  
  153. def _separate_name(self, name):
  154. if name.last_name is None:
  155. return (name.first_name, None, None)
  156. else:
  157. return (name.first_name, name.last_name[0], name.last_name[1])
  158.  
  159. def _get_password_recovery_hash(self, user):
  160. if user.password_recovery_hash is None:
  161. password_recovery_hash = None
  162. password_recovery_salt = None
  163. password_recovery_rounds = None
  164. else:
  165. password_recovery_hash = user.password_recovery_hash.hash
  166. password_recovery_salt = user.password_recovery_hash.salt
  167. password_recovery_rounds = user.password_recovery_hash.rounds
  168. return password_recovery_hash, password_recovery_rounds, password_recovery_salt
  169.  
  170. def _format_phone_numbers(self, phone_numbers):
  171. return [phonenumbers.format_number(p, PhoneNumberFormat.INTERNATIONAL)
  172. for p in phone_numbers]
  173.  
  174. def _row_to_user(self, row):
  175. user = User(
  176. id=row[users.c.id],
  177. name=row_to_name(row),
  178. password_hash=self._row_to_password_hash(row),
  179. email_address=row[users.c.email_address],
  180. phone_numbers=[phonenumbers.parse(p) for p in row[users.c.phone_numbers]],
  181. password_recovery_hash=self._row_to_password_recovery_hash(row),
  182. must_change_password=row[users.c.must_change_password],
  183. created_at=row[users.c.created_at],
  184. active=row[users.c.active],
  185. last_heartbeat=row[users.c.last_heartbeat],
  186. )
  187. return user
  188.  
  189. def _row_to_password_hash(self, row):
  190. return PasswordHash(
  191. row[users.c.password_hash],
  192. row[users.c.password_salt],
  193. row[users.c.password_rounds],
  194. )
  195.  
  196. def _row_to_password_recovery_hash(self, row):
  197. if not row[users.c.password_recovery_hash] is None:
  198. return PasswordHash(
  199. row[users.c.password_recovery_hash],
  200. row[users.c.password_recovery_salt],
  201. row[users.c.password_recovery_rounds],
  202. )
  203.  
  204. @generate_into(list)
  205. def fetch_all_account_managers(self):
  206. rows = self._db.execute(select([users
  207. .join(user_roles, users.c.id == user_roles.c.user_id)
  208. .join(roles, roles.c.id == user_roles.c.role_id)],
  209. use_labels=True)
  210. .where(roles.c.name == RoleType.ACCOUNT_MANAGER.value)).fetchall()
  211. for row in rows:
  212. yield self._row_to_user(row)
  213.  
  214.  
  215. def _check_duplicate_email_address(db, user):
  216. query = (select([func.count(users.c.id) == 1])
  217. .where(users.c.email_address == user.email_address)
  218. .where(users.c.id != user.id))
  219. if db.execute(query).scalar():
  220. raise ValidationError(
  221. {UserValidationError.EMAIL_ADDRESS_ALREADY_IN_USE})
  222.  
  223.  
  224. def _row_to_password_hash(row):
  225. return PasswordHash(
  226. row[users.c.password_hash],
  227. row[users.c.password_salt],
  228. row[users.c.password_rounds],
  229. )
  230.  
  231.  
  232. def _row_to_password_recovery_hash(row):
  233. if not row[users.c.password_recovery_hash] is None:
  234. return PasswordHash(
  235. row[users.c.password_recovery_hash],
  236. row[users.c.password_recovery_salt],
  237. row[users.c.password_recovery_rounds],
  238. )
  239.  
  240.  
  241. def _row_to_user(row):
  242. user = User(
  243. row[users.c.id],
  244. row_to_name(row),
  245. _row_to_password_hash(row),
  246. row[users.c.email_address],
  247. [phonenumbers.parse(p) for p in row[users.c.phone_numbers]],
  248. _row_to_password_recovery_hash(row),
  249. created_at=row[users.c.created_at]
  250. )
  251. return user
  252.  
  253.  
  254. def row_to_name(row):
  255. first_name = row[users.c.first_name]
  256. tussenvoegsel = row[users.c.tussenvoegsel]
  257. last_name = row[users.c.last_name]
  258. if last_name is None and tussenvoegsel is None:
  259. return Name(first_name, None)
  260. else:
  261. return Name(first_name, (tussenvoegsel, last_name))
  262.  
  263.  
  264. def backup_user(backup_dir, user):
  265. backup_path = backup_dir / '{}.{}'.format(user.id, pinn.__version__)
  266. with backup_path.open('wb') as backup_file:
  267. pickle.dump(user, backup_file)
  268.  
  269.  
  270. def _format_phone_numbers(phone_numbers):
  271. return [phonenumbers.format_number(p, PhoneNumberFormat.INTERNATIONAL)
  272. for p in phone_numbers]
  273.  
  274.  
  275. def insert_user(db, user):
  276. _check_duplicate_email_address(db, user)
  277.  
  278. formatted_phone_numbers = _format_phone_numbers(user.phone_numbers)
  279. first_name, tussenvoegsel, last_name = _get_name(user)
  280.  
  281. query = users.insert().values(
  282. first_name=first_name,
  283. tussenvoegsel=tussenvoegsel,
  284. last_name=last_name,
  285.  
  286. password_hash=user.password_hash.hash,
  287. password_salt=user.password_hash.salt,
  288. password_rounds=user.password_hash.rounds,
  289.  
  290. email_address=user.email_address,
  291. phone_numbers=formatted_phone_numbers,
  292.  
  293. password_recovery_hash=user.password_recovery_hash.hash if not user.password_recovery_hash is None else None,
  294. password_recovery_salt=user.password_recovery_hash.salt if not user.password_recovery_hash is None else None,
  295. password_recovery_rounds=user.password_recovery_hash.rounds if not user.password_recovery_hash is None else None,
  296.  
  297. created_at=user.created_at,
  298. active=True,
  299. )
  300. return db.execute(query).inserted_primary_key[0]
  301.  
  302.  
  303. def update_user(db, user):
  304. _check_duplicate_email_address(db, user)
  305.  
  306. formatted_phone_numbers = _format_phone_numbers(user.phone_numbers)
  307. first_name, tussenvoegsel, last_name = _get_name(user)
  308. query = users.update().values(
  309. first_name=first_name,
  310. tussenvoegsel=tussenvoegsel,
  311. last_name=last_name,
  312.  
  313. password_hash=user.password_hash.hash,
  314. password_salt=user.password_hash.salt,
  315. password_rounds=user.password_hash.rounds,
  316.  
  317. email_address=user.email_address,
  318. phone_numbers=formatted_phone_numbers,
  319.  
  320. password_recovery_hash=user.password_recovery_hash.hash if not user.password_recovery_hash is None else None,
  321. password_recovery_salt=user.password_recovery_hash.salt if not user.password_recovery_hash is None else None,
  322. password_recovery_rounds=user.password_recovery_hash.rounds if not user.password_recovery_hash is None else None,
  323.  
  324. ).where(users.c.id == user.id)
  325. db.execute(query)
  326.  
  327.  
  328. def _get_name(user):
  329. first_name = user.name.first_name
  330. if user.name.last_name is None:
  331. tussenvoegsel = None
  332. last_name = None
  333. else:
  334. tussenvoegsel = user.name.last_name[0]
  335. last_name = user.name.last_name[1]
  336. return first_name, tussenvoegsel, last_name
  337.  
  338.  
  339. def fetch_users(db):
  340. query = select([users])
  341. return list(map(_row_to_user, db.execute(query)))
  342.  
  343.  
  344. def fetch_user_by_id(db, id):
  345. query = select([users]).where(users.c.id == id)
  346. row = db.execute(query).first()
  347. return row and _row_to_user(row)
  348.  
  349.  
  350. def fetch_user_by_email_address(db, email_address):
  351. query = select([users]).where(users.c.email_address == email_address)
  352. row = db.execute(query).first()
  353. return row and _row_to_user(row)
  354.  
  355.  
  356. def delete_user_with_id(db, backup_dir, id):
  357. user = fetch_user_by_id(db, id)
  358. if user is not None:
  359. backup_user(backup_dir, user)
  360.  
  361. query = users.delete().where(users.c.id == id)
  362. db.execute(query)
  363.  
  364.  
  365. def fetch_user_by_password_recovery_token(db, token):
  366. for user in fetch_users(db):
  367. password_recovery_hash = user.password_recovery_hash
  368. if not password_recovery_hash is None:
  369. if password_recovery_hash.matches_password(token):
  370. return user
  371.  
  372.  
  373. def fetch_all_roles(db):
  374. query = select([roles])
  375. return {_row_to_role(row) for row in db.execute(query)}
  376.  
  377.  
  378. def add_role_to_user(db, user_id, role_id):
  379. query = user_roles.insert().values(user_id=user_id, role_id=role_id)
  380. db.execute(query)
  381.  
  382.  
  383. def remove_role_from_user(db, user_id, role_id):
  384. query = (user_roles.delete()
  385. .where(user_roles.c.user_id == user_id)
  386. .where(user_roles.c.role_id == role_id))
  387. db.execute(query)
  388.  
  389.  
  390. def _row_to_role(row):
  391. return Role(row[roles.c.id], row[roles.c.name])
  392.  
  393.  
  394. def fetch_user_roles(db, user_id):
  395. query = (select([user_roles.join(roles)])
  396. .where(user_roles.c.user_id == user_id))
  397. return {_row_to_role(row) for row in db.execute(query)}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement