slidge 0.3.0b1__tar.gz → 0.3.0b2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. {slidge-0.3.0b1 → slidge-0.3.0b2}/PKG-INFO +1 -1
  2. {slidge-0.3.0b1 → slidge-0.3.0b2}/pyproject.toml +0 -1
  3. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/contact/roster.py +2 -0
  4. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/message/message.py +3 -1
  5. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/presence.py +5 -0
  6. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/avatar.py +7 -19
  7. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/session.py +2 -2
  8. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/group/room.py +37 -27
  9. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/main.py +6 -4
  10. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/conf.py +4 -1
  11. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge.egg-info/PKG-INFO +1 -1
  12. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_config.py +12 -0
  13. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_session.py +3 -2
  14. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_session_2.py +127 -1
  15. {slidge-0.3.0b1 → slidge-0.3.0b2}/.gitignore +0 -0
  16. {slidge-0.3.0b1 → slidge-0.3.0b2}/.pre-commit-config.yaml +0 -0
  17. {slidge-0.3.0b1 → slidge-0.3.0b2}/.woodpecker/container-ci.yaml +0 -0
  18. {slidge-0.3.0b1 → slidge-0.3.0b2}/.woodpecker/docs.yaml +0 -0
  19. {slidge-0.3.0b1 → slidge-0.3.0b2}/.woodpecker/package.yaml +0 -0
  20. {slidge-0.3.0b1 → slidge-0.3.0b2}/.woodpecker/test.yaml +0 -0
  21. {slidge-0.3.0b1 → slidge-0.3.0b2}/Dockerfile +0 -0
  22. {slidge-0.3.0b1 → slidge-0.3.0b2}/LICENSE +0 -0
  23. {slidge-0.3.0b1 → slidge-0.3.0b2}/README.md +0 -0
  24. {slidge-0.3.0b1 → slidge-0.3.0b2}/commitlint.config.js +0 -0
  25. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/assets/5x5.png +0 -0
  26. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/assets/slidge-color-small.png +0 -0
  27. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/assets/slidge-color.png +0 -0
  28. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/assets/slidge-mono-black.png +0 -0
  29. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/assets/slidge-mono-white.png +0 -0
  30. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/assets/slidge.svg +0 -0
  31. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/confs/movim.env +0 -0
  32. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/confs/nginx.conf +0 -0
  33. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/confs/slidge-dev.ini +0 -0
  34. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/confs/slidge-example.ini +0 -0
  35. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/hot-reload.sh +0 -0
  36. {slidge-0.3.0b1 → slidge-0.3.0b2}/dev/prettify_tests.py +0 -0
  37. {slidge-0.3.0b1 → slidge-0.3.0b2}/doap.xml +0 -0
  38. {slidge-0.3.0b1 → slidge-0.3.0b2}/docker-compose.yml +0 -0
  39. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/Makefile +0 -0
  40. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/attachments.rst +0 -0
  41. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/component.rst +0 -0
  42. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/config/index.rst +0 -0
  43. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/daemon.rst +0 -0
  44. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/examples/ejabberd.yaml +0 -0
  45. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/examples/index.rst +0 -0
  46. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/examples/prosody.cfg.lua +0 -0
  47. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/index.rst +0 -0
  48. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/install.rst +0 -0
  49. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/note.rst +0 -0
  50. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/admin/privilege.rst +0 -0
  51. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/codeberg.svg +0 -0
  52. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/conf.py +0 -0
  53. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/dev/contributing.rst +0 -0
  54. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/dev/design.rst +0 -0
  55. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/dev/howto.rst +0 -0
  56. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/dev/index.rst +0 -0
  57. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/dev/tutorial.rst +0 -0
  58. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/glossary.rst +0 -0
  59. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/index.rst +0 -0
  60. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/commands.rst +0 -0
  61. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/contacts.rst +0 -0
  62. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/foxyproxy.png +0 -0
  63. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/gajim.png +0 -0
  64. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/index.rst +0 -0
  65. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/low_profile.rst +0 -0
  66. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/movim1.png +0 -0
  67. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/movim2.png +0 -0
  68. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/note.rst +0 -0
  69. {slidge-0.3.0b1 → slidge-0.3.0b2}/docs/source/user/register.rst +0 -0
  70. {slidge-0.3.0b1 → slidge-0.3.0b2}/setup.cfg +0 -0
  71. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/__init__.py +0 -0
  72. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/__main__.py +0 -0
  73. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/__init__.py +0 -0
  74. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/adhoc.py +0 -0
  75. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/admin.py +0 -0
  76. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/base.py +0 -0
  77. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/categories.py +0 -0
  78. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/chat_command.py +0 -0
  79. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/register.py +0 -0
  80. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/command/user.py +0 -0
  81. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/contact/__init__.py +0 -0
  82. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/contact/contact.py +0 -0
  83. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/__init__.py +0 -0
  84. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/config.py +0 -0
  85. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/__init__.py +0 -0
  86. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/caps.py +0 -0
  87. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/disco.py +0 -0
  88. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/message/__init__.py +0 -0
  89. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/message/chat_state.py +0 -0
  90. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/message/marker.py +0 -0
  91. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/muc/__init__.py +0 -0
  92. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/muc/admin.py +0 -0
  93. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/muc/mam.py +0 -0
  94. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/muc/misc.py +0 -0
  95. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/muc/owner.py +0 -0
  96. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/muc/ping.py +0 -0
  97. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/registration.py +0 -0
  98. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/search.py +0 -0
  99. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/session_dispatcher.py +0 -0
  100. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/util.py +0 -0
  101. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/dispatcher/vcard.py +0 -0
  102. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/gateway.py +0 -0
  103. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/__init__.py +0 -0
  104. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/attachment.py +0 -0
  105. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/base.py +0 -0
  106. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/db.py +0 -0
  107. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/disco.py +0 -0
  108. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/message.py +0 -0
  109. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/message_maker.py +0 -0
  110. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/message_text.py +0 -0
  111. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/presence.py +0 -0
  112. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/mixins/recipient.py +0 -0
  113. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/core/pubsub.py +0 -0
  114. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/__init__.py +0 -0
  115. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/alembic/__init__.py +0 -0
  116. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/alembic/env.py +0 -0
  117. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/alembic/script.py.mako +0 -0
  118. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/alembic/versions/cef02a8b1451_initial_schema.py +0 -0
  119. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/avatar.py +0 -0
  120. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/meta.py +0 -0
  121. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/models.py +0 -0
  122. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/db/store.py +0 -0
  123. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/group/__init__.py +0 -0
  124. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/group/archive.py +0 -0
  125. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/group/bookmarks.py +0 -0
  126. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/group/participant.py +0 -0
  127. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/migration.py +0 -0
  128. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/py.typed +0 -0
  129. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/__init__.py +0 -0
  130. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/delivery_receipt.py +0 -0
  131. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/link_preview/__init__.py +0 -0
  132. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/link_preview/link_preview.py +0 -0
  133. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/link_preview/stanza.py +0 -0
  134. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/roster.py +0 -0
  135. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0077/__init__.py +0 -0
  136. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0077/register.py +0 -0
  137. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0077/stanza.py +0 -0
  138. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0100/__init__.py +0 -0
  139. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0100/gateway.py +0 -0
  140. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0100/stanza.py +0 -0
  141. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0153/__init__.py +0 -0
  142. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0153/vcard_avatar.py +0 -0
  143. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0292/__init__.py +0 -0
  144. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/slixfix/xep_0292/vcard4.py +0 -0
  145. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/__init__.py +0 -0
  146. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/archive_msg.py +0 -0
  147. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/jid_escaping.py +0 -0
  148. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/lock.py +0 -0
  149. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/test.py +0 -0
  150. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/types.py +0 -0
  151. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge/util/util.py +0 -0
  152. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge.egg-info/SOURCES.txt +0 -0
  153. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge.egg-info/dependency_links.txt +0 -0
  154. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge.egg-info/entry_points.txt +0 -0
  155. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge.egg-info/requires.txt +0 -0
  156. {slidge-0.3.0b1 → slidge-0.3.0b2}/slidge.egg-info/top_level.txt +0 -0
  157. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/__init__.py +0 -0
  158. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/__main__.py +0 -0
  159. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/contact.py +0 -0
  160. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/gateway.py +0 -0
  161. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/group.py +0 -0
  162. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/legacy_client.py +0 -0
  163. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/session.py +0 -0
  164. {slidge-0.3.0b1 → slidge-0.3.0b2}/superduper/util.py +0 -0
  165. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/conftest.py +0 -0
  166. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_adhoc/test_access.py +0 -0
  167. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_adhoc/test_confirmation.py +0 -0
  168. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_adhoc/test_form.py +0 -0
  169. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_adhoc/test_reported.py +0 -0
  170. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_attachment.py +0 -0
  171. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_avatar.py +0 -0
  172. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_backfill.py +0 -0
  173. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_chat_commands.py +0 -0
  174. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_db/test_store.py +0 -0
  175. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_db/test_user.py +0 -0
  176. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_feature_restriction.py +0 -0
  177. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_mam_archivable.py +0 -0
  178. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_mds.py +0 -0
  179. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_muc.py +0 -0
  180. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_resourceprep.py +0 -0
  181. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_set_name_before_fill.py +0 -0
  182. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_shakespeare.py +0 -0
  183. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_stanza_link_preview.py +0 -0
  184. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_util.py +0 -0
  185. {slidge-0.3.0b1 → slidge-0.3.0b2}/tests/test_vcard.py +0 -0
  186. {slidge-0.3.0b1 → slidge-0.3.0b2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: slidge
3
- Version: 0.3.0b1
3
+ Version: 0.3.0b2
4
4
  Summary: XMPP bridging framework
5
5
  Author-email: Nicolas Cedilnik <nicoco@nicoco.fr>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -99,7 +99,6 @@ exclude_lines = [
99
99
  ]
100
100
 
101
101
  [tool.pytest.ini_options]
102
- log_level = "DEBUG"
103
102
  asyncio_mode = "strict"
104
103
  filterwarnings = [
105
104
  "ignore:The object should be created within an async function:DeprecationWarning:aiohttp",
@@ -95,6 +95,8 @@ class LegacyRoster(
95
95
  contact_jid = JID(contact_jid.bare)
96
96
  async with self.lock(("username", username)):
97
97
  legacy_id = await self.jid_username_to_legacy_id(username)
98
+ if legacy_id == self.user_legacy_id:
99
+ raise ContactIsUser
98
100
  if self.get_lock(("legacy_id", legacy_id)):
99
101
  self.log.debug("Already updating %s via by_legacy_id()", contact_jid)
100
102
  return await self.by_legacy_id(legacy_id)
@@ -415,7 +415,9 @@ class MessageContentMixin(DispatcherMixin):
415
415
  with self.xmpp.store.session() as orm:
416
416
  sticker = self.xmpp.store.bob.get_sticker(orm, cid)
417
417
  if sticker is None:
418
- await self.xmpp.plugin["xep_0231"].get_bob(from_, cid)
418
+ await self.xmpp.plugin["xep_0231"].get_bob(
419
+ from_, cid, ifrom=self.xmpp.boundjid
420
+ )
419
421
  with self.xmpp.store.session() as orm:
420
422
  sticker = self.xmpp.store.bob.get_sticker(orm, cid)
421
423
  assert sticker is not None
@@ -3,6 +3,7 @@ import logging
3
3
  from slixmpp import JID, Presence
4
4
  from slixmpp.exceptions import XMPPError
5
5
 
6
+ from ...contact.roster import ContactIsUser
6
7
  from ...util.util import merge_resources
7
8
  from ..session import BaseSession
8
9
  from .util import DispatcherMixin, exceptions_to_xmpp_errors
@@ -142,6 +143,10 @@ class PresenceHandlerMixin(DispatcherMixin):
142
143
  contact = await session.contacts.by_jid(pto)
143
144
  except XMPPError:
144
145
  contact = None
146
+ except ContactIsUser:
147
+ raise XMPPError(
148
+ "bad-request", "Actions with yourself are not supported."
149
+ )
145
150
  if contact is not None:
146
151
  await self.xmpp.pubsub.on_presence_available(p, contact)
147
152
  return
@@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Optional
4
4
 
5
5
  from PIL import UnidentifiedImageError
6
6
  from slixmpp import JID
7
- from sqlalchemy.exc import IntegrityError
8
7
  from sqlalchemy.orm.exc import DetachedInstanceError
9
8
 
10
9
  from ...db.avatar import CachedAvatar, avatar_cache
@@ -124,25 +123,14 @@ class AvatarMixin(UpdateInfoMixin):
124
123
  avatar.path.unlink()
125
124
 
126
125
  stored_avatar = None if cached_avatar is None else cached_avatar.stored
127
- self.stored.avatar = stored_avatar
128
-
129
- try:
130
- self.commit(merge=True)
131
- except IntegrityError as e:
132
- with self.xmpp.store.session(expire_on_commit=False) as orm:
133
- if orm.object_session(self.stored):
134
- self.log.debug(
135
- "Hit integrity error, attempting to fix by refreshing participants"
136
- )
137
- orm.refresh(self.stored, ["participants"])
138
- else:
139
- self.log.debug(
140
- "Hit integrity error, attempting to fix by merging contact.stored"
141
- )
126
+ if not self._updating_info:
127
+ with self.xmpp.store.session() as orm:
128
+ with orm.no_autoflush:
142
129
  self.stored = orm.merge(self.stored)
143
- self.stored.avatar = stored_avatar
144
- orm.add(self.stored)
145
- orm.commit()
130
+ orm.refresh(self.stored)
131
+
132
+ self.stored.avatar = stored_avatar
133
+ self.commit(merge=True)
146
134
 
147
135
  self._post_avatar_update(cached_avatar)
148
136
 
@@ -133,8 +133,8 @@ class BaseSession(
133
133
  self.log.debug("Removing fut %s", fut)
134
134
  self.__tasks.remove(fut)
135
135
 
136
- def create_task(self, coro) -> asyncio.Task:
137
- task = self.xmpp.loop.create_task(coro)
136
+ def create_task(self, coro, name: str | None = None) -> asyncio.Task:
137
+ task = self.xmpp.loop.create_task(coro, name=name)
138
138
  self.__tasks.add(task)
139
139
  self.log.debug("Creating task %s", task)
140
140
  task.add_done_callback(lambda _: self.__remove_task(task))
@@ -3,6 +3,8 @@ import logging
3
3
  import re
4
4
  import string
5
5
  import warnings
6
+ from asyncio import Lock
7
+ from contextlib import asynccontextmanager
6
8
  from copy import copy
7
9
  from datetime import datetime, timedelta, timezone
8
10
  from typing import TYPE_CHECKING, AsyncIterator, Generic, Optional, Type, Union
@@ -18,7 +20,6 @@ from slixmpp.plugins.xep_0469.stanza import NS as PINNING_NS
18
20
  from slixmpp.plugins.xep_0492.stanza import NS as NOTIFY_NS
19
21
  from slixmpp.plugins.xep_0492.stanza import WhenLiteral
20
22
  from slixmpp.xmlstream import ET
21
- from sqlalchemy.exc import InvalidRequestError
22
23
  from sqlalchemy.orm import Session as OrmSession
23
24
 
24
25
  from ..contact.contact import LegacyContact
@@ -28,7 +29,6 @@ from ..core.mixins.disco import ChatterDiscoMixin
28
29
  from ..core.mixins.recipient import ReactionRecipientMixin, ThreadRecipientMixin
29
30
  from ..db.models import Participant, Room
30
31
  from ..util.jid_escaping import unescape_node
31
- from ..util.lock import NamedLockMixin
32
32
  from ..util.types import (
33
33
  HoleBound,
34
34
  LegacyGroupIdType,
@@ -56,7 +56,6 @@ class LegacyMUC(
56
56
  LegacyGroupIdType, LegacyMessageType, LegacyParticipantType, LegacyUserIdType
57
57
  ],
58
58
  AvatarMixin,
59
- NamedLockMixin,
60
59
  ChatterDiscoMixin,
61
60
  ReactionRecipientMixin,
62
61
  ThreadRecipientMixin,
@@ -242,10 +241,22 @@ class LegacyMUC(
242
241
  )
243
242
  self.commit()
244
243
 
244
+ @asynccontextmanager
245
+ async def lock(self, id_: str) -> AsyncIterator[None]:
246
+ async with self.session.lock((self.legacy_id, id_)):
247
+ yield
248
+
249
+ def get_lock(self, id_: str) -> Lock | None:
250
+ return self.session.get_lock((self.legacy_id, id_))
251
+
245
252
  async def __fill_participants(self) -> None:
246
- if self.participants_filled:
247
- return
248
253
  async with self.lock("fill participants"):
254
+ with self.xmpp.store.session(expire_on_commit=False) as orm:
255
+ orm.add(self.stored)
256
+ with orm.no_autoflush:
257
+ orm.refresh(self.stored, ["participants_filled"])
258
+ if self.participants_filled:
259
+ return
249
260
  parts: list[Participant] = []
250
261
  resources = set[str]()
251
262
  # During fill_participants(), self.get_participant*() methods may
@@ -261,17 +272,13 @@ class LegacyMUC(
261
272
  resources.add(participant.stored.resource)
262
273
  with self.xmpp.store.session(expire_on_commit=False) as orm:
263
274
  orm.add(self.stored)
264
- # because self.participants() is async, self.stored may be out of sync at
265
- # this point.
275
+ # because self.fill_participants() is async, self.stored may be stale at
276
+ # this point, and the only thing we want to update is the participant list
277
+ # and the participant_filled attribute.
266
278
  with orm.no_autoflush:
267
279
  orm.refresh(self.stored)
268
- for part in parts:
269
- try:
270
- self.stored.participants.append(part)
271
- except InvalidRequestError:
272
- # the participant was already stored in the DB. `part` may even
273
- # be out-of-sync, so it's fine to just ditch it.
274
- pass
280
+ for part in parts:
281
+ orm.merge(part)
275
282
  self.stored.participants_filled = True
276
283
  orm.commit()
277
284
 
@@ -290,10 +297,14 @@ class LegacyMUC(
290
297
  yield self.participant_from_store(db_participant)
291
298
 
292
299
  async def __fill_history(self) -> None:
293
- if self.stored.history_filled:
294
- self.log.debug("History has already been fetched.")
295
- return
296
300
  async with self.lock("fill history"):
301
+ with self.xmpp.store.session(expire_on_commit=False) as orm:
302
+ orm.add(self.stored)
303
+ with orm.no_autoflush:
304
+ orm.refresh(self.stored, ["history_filled"])
305
+ if self.stored.history_filled:
306
+ self.log.debug("History has already been fetched.")
307
+ return
297
308
  log.debug("Fetching history for %s", self)
298
309
  try:
299
310
  before, after = self.archive.get_hole_bounds()
@@ -767,16 +778,15 @@ class LegacyMUC(
767
778
  """
768
779
  await self.session.contacts.ready
769
780
 
770
- if not self.get_lock("fill participants"):
771
- with self.xmpp.store.session() as orm:
772
- self.stored = orm.merge(self.stored)
773
- stored = (
774
- orm.query(Participant)
775
- .filter_by(contact=c.stored, room=self.stored)
776
- .one_or_none()
777
- )
778
- if stored is not None:
779
- return self.participant_from_store(stored=stored, contact=c)
781
+ with self.xmpp.store.session() as orm:
782
+ self.stored = orm.merge(self.stored)
783
+ stored = (
784
+ orm.query(Participant)
785
+ .filter_by(contact=c.stored, room=self.stored)
786
+ .one_or_none()
787
+ )
788
+ if stored is not None:
789
+ return self.participant_from_store(stored=stored, contact=c)
780
790
 
781
791
  nickname = c.name or unescape_node(c.jid.node)
782
792
 
@@ -166,10 +166,12 @@ def main(module_name: str | None = None) -> None:
166
166
  f"_{config.LEGACY_MODULE.split('.')[-1].upper()}_"
167
167
  )
168
168
  logging.debug("Env var prefix: %s", ConfigModule.ENV_VAR_PREFIX)
169
- ConfigModule(plugin_config_obj).set_conf(unknown_argv)
170
- else:
171
- if unknown_argv:
172
- raise RuntimeError("Some arguments have not been recognized", unknown_argv)
169
+ _, unknown_argv = ConfigModule(plugin_config_obj).set_conf(unknown_argv)
170
+
171
+ if unknown_argv:
172
+ logging.error(
173
+ f"These config options have not been recognized and ignored: {unknown_argv}"
174
+ )
173
175
 
174
176
  migrate()
175
177
 
@@ -159,7 +159,10 @@ class ConfigModule:
159
159
  upper = _argv_to_option_name(a)
160
160
  opt = options_long.get(upper)
161
161
  if opt and opt.type is bool:
162
- if _argv_to_option_name(aa) not in options_long:
162
+ if (
163
+ not aa.startswith("-")
164
+ and _argv_to_option_name(aa) not in options_long
165
+ ):
163
166
  log.debug("Removing %s from argv", aa)
164
167
  skip_next = True
165
168
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: slidge
3
- Version: 0.3.0b1
3
+ Version: 0.3.0b2
4
4
  Summary: XMPP bridging framework
5
5
  Author-email: Nicolas Cedilnik <nicoco@nicoco.fr>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -272,3 +272,15 @@ def test_rest(tmp_path):
272
272
 
273
273
  assert Config1.PROUT == "caca"
274
274
  assert Config2.PROUT2 == "something"
275
+
276
+
277
+ def test_unrecognized_after_boolean():
278
+ class Config:
279
+ PROUT = True
280
+ PROUT__DOC = "?"
281
+
282
+
283
+ configurator = ConfigModule(Config)
284
+ ns, rest = configurator.set_conf(["--prout", "--joujoujou"])
285
+ assert Config.PROUT
286
+ assert rest == ["--joujoujou"]
@@ -328,10 +328,11 @@ class TestSession(AvatarFixtureMixin, SlidgeTest):
328
328
  """
329
329
  self.recv(sticker_stanza)
330
330
  self.send( # language=XML
331
- """
331
+ f"""
332
332
  <iq id="2"
333
333
  type="get"
334
- to="romeo@montague.lit/movim">
334
+ to="romeo@montague.lit/movim"
335
+ from="{self.xmpp.boundjid.bare}">
335
336
  <data xmlns="urn:xmpp:bob"
336
337
  cid="sha1+4b97ce7f0f06a0e05999f3c719cd5b4f3da992a7@bob.xmpp.org" />
337
338
  </iq>
@@ -43,7 +43,10 @@ class Contact(LegacyContact):
43
43
 
44
44
  class MUC(LegacyMUC):
45
45
  async def update_info(self):
46
- if self.legacy_id in ("room-noinfo", "room-duplicate-participant"):
46
+ if self.legacy_id in ("room-noinfo", "room-duplicate-participant", "room-avatar-slow", "room-contact-conflict"):
47
+ return
48
+ if self.legacy_id == "room-avatar-in-slow-task":
49
+ self.session.create_task(self._slow_set_avatar(), "slow-avatar")
47
50
  return
48
51
  self.name = "Cool name"
49
52
  self.description = "Cool description"
@@ -68,6 +71,12 @@ class MUC(LegacyMUC):
68
71
  if "duplicate-participant" in self.legacy_id:
69
72
  yield await self.get_participant_by_legacy_id("duplicate")
70
73
  yield await self.get_participant_by_legacy_id("duplicate")
74
+ if "contact-conflict" in self.legacy_id:
75
+ yield await self.get_participant_by_legacy_id("contact-conflict")
76
+
77
+ async def _slow_set_avatar(self):
78
+ await asyncio.sleep(1)
79
+ await self.set_avatar("AVATAR_URL")
71
80
 
72
81
  class Bookmarks(LegacyBookmarks):
73
82
  async def fill(self):
@@ -376,3 +385,120 @@ class TestSession2(AvatarFixtureMixin, SlidgeTest):
376
385
  )
377
386
  assert self.next_sent().get_from().resource == "duplicate"
378
387
  assert self.next_sent().get_from().resource == muc.user_nick
388
+
389
+ def test_presence_to_user_account(self):
390
+ self.romeo_session.contacts.user_legacy_id = "user-id"
391
+ self.recv( # language=XML
392
+ """
393
+ <presence from="romeo@montague.lit/movim"
394
+ to="user-id@aim.shakespeare.lit" />
395
+ """
396
+ )
397
+ self.send( # language=XML
398
+ """
399
+ <presence from="user-id@aim.shakespeare.lit"
400
+ to="romeo@montague.lit/movim"
401
+ type="error">
402
+ <error type="modify">
403
+ <bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
404
+ <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Actions with yourself are not supported.</text>
405
+ </error>
406
+ </presence>
407
+ """
408
+ )
409
+
410
+ def test_slow_avatar_in_task(self):
411
+ muc: LegacyMUC = self.run_coro(
412
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-in-slow-task")
413
+ )
414
+ assert not muc.participants_filled
415
+ assert self.next_sent() is None
416
+ muc: LegacyMUC = self.run_coro(
417
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-in-slow-task")
418
+ )
419
+ assert not muc.participants_filled
420
+ assert self.next_sent() is None
421
+ self.recv( # language=XML
422
+ f"""
423
+ <presence from="romeo@montague.lit/movim"
424
+ to="{muc.jid}/nick">
425
+ <x xmlns='http://jabber.org/protocol/muc' />
426
+ </presence>
427
+ """
428
+ )
429
+ self.next_sent()
430
+ muc = self.run_coro(
431
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-in-slow-task")
432
+ )
433
+ assert muc.participants_filled
434
+ for task in self.romeo_session._BaseSession__tasks:
435
+ task: asyncio.Task
436
+ if task.get_name() == "slow-avatar":
437
+ self.run_coro(asyncio.wait_for(task, 2))
438
+ break
439
+ else:
440
+ assert False
441
+ muc = self.run_coro(
442
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-in-slow-task")
443
+ )
444
+ assert muc.participants_filled
445
+
446
+ def test_slow_avatar(self):
447
+ muc: LegacyMUC = self.run_coro(
448
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-slow")
449
+ )
450
+ assert not muc.participants_filled
451
+ assert self.next_sent() is None
452
+ muc: LegacyMUC = self.run_coro(
453
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-slow")
454
+ )
455
+ muc.avatar = "SLOW"
456
+ assert not muc.participants_filled
457
+ assert self.next_sent() is None
458
+ self.recv( # language=XML
459
+ f"""
460
+ <presence from="romeo@montague.lit/movim"
461
+ to="{muc.jid}/nick">
462
+ <x xmlns='http://jabber.org/protocol/muc' />
463
+ </presence>
464
+ """
465
+ )
466
+ self.next_sent()
467
+ muc2 = self.run_coro(
468
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-slow")
469
+ )
470
+ assert muc2.participants_filled
471
+
472
+ self.run_coro(asyncio.wait_for(muc._set_avatar_task, 2))
473
+ muc = self.run_coro(
474
+ self.romeo_session.bookmarks.by_legacy_id("room-avatar-slow")
475
+ )
476
+ assert muc.participants_filled
477
+
478
+ def test_live_message_then_fill_participants(self):
479
+ muc: LegacyMUC = self.run_coro(
480
+ self.romeo_session.bookmarks.by_legacy_id("room-contact-conflict")
481
+ )
482
+ part = self.run_coro(muc.get_participant_by_legacy_id("contact-conflict"))
483
+ part.send_text("some text")
484
+ self.recv( # language=XML
485
+ f"""
486
+ <presence from="romeo@montague.lit/movim"
487
+ to="{muc.jid}/nick">
488
+ <x xmlns='http://jabber.org/protocol/muc' />
489
+ </presence>
490
+ """
491
+ )
492
+ self.send( # language=XML
493
+ """
494
+ <presence from="room-contact-conflict@aim.shakespeare.lit/contact-conflict"
495
+ to="romeo@montague.lit/movim">
496
+ <x xmlns="http://jabber.org/protocol/muc#user">
497
+ <item affiliation="member"
498
+ role="participant" />
499
+ </x>
500
+ <occupant-id xmlns="urn:xmpp:occupant-id:0"
501
+ id="contact-conflict@aim.shakespeare.lit/slidge" />
502
+ </presence>
503
+ """
504
+ )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes