moderator.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import logging
  2. from typing import Optional
  3. from aiogram.types import ChatIdUnion
  4. from sqlalchemy.exc import IntegrityError
  5. from sqlalchemy.ext.asyncio import AsyncSession
  6. from anonflow.database import (
  7. Database,
  8. BanRepository,
  9. ModeratorRepository
  10. )
  11. class ForbiddenError(PermissionError): ...
  12. class ModeratorService:
  13. def __init__(
  14. self,
  15. database: Database,
  16. ban_repository: BanRepository,
  17. moderator_repository: ModeratorRepository
  18. ):
  19. self._logger = logging.getLogger(__name__)
  20. self._database = database
  21. self._ban_repository = ban_repository
  22. self._moderator_repository = moderator_repository
  23. async def add(self, actor_chat_id: ChatIdUnion, chat_id: ChatIdUnion):
  24. try:
  25. async with self._database.get_session() as session:
  26. if await self._can_manage_moderators(session, actor_chat_id):
  27. await self._moderator_repository.add(session, chat_id)
  28. else:
  29. raise ForbiddenError()
  30. except IntegrityError:
  31. self._logger.warning("Failed to add moderator chat_id=%s", chat_id)
  32. async def ban(self, actor_chat_id: ChatIdUnion, chat_id: ChatIdUnion):
  33. async with self._database.get_session() as session:
  34. if await self._can_manage_bans(session, actor_chat_id):
  35. await self._ban_repository.ban(session, actor_chat_id, chat_id)
  36. else:
  37. raise ForbiddenError()
  38. async def _get_permission(self, session: AsyncSession, actor_chat_id: ChatIdUnion, name: str) -> bool:
  39. moderator = await self._moderator_repository.get(session, actor_chat_id)
  40. return getattr(getattr(moderator, name, None), "value", False)
  41. async def _can_approve_posts(self, session: AsyncSession, actor_chat_id: ChatIdUnion):
  42. return await self._get_permission(session, actor_chat_id, "can_approve_posts")
  43. async def can_approve_posts(self, actor_chat_id: ChatIdUnion):
  44. async with self._database.get_session() as session:
  45. return await self._can_approve_posts(session, actor_chat_id)
  46. async def _can_manage_bans(self, session: AsyncSession, actor_chat_id: ChatIdUnion):
  47. return await self._get_permission(session, actor_chat_id, "can_manage_bans")
  48. async def can_manage_bans(self, actor_chat_id: ChatIdUnion):
  49. async with self._database.get_session() as session:
  50. return await self._can_manage_bans(session, actor_chat_id)
  51. async def _can_manage_moderators(self, session: AsyncSession, actor_chat_id: ChatIdUnion):
  52. return await self._get_permission(session, actor_chat_id, "can_manage_moderators")
  53. async def can_manage_moderators(self, actor_chat_id: ChatIdUnion):
  54. async with self._database.get_session() as session:
  55. return await self._can_manage_moderators(session, actor_chat_id)
  56. async def get(self, chat_id: ChatIdUnion):
  57. async with self._database.get_session() as session:
  58. return await self._moderator_repository.get(session, chat_id)
  59. async def get_permissions(self, chat_id: ChatIdUnion):
  60. async with self._database.get_session() as session:
  61. return await self._moderator_repository.get_permissions(session, chat_id)
  62. async def has(self, chat_id: ChatIdUnion):
  63. async with self._database.get_session() as session:
  64. return await self._moderator_repository.has(session, chat_id)
  65. async def is_banned(self, chat_id: ChatIdUnion):
  66. async with self._database.get_session() as session:
  67. return await self._ban_repository.is_banned(session, chat_id)
  68. async def remove(self, actor_chat_id: ChatIdUnion, chat_id: ChatIdUnion):
  69. try:
  70. async with self._database.get_session() as session:
  71. if await self._can_manage_moderators(session, actor_chat_id):
  72. await self._moderator_repository.remove(session, chat_id)
  73. else:
  74. raise ForbiddenError()
  75. except IntegrityError:
  76. self._logger.warning("Failed to remove moderator chat_id=%s", chat_id)
  77. async def unban(self, actor_chat_id: ChatIdUnion, chat_id: ChatIdUnion):
  78. async with self._database.get_session() as session:
  79. if await self._can_manage_bans(session, actor_chat_id):
  80. await self._ban_repository.unban(session, actor_chat_id, chat_id)
  81. else:
  82. raise ForbiddenError()
  83. async def update(self, actor_chat_id: ChatIdUnion, chat_id: ChatIdUnion, **fields):
  84. try:
  85. async with self._database.get_session() as session:
  86. if await self._can_manage_moderators(session, actor_chat_id):
  87. await self._moderator_repository.update(session, chat_id, **fields)
  88. else:
  89. raise ForbiddenError()
  90. except IntegrityError:
  91. self._logger.warning("Failed to update moderator chat_id=%s", chat_id)
  92. async def update_permissions(
  93. self,
  94. actor_chat_id: ChatIdUnion,
  95. chat_id: ChatIdUnion,
  96. *,
  97. can_approve_posts: Optional[bool] = None,
  98. can_manage_bans: Optional[bool] = None,
  99. can_manage_moderators: Optional[bool] = None
  100. ):
  101. try:
  102. async with self._database.get_session() as session:
  103. if await self._can_manage_moderators(session, actor_chat_id):
  104. await self._moderator_repository.update_permissions(
  105. session,
  106. chat_id,
  107. can_approve_posts=can_approve_posts,
  108. can_manage_bans=can_manage_bans,
  109. can_manage_moderators=can_manage_moderators
  110. )
  111. else:
  112. raise ForbiddenError()
  113. except IntegrityError:
  114. self._logger.warning("Failed to update moderator chat_id=%s", chat_id)