diff --git a/main.py b/main.py index 337a56a..fb33548 100644 --- a/main.py +++ b/main.py @@ -156,7 +156,7 @@ class SignalAPI: async for websocket in websockets.connect(f"{ws_url}/v1/receive/{self.number}"): yield websocket - async def receive_messages(self, websocket) -> Result[Message, str]: + async def receive_message(self, websocket) -> Result[Message, str]: return parse_response(Message, await websocket.recv()) def send_message(self, message: SendMessageSimple) -> Result[SendMessageResponse, str]: @@ -224,12 +224,87 @@ class LabCleaningBot: async for websocket in self.api.websocket_connect_receive(): try: while True: - message = await self.api.receive_messages(websocket) - print(message) + message_result = await self.api.receive_message(websocket) + + if is_err(message_result): + print(message_result.unwrap_err()) + continue + else: + message = message_result.unwrap() + + self.message_received(message, session) except websockets.exceptions.ConnectionClosed: print("Websockets connection closed. Reestablishing connection.") + def message_received(self, message: Message, session: Session): + envelope = message.envelope + + match envelope: + # Normal direct message (no edits, no reactions) + case EnvelopeData(dataMessage=DataMessage(message=message, groupInfo=None), sourceNumber=sourceNumber): + print(message, "direct", sourceNumber) + # Normal group message (no edits, no reactions) + case EnvelopeData(dataMessage=DataMessage(message=message, groupInfo=GroupInfo(groupId=group_id)), sourceNumber=sourceNumber): + print(message, group_id) + # Reaction in direct messages + case EnvelopeData( + dataMessage=ReactionMessage( + reaction=Reaction( + emoji=emoji, + isRemove=isRemove, + targetSentTimestamp=targetSentTimestamp + ), + groupInfo=None, + timestamp=timestamp + ), + sourceNumber=sourceNumber): + + reactionTimestamp = signal_timestamp_to_datetime(timestamp) + requestTimestamp = signal_timestamp_to_datetime(targetSentTimestamp) + + maybe_request = get_participation_request_by_timestamp(session, requestTimestamp) + + if is_err(maybe_request): + print("No participation request found for timestamp %s." % requestTimestamp) + return + + request = maybe_request.unwrap() + + response_msg = "" + + if emoji == "👍" and not isRemove: + accept_result = request.try_accept(now=reactionTimestamp) + + match accept_result: + case Ok(AcceptInTime()): + response_msg = "You accepted the request." + case Ok(AcceptAfterRejectAllowed()): + response_msg = "You accepted the request after rejecting it." + case Err(AcceptAfterRejectExpired()): + response_msg = "You cannot accept the request after rejecting it after 5 minutes." + case Err(AlreadyAccepted()): + response_msg = "You already accepted the request." + case Err(AcceptAfterTimeout()): + response_msg = "You cannot accept the request after the timeout." + else: + reject_result = request.try_reject(now=reactionTimestamp) + + match reject_result: + case Ok(RejectInTime()): + response_msg = "You rejected the request." + case Ok(RejectAfterAccept()): + response_msg = "You rejected the request after accepting it." + case Err(AlreadyRejected()): + response_msg = "You already rejected the request." + case Err(RejectAfterTimeout()): + response_msg = "You cannot reject the request after the timeout." + + self.api.send_message( + SendMessageSimple(message=response_msg, recipients=[sourceNumber])) + + print(emoji, "direct", sourceNumber, isRemove) + async def sync_members_and_tasks(self, session: Session): unfulfillable_tasks = [] diff --git a/models.py b/models.py index c9dabd6..33b14b1 100644 --- a/models.py +++ b/models.py @@ -69,6 +69,15 @@ def get_user_by_name(session: Session, name: str, only_active: bool = True) -> R else: return Ok(user) +def get_participation_request_by_timestamp(session: Session, timestamp: datetime.datetime) -> Result["ParticipationRequest", None]: + Q = select(ParticipationRequest).where(ParticipationRequest.requested_at == timestamp) + request = session.exec(Q).first() + + if request is None: + return Err(None) + else: + return Ok(request) + class Task(SQLModel, table=True): id: int = Field(primary_key=True) name: str