reaction.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # mautrix-signal - A Matrix-Signal puppeting bridge
  2. # Copyright (C) 2020 Tulir Asokan
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU Affero General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU Affero General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. from typing import Optional, ClassVar, Union, TYPE_CHECKING
  17. from uuid import UUID
  18. from attr import dataclass
  19. import asyncpg
  20. from mausignald.types import Address, GroupID
  21. from mautrix.types import RoomID, EventID
  22. from mautrix.util.async_db import Database
  23. from ..util import id_to_str
  24. fake_db = Database.create("") if TYPE_CHECKING else None
  25. @dataclass
  26. class Reaction:
  27. db: ClassVar[Database] = fake_db
  28. mxid: EventID
  29. mx_room: RoomID
  30. signal_chat_id: Union[GroupID, Address]
  31. signal_receiver: str
  32. msg_author: Address
  33. msg_timestamp: int
  34. author: Address
  35. emoji: str
  36. async def insert(self) -> None:
  37. q = ("INSERT INTO reaction (mxid, mx_room, signal_chat_id, signal_receiver, msg_author,"
  38. " msg_timestamp, author, emoji) "
  39. "VALUES ($1, $2, $3, $4, $5, $6, $7, $8)")
  40. await self.db.execute(q, self.mxid, self.mx_room, id_to_str(self.signal_chat_id),
  41. self.signal_receiver, self.msg_author.best_identifier,
  42. self.msg_timestamp, self.author.best_identifier, self.emoji)
  43. async def edit(self, mx_room: RoomID, mxid: EventID, emoji: str) -> None:
  44. await self.db.execute("UPDATE reaction SET mxid=$1, mx_room=$2, emoji=$3 "
  45. "WHERE signal_chat_id=$4 AND signal_receiver=$5"
  46. " AND msg_author=$6 AND msg_timestamp=$7 AND author=$8",
  47. mxid, mx_room, emoji, id_to_str(self.signal_chat_id),
  48. self.signal_receiver, self.msg_author.best_identifier,
  49. self.msg_timestamp, self.author.best_identifier)
  50. async def delete(self) -> None:
  51. q = ("DELETE FROM reaction WHERE signal_chat_id=$1 AND signal_receiver=$2"
  52. " AND msg_author=$3 AND msg_timestamp=$4 AND author=$5")
  53. await self.db.execute(q, id_to_str(self.signal_chat_id), self.signal_receiver,
  54. self.msg_author.best_identifier, self.msg_timestamp,
  55. self.author.best_identifier)
  56. @classmethod
  57. def _from_row(cls, row: asyncpg.Record) -> 'Reaction':
  58. data = {**row}
  59. chat_id = data.pop("signal_chat_id")
  60. if data["signal_receiver"]:
  61. chat_id = Address.parse(chat_id)
  62. msg_author = Address.parse(data.pop("msg_author"))
  63. author = Address.parse(data.pop("author"))
  64. return cls(signal_chat_id=chat_id, msg_author=msg_author, author=author, **data)
  65. @classmethod
  66. async def get_by_mxid(cls, mxid: EventID, mx_room: RoomID) -> Optional['Reaction']:
  67. q = ("SELECT mxid, mx_room, signal_chat_id, signal_receiver,"
  68. " msg_author, msg_timestamp, author, emoji "
  69. "FROM reaction WHERE mxid=$1 AND mx_room=$2")
  70. row = await cls.db.fetchrow(q, mxid, mx_room)
  71. if not row:
  72. return None
  73. return cls._from_row(row)
  74. @classmethod
  75. async def get_by_signal_id(cls, chat_id: Union[GroupID, Address], receiver: str,
  76. msg_author: Address, msg_timestamp: int, author: Address
  77. ) -> Optional['Reaction']:
  78. q = ("SELECT mxid, mx_room, signal_chat_id, signal_receiver,"
  79. " msg_author, msg_timestamp, author, emoji "
  80. "FROM reaction WHERE signal_chat_id=$1 AND signal_receiver=$2"
  81. " AND msg_author=$3 AND msg_timestamp=$4 AND author=$5")
  82. row = await cls.db.fetchrow(q, id_to_str(chat_id), receiver, msg_author.best_identifier,
  83. msg_timestamp, author.best_identifier)
  84. if not row:
  85. return None
  86. return cls._from_row(row)