slidge 0.2.0a9__py3-none-any.whl → 0.2.0b0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. slidge/__main__.py +2 -3
  2. slidge/__version__.py +1 -1
  3. slidge/command/adhoc.py +1 -1
  4. slidge/command/base.py +4 -4
  5. slidge/command/user.py +5 -1
  6. slidge/contact/roster.py +9 -0
  7. slidge/core/config.py +0 -3
  8. slidge/core/dispatcher/__init__.py +3 -0
  9. slidge/core/{gateway → dispatcher}/caps.py +6 -4
  10. slidge/core/{gateway → dispatcher}/disco.py +11 -17
  11. slidge/core/dispatcher/message/__init__.py +10 -0
  12. slidge/core/dispatcher/message/chat_state.py +40 -0
  13. slidge/core/dispatcher/message/marker.py +62 -0
  14. slidge/core/dispatcher/message/message.py +397 -0
  15. slidge/core/dispatcher/muc/__init__.py +12 -0
  16. slidge/core/dispatcher/muc/admin.py +98 -0
  17. slidge/core/{gateway → dispatcher/muc}/mam.py +26 -15
  18. slidge/core/dispatcher/muc/misc.py +121 -0
  19. slidge/core/dispatcher/muc/owner.py +96 -0
  20. slidge/core/{gateway → dispatcher/muc}/ping.py +10 -15
  21. slidge/core/dispatcher/presence.py +177 -0
  22. slidge/core/{gateway → dispatcher}/registration.py +23 -2
  23. slidge/core/{gateway → dispatcher}/search.py +9 -14
  24. slidge/core/dispatcher/session_dispatcher.py +84 -0
  25. slidge/core/dispatcher/util.py +174 -0
  26. slidge/core/{gateway/vcard_temp.py → dispatcher/vcard.py} +26 -12
  27. slidge/core/{gateway/base.py → gateway.py} +42 -137
  28. slidge/core/mixins/attachment.py +24 -8
  29. slidge/core/mixins/base.py +2 -2
  30. slidge/core/mixins/lock.py +10 -8
  31. slidge/core/mixins/message.py +9 -203
  32. slidge/core/mixins/message_text.py +211 -0
  33. slidge/core/pubsub.py +2 -1
  34. slidge/core/session.py +28 -2
  35. slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +83 -0
  36. slidge/db/alembic/versions/45c24cc73c91_add_bob.py +42 -0
  37. slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +12 -1
  38. slidge/db/models.py +16 -1
  39. slidge/db/store.py +144 -11
  40. slidge/group/bookmarks.py +23 -1
  41. slidge/group/participant.py +5 -5
  42. slidge/group/room.py +10 -1
  43. slidge/{core/gateway → slixfix}/delivery_receipt.py +1 -1
  44. slidge/util/test.py +9 -5
  45. slidge/util/types.py +6 -0
  46. slidge/util/util.py +5 -2
  47. {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/METADATA +2 -1
  48. {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/RECORD +51 -40
  49. slidge-0.2.0b0.dist-info/entry_points.txt +3 -0
  50. slidge/core/gateway/__init__.py +0 -3
  51. slidge/core/gateway/muc_admin.py +0 -35
  52. slidge/core/gateway/presence.py +0 -95
  53. slidge/core/gateway/session_dispatcher.py +0 -895
  54. slidge-0.2.0a9.dist-info/entry_points.txt +0 -3
  55. {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/LICENSE +0 -0
  56. {slidge-0.2.0a9.dist-info → slidge-0.2.0b0.dist-info}/WHEEL +0 -0
slidge/__main__.py CHANGED
@@ -1,4 +1,3 @@
1
- if __name__ == "__main__":
2
- from slidge.main import main
1
+ from slidge.main import main
3
2
 
4
- main()
3
+ main()
slidge/__version__.py CHANGED
@@ -2,4 +2,4 @@ from slidge.util.util import get_version # noqa: F401
2
2
 
3
3
  # this is modified before publish, but if someone cloned from the repo,
4
4
  # it can help
5
- __version__ = "0.2.0alpha9"
5
+ __version__ = "0.2.0beta0"
slidge/command/adhoc.py CHANGED
@@ -13,7 +13,7 @@ from . import Command, CommandResponseType, Confirmation, Form, TableResult
13
13
  from .base import FormField
14
14
 
15
15
  if TYPE_CHECKING:
16
- from ..core.gateway.base import BaseGateway
16
+ from ..core.gateway import BaseGateway
17
17
  from ..core.session import BaseSession
18
18
 
19
19
 
slidge/command/base.py CHANGED
@@ -6,9 +6,9 @@ from typing import (
6
6
  Any,
7
7
  Awaitable,
8
8
  Callable,
9
- Collection,
10
9
  Iterable,
11
10
  Optional,
11
+ Sequence,
12
12
  Type,
13
13
  TypedDict,
14
14
  Union,
@@ -54,11 +54,11 @@ class TableResult:
54
54
  Structured data as the result of a command
55
55
  """
56
56
 
57
- fields: Collection["FormField"]
57
+ fields: Sequence["FormField"]
58
58
  """
59
59
  The 'columns names' of the table.
60
60
  """
61
- items: Collection[dict[str, Union[str, JID]]]
61
+ items: Sequence[dict[str, Union[str, JID]]]
62
62
  """
63
63
  The rows of the table. Each row is a dict where keys are the fields ``var``
64
64
  attribute.
@@ -149,7 +149,7 @@ class Form:
149
149
 
150
150
  title: str
151
151
  instructions: str
152
- fields: Collection["FormField"]
152
+ fields: Sequence["FormField"]
153
153
  handler: FormHandlerType
154
154
  handler_args: Iterable[Any] = field(default_factory=list)
155
155
  handler_kwargs: dict[str, Any] = field(default_factory=dict)
slidge/command/user.py CHANGED
@@ -305,7 +305,10 @@ class LeaveGroup(Command):
305
305
  FormField(
306
306
  "group",
307
307
  "Group name",
308
- options=[{"label": g.name, "value": g.name} for g in groups],
308
+ type="list-single",
309
+ options=[
310
+ {"label": g.name, "value": str(i)} for i, g in enumerate(groups)
311
+ ],
309
312
  )
310
313
  ],
311
314
  handler=self.confirm, # type:ignore
@@ -329,3 +332,4 @@ class LeaveGroup(Command):
329
332
  @staticmethod
330
333
  async def finish(session: AnyBaseSession, _ifrom, group: LegacyMUC):
331
334
  await session.on_leave_group(group.legacy_id)
335
+ await session.bookmarks.remove(group, reason="You left this group via slidge.")
slidge/contact/roster.py CHANGED
@@ -92,6 +92,13 @@ class LegacyRoster(
92
92
  stored = self.__store.get_by_jid(self.session.user_pk, contact_jid)
93
93
  return await self.__update_contact(stored, legacy_id, username)
94
94
 
95
+ def by_jid_only_if_exists(self, contact_jid: JID) -> LegacyContactType | None:
96
+ with self.__store.session():
97
+ stored = self.__store.get_by_jid(self.session.user_pk, contact_jid)
98
+ if stored is not None and stored.updated:
99
+ return self._contact_cls.from_store(self.session, stored)
100
+ return None
101
+
95
102
  async def by_legacy_id(
96
103
  self, legacy_id: LegacyUserIdType, *args, **kwargs
97
104
  ) -> LegacyContactType:
@@ -147,6 +154,8 @@ class LegacyRoster(
147
154
  try:
148
155
  with contact.updating_info():
149
156
  await contact.avatar_wrap_update_info()
157
+ except XMPPError:
158
+ raise
150
159
  except Exception as e:
151
160
  raise XMPPError("internal-server-error", str(e))
152
161
  contact._caps_ver = await contact.get_caps_ver(contact.jid)
slidge/core/config.py CHANGED
@@ -154,9 +154,6 @@ LAST_SEEN_FALLBACK__DOC = (
154
154
  QR_TIMEOUT = 60
155
155
  QR_TIMEOUT__DOC = "Timeout for QR code flashing confirmation."
156
156
 
157
- DOWNLOAD_CHUNK_SIZE = 1024
158
- DOWNLOAD_CHUNK_SIZE__DOC = "Chunk size when slidge needs to download files using HTTP."
159
-
160
157
  LAST_MESSAGE_CORRECTION_RETRACTION_WORKAROUND = False
161
158
  LAST_MESSAGE_CORRECTION_RETRACTION_WORKAROUND__DOC = (
162
159
  "If the legacy service does not support last message correction but supports"
@@ -0,0 +1,3 @@
1
+ from .session_dispatcher import SessionDispatcher
2
+
3
+ __all__ = ("SessionDispatcher",)
@@ -5,17 +5,19 @@ from slixmpp import Presence
5
5
  from slixmpp.exceptions import XMPPError
6
6
  from slixmpp.xmlstream import StanzaBase
7
7
 
8
+ from .util import DispatcherMixin
9
+
8
10
  if TYPE_CHECKING:
9
- from .base import BaseGateway
11
+ from slidge.core.gateway import BaseGateway
10
12
 
11
13
 
12
- class Caps:
14
+ class CapsMixin(DispatcherMixin):
13
15
  def __init__(self, xmpp: "BaseGateway"):
14
- self.xmpp = xmpp
16
+ super().__init__(xmpp)
15
17
  xmpp.del_filter("out", xmpp.plugin["xep_0115"]._filter_add_caps)
16
18
  xmpp.add_filter("out", self._filter_add_caps) # type:ignore
17
19
 
18
- async def _filter_add_caps(self, stanza: StanzaBase):
20
+ async def _filter_add_caps(self, stanza: StanzaBase) -> StanzaBase:
19
21
  # we rolled our own "add caps on presences" filter because
20
22
  # there is too much magic happening in slixmpp
21
23
  # anyway, we probably want to roll our own "dynamic disco"/caps
@@ -5,13 +5,15 @@ from slixmpp.exceptions import XMPPError
5
5
  from slixmpp.plugins.xep_0030.stanza.items import DiscoItems
6
6
  from slixmpp.types import OptJid
7
7
 
8
+ from .util import DispatcherMixin
9
+
8
10
  if TYPE_CHECKING:
9
- from .base import BaseGateway
11
+ from slidge.core.gateway import BaseGateway
10
12
 
11
13
 
12
- class Disco:
14
+ class DiscoMixin(DispatcherMixin):
13
15
  def __init__(self, xmpp: "BaseGateway"):
14
- self.xmpp = xmpp
16
+ super().__init__(xmpp)
15
17
 
16
18
  xmpp.plugin["xep_0030"].set_node_handler(
17
19
  "get_info",
@@ -36,15 +38,11 @@ class Disco:
36
38
  if ifrom is None:
37
39
  raise XMPPError("subscription-required")
38
40
 
39
- user = self.xmpp.store.users.get(ifrom)
40
- if user is None:
41
- raise XMPPError("registration-required")
42
- session = self.xmpp.get_session_from_user(user)
43
- await session.wait_for_ready()
41
+ assert jid is not None
42
+ session = await self._get_session_from_jid(jid=ifrom)
44
43
 
45
44
  log.debug("Looking for entity: %s", jid)
46
45
 
47
- assert jid is not None
48
46
  entity = await session.get_contact_or_group_or_participant(jid)
49
47
 
50
48
  if entity is None:
@@ -61,16 +59,12 @@ class Disco:
61
59
  if jid != self.xmpp.boundjid.bare:
62
60
  return DiscoItems()
63
61
 
64
- user = self.xmpp.store.users.get(ifrom)
65
- if user is None:
66
- raise XMPPError("registration-required")
67
-
68
- session = self.xmpp.get_session_from_user(user)
69
- await session.wait_for_ready()
62
+ assert ifrom is not None
63
+ session = await self._get_session_from_jid(ifrom)
70
64
 
71
65
  d = DiscoItems()
72
- for muc in sorted(session.bookmarks, key=lambda m: m.name):
73
- d.add_item(muc.jid, name=muc.name)
66
+ for room in self.xmpp.store.rooms.get_all_jid_and_names(session.user_pk):
67
+ d.add_item(room.jid, name=room.name)
74
68
 
75
69
  return d
76
70
 
@@ -0,0 +1,10 @@
1
+ from .chat_state import ChatStateMixin
2
+ from .marker import MarkerMixin
3
+ from .message import MessageContentMixin
4
+
5
+
6
+ class MessageMixin(ChatStateMixin, MarkerMixin, MessageContentMixin):
7
+ pass
8
+
9
+
10
+ __all__ = ("MessageMixin",)
@@ -0,0 +1,40 @@
1
+ from slixmpp import Message
2
+ from slixmpp.xmlstream import StanzaBase
3
+
4
+ from ..util import DispatcherMixin, exceptions_to_xmpp_errors
5
+
6
+
7
+ class ChatStateMixin(DispatcherMixin):
8
+ def __init__(self, xmpp) -> None:
9
+ super().__init__(xmpp)
10
+ xmpp.add_event_handler("chatstate_active", self.on_chatstate_active)
11
+ xmpp.add_event_handler("chatstate_inactive", self.on_chatstate_inactive)
12
+ xmpp.add_event_handler("chatstate_composing", self.on_chatstate_composing)
13
+ xmpp.add_event_handler("chatstate_paused", self.on_chatstate_paused)
14
+
15
+ @exceptions_to_xmpp_errors
16
+ async def on_chatstate_active(self, msg: StanzaBase) -> None:
17
+ assert isinstance(msg, Message)
18
+ if msg["body"]:
19
+ # if there is a body, it's handled in on_legacy_message()
20
+ return
21
+ session, entity, thread = await self._get_session_entity_thread(msg)
22
+ await session.on_active(entity, thread)
23
+
24
+ @exceptions_to_xmpp_errors
25
+ async def on_chatstate_inactive(self, msg: StanzaBase) -> None:
26
+ assert isinstance(msg, Message)
27
+ session, entity, thread = await self._get_session_entity_thread(msg)
28
+ await session.on_inactive(entity, thread)
29
+
30
+ @exceptions_to_xmpp_errors
31
+ async def on_chatstate_composing(self, msg: StanzaBase) -> None:
32
+ assert isinstance(msg, Message)
33
+ session, entity, thread = await self._get_session_entity_thread(msg)
34
+ await session.on_composing(entity, thread)
35
+
36
+ @exceptions_to_xmpp_errors
37
+ async def on_chatstate_paused(self, msg: StanzaBase) -> None:
38
+ assert isinstance(msg, Message)
39
+ session, entity, thread = await self._get_session_entity_thread(msg)
40
+ await session.on_paused(entity, thread)
@@ -0,0 +1,62 @@
1
+ from slixmpp import JID, Message
2
+ from slixmpp.xmlstream import StanzaBase
3
+
4
+ from ....group.room import LegacyMUC
5
+ from ....util.types import Recipient
6
+ from ..util import DispatcherMixin, _get_entity, exceptions_to_xmpp_errors
7
+
8
+
9
+ class MarkerMixin(DispatcherMixin):
10
+ def __init__(self, xmpp) -> None:
11
+ super().__init__(xmpp)
12
+ xmpp.add_event_handler("marker_displayed", self.on_marker_displayed)
13
+ xmpp.add_event_handler(
14
+ "message_displayed_synchronization_publish",
15
+ self.on_message_displayed_synchronization_publish,
16
+ )
17
+
18
+ @exceptions_to_xmpp_errors
19
+ async def on_marker_displayed(self, msg: StanzaBase) -> None:
20
+ assert isinstance(msg, Message)
21
+ session = await self._get_session(msg)
22
+
23
+ e: Recipient = await _get_entity(session, msg)
24
+ legacy_thread = await self._xmpp_to_legacy_thread(session, msg, e)
25
+ displayed_msg_id = msg["displayed"]["id"]
26
+ if not isinstance(e, LegacyMUC) and self.xmpp.MARK_ALL_MESSAGES:
27
+ to_mark = e.get_msg_xmpp_id_up_to(displayed_msg_id) # type: ignore
28
+ if to_mark is None:
29
+ session.log.debug("Can't mark all messages up to %s", displayed_msg_id)
30
+ to_mark = [displayed_msg_id]
31
+ else:
32
+ to_mark = [displayed_msg_id]
33
+ for xmpp_id in to_mark:
34
+ await session.on_displayed(
35
+ e, self._xmpp_msg_id_to_legacy(session, xmpp_id), legacy_thread
36
+ )
37
+ if isinstance(e, LegacyMUC):
38
+ await e.echo(msg, None)
39
+
40
+ @exceptions_to_xmpp_errors
41
+ async def on_message_displayed_synchronization_publish(
42
+ self, msg: StanzaBase
43
+ ) -> None:
44
+ assert isinstance(msg, Message)
45
+ chat_jid = JID(msg["pubsub_event"]["items"]["item"]["id"])
46
+ if chat_jid.server != self.xmpp.boundjid.bare:
47
+ return
48
+
49
+ session = await self._get_session(msg, timeout=None)
50
+
51
+ if chat_jid == self.xmpp.boundjid.bare:
52
+ return
53
+
54
+ chat = await session.get_contact_or_group_or_participant(chat_jid)
55
+ if not isinstance(chat, LegacyMUC):
56
+ session.log.debug("Ignoring non-groupchat MDS event")
57
+ return
58
+
59
+ stanza_id = msg["pubsub_event"]["items"]["item"]["displayed"]["stanza_id"]["id"]
60
+ await session.on_displayed(
61
+ chat, self._xmpp_msg_id_to_legacy(session, stanza_id)
62
+ )