users_manager.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import asyncio
  2. import tortoise.transactions
  3. from .user import user
  4. from .user import user_proxy
  5. from .validators import validators
  6. from .exceptions import nick_in_use
  7. from .exceptions import nick_not_exists
  8. from .exceptions import user_is_not_admin
  9. from .exceptions import apikey_not_exists
  10. from .exceptions import invalid_nick_syntax
  11. from .exceptions import invalid_apikey_syntax
  12. from .exceptions import invalid_password_syntax
  13. from .exceptions import user_is_only_admin
  14. class users_manager:
  15. @classmethod
  16. async def api_register(
  17. cls,
  18. apikey: str,
  19. nick: str,
  20. password: str
  21. ) -> [user, user]:
  22. requester = await cls.require_by_apikey(apikey)
  23. if not requester.is_admin:
  24. raise user_is_not_admin()
  25. return await cls.register(nick, password), requester
  26. @classmethod
  27. async def register(cls, nick: str, password: str) -> user:
  28. if await cls.is_nick_in_use(nick):
  29. raise nick_in_use(nick)
  30. try:
  31. nick = validators.nick(nick)
  32. except Exception as error:
  33. raise invalid_nick_syntax(nick, error)
  34. async with tortoise.transactions.in_transaction():
  35. proxy = await user_proxy.create(nick, password)
  36. while await cls.is_apikey_in_use(proxy.result().apikey):
  37. proxy.drop_sessions()
  38. user = proxy.result()
  39. await user.save()
  40. return user
  41. @classmethod
  42. async def set_privileges_process(
  43. cls,
  44. apikey: str,
  45. nick: str,
  46. privileges: bool
  47. ) -> [user, user]:
  48. requester = await cls.get_by_apikey(apikey)
  49. if requester.nick == nick:
  50. raise can_not_change_own_privileges()
  51. if not requester.is_admin:
  52. raise user_is_not_admin()
  53. return requester, await cls.set_privileges(nick, privileges)
  54. @classmethod
  55. async def set_privileges(cls, nick: str, privileges: bool) -> user:
  56. async with tortoise.transactions.in_transaction():
  57. target = await cls.require_by_nick(nick)
  58. admins_count = await cls.count_admins()
  59. if admins_count == 1 and target.is_admin:
  60. raise user_is_only_admin
  61. target.is_admin = privileges
  62. await target.save()
  63. return target
  64. @classmethod
  65. async def remove(cls, nick: str) -> None:
  66. async with tortoise.transactions.in_transaction():
  67. target = await cls.require_by_nick(nick)
  68. admins_count = await cls.count_admins()
  69. if target.is_admin and admins_count == 1:
  70. raise user_is_only_admin()
  71. await target.delete()
  72. @classmethod
  73. async def remove_process(cls, apikey: str, nick: str) -> None:
  74. requester = await cls.require_by_apikey(apikey)
  75. if requester.nick == nick:
  76. return await cls.remove(nick)
  77. if requester.is_admin is False:
  78. raise user_is_not_admin()
  79. await cls.remove(nick)
  80. @classmethod
  81. async def count_admins(cls) -> int:
  82. return await user.filter(is_admin = True).count()
  83. @classmethod
  84. async def login(cls, nick: str, password: str) -> user | None:
  85. try:
  86. nick = validators.nick(nick)
  87. except Exception as error:
  88. raise invalid_nick_syntax(nick, error)
  89. async with tortoise.transactions.in_transaction():
  90. result = await user.filter(nick = nick).first()
  91. proxy = user_proxy(result)
  92. if await proxy.compare_password(password):
  93. return result
  94. return None
  95. @classmethod
  96. async def change_own_password(cls, apikey: str, password: str) -> user:
  97. target = await cls.require_by_apikey(apikey)
  98. return await cls.change_password(target, password)
  99. @classmethod
  100. async def change_other_password(
  101. cls,
  102. apikey: str,
  103. nick: str,
  104. password: str
  105. ) -> [user, user]:
  106. requester = await cls.require_by_apikey(apikey)
  107. target = await cls.require_by_nick(nick)
  108. if not requester.is_admin:
  109. raise user_is_not_admin()
  110. return requester, await cls.change_password(target, password)
  111. @classmethod
  112. async def drop_own_sessions(cls, apikey: str) -> user:
  113. target = await cls.require_by_apikey(apikey)
  114. return await cls.drop_sessions(target)
  115. @classmethod
  116. async def drop_other_sessions(
  117. cls,
  118. apikey: str,
  119. nick: str
  120. ) -> [user, user]:
  121. requester = await cls.require_by_apikey(apikey)
  122. target = await cls.require_by_nick(nick)
  123. if not requester.is_admin:
  124. raise user_is_not_admin()
  125. return requester, await cls.drop_sessions(target)
  126. @classmethod
  127. async def change_password(cls, target: user, password: str) -> user:
  128. try:
  129. password = validatord.password(password)
  130. except Exception as error:
  131. raise invalid_password_syntax(password, error)
  132. proxy = user_proxy(target)
  133. await proxy.set_password(password)
  134. async with tortoise.transactions.in_transaction():
  135. result = proxy.result()
  136. await result.save()
  137. return result
  138. @classmethod
  139. async def drop_sessions(cls, target: user) -> user:
  140. async with tortoise.transactions.in_transaction():
  141. proxy = user_proxy(target)
  142. proxy.drop_sessions(self)
  143. while await cls.is_apikey_in_use(proxy.result().apikey):
  144. proxy.drop_sessions(self)
  145. result = proxy.result()
  146. await result.save()
  147. return result
  148. @classmethod
  149. async def get_by_apikey(cls, apikey: str) -> user | None:
  150. try:
  151. apikey = validators.apikey(apikey)
  152. except Exception as error:
  153. raise invalid_apikey_syntax(apikey, error)
  154. async with tortoise.transactions.in_transaction():
  155. return await user.filter(apikey = apikey).first()
  156. @classmethod
  157. async def is_apikey_in_use(cls, apikey: str) -> bool:
  158. return (await cls.get_by_apikey(apikey)) is not None
  159. @classmethod
  160. async def require_by_apikey(cls, apikey: str) -> user:
  161. target = await cls.get_by_apikey(apikey)
  162. if target is None:
  163. raise apikey_not_exists(apikey)
  164. return target
  165. @classmethod
  166. async def get_by_nick(cls, nick: str) -> user | None:
  167. try:
  168. nick = validators.nick(nick)
  169. except Exception as error:
  170. raise invalid_nick_syntax(nick, error)
  171. async with tortoise.transactions.in_transaction():
  172. return await user.filter(nick = nick).first()
  173. @classmethod
  174. async def is_nick_in_use(cls, nick: str) -> bool:
  175. return (await cls.get_by_nick(nick)) is not None
  176. @classmethod
  177. async def require_by_nick(cls, nick: str) -> user:
  178. target = await cls.get_by_nick(nick)
  179. if target is None:
  180. raise nick_not_exists(nick)
  181. return target