slidge 0.3.0b1__tar.gz → 0.3.0b3__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.
- {slidge-0.3.0b1 → slidge-0.3.0b3}/PKG-INFO +1 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/examples/ejabberd.yaml +5 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/privilege.rst +6 -6
- {slidge-0.3.0b1 → slidge-0.3.0b3}/pyproject.toml +0 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/contact/roster.py +2 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/message/message.py +3 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/presence.py +5 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/attachment.py +4 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/avatar.py +7 -19
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/base.py +1 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/disco.py +1 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/session.py +2 -2
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/store.py +1 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/group/bookmarks.py +21 -3
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/group/room.py +73 -36
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/main.py +6 -4
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/conf.py +4 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/types.py +2 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge.egg-info/PKG-INFO +1 -1
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_attachment.py +22 -9
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_config.py +12 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_muc.py +1 -3
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_session.py +3 -2
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_session_2.py +207 -3
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_shakespeare.py +1 -2
- {slidge-0.3.0b1 → slidge-0.3.0b3}/.gitignore +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/.pre-commit-config.yaml +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/.woodpecker/container-ci.yaml +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/.woodpecker/docs.yaml +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/.woodpecker/package.yaml +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/.woodpecker/test.yaml +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/Dockerfile +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/LICENSE +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/README.md +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/commitlint.config.js +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/assets/5x5.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/assets/slidge-color-small.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/assets/slidge-color.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/assets/slidge-mono-black.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/assets/slidge-mono-white.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/assets/slidge.svg +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/confs/movim.env +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/confs/nginx.conf +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/confs/slidge-dev.ini +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/confs/slidge-example.ini +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/hot-reload.sh +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/dev/prettify_tests.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/doap.xml +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docker-compose.yml +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/Makefile +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/attachments.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/component.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/config/index.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/daemon.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/examples/index.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/examples/prosody.cfg.lua +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/index.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/install.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/admin/note.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/codeberg.svg +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/conf.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/dev/contributing.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/dev/design.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/dev/howto.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/dev/index.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/dev/tutorial.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/glossary.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/index.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/commands.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/contacts.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/foxyproxy.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/gajim.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/index.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/low_profile.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/movim1.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/movim2.png +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/note.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/docs/source/user/register.rst +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/setup.cfg +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/__main__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/adhoc.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/admin.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/base.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/categories.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/chat_command.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/register.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/command/user.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/contact/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/contact/contact.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/config.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/caps.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/disco.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/message/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/message/chat_state.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/message/marker.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/muc/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/muc/admin.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/muc/mam.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/muc/misc.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/muc/owner.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/muc/ping.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/registration.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/search.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/session_dispatcher.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/util.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/dispatcher/vcard.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/gateway.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/db.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/message.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/message_maker.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/message_text.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/presence.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/mixins/recipient.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/core/pubsub.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/alembic/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/alembic/env.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/alembic/script.py.mako +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/alembic/versions/cef02a8b1451_initial_schema.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/avatar.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/meta.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/db/models.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/group/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/group/archive.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/group/participant.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/migration.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/py.typed +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/delivery_receipt.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/link_preview/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/link_preview/link_preview.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/link_preview/stanza.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/roster.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0077/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0077/register.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0077/stanza.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0100/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0100/gateway.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0100/stanza.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0153/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0153/vcard_avatar.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0292/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/slixfix/xep_0292/vcard4.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/archive_msg.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/jid_escaping.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/lock.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/test.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge/util/util.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge.egg-info/SOURCES.txt +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge.egg-info/dependency_links.txt +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge.egg-info/entry_points.txt +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge.egg-info/requires.txt +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/slidge.egg-info/top_level.txt +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/__init__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/__main__.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/contact.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/gateway.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/group.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/legacy_client.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/session.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/superduper/util.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/conftest.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_adhoc/test_access.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_adhoc/test_confirmation.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_adhoc/test_form.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_adhoc/test_reported.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_avatar.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_backfill.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_chat_commands.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_db/test_store.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_db/test_user.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_feature_restriction.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_mam_archivable.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_mds.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_resourceprep.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_set_name_before_fill.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_stanza_link_preview.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_util.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/tests/test_vcard.py +0 -0
- {slidge-0.3.0b1 → slidge-0.3.0b3}/uv.lock +0 -0
@@ -60,12 +60,6 @@ for all changes to be taken into account
|
|
60
60
|
Privileges with ejabberd
|
61
61
|
------------------------
|
62
62
|
|
63
|
-
.. warning::
|
64
|
-
|
65
|
-
If you want to set up privileges, you need ejabberd with version 23.10 or newer because of these two issues:
|
66
|
-
https://github.com/processone/ejabberd/issues/3990 and
|
67
|
-
https://github.com/processone/ejabberd/issues/3942
|
68
|
-
|
69
63
|
.. code-block:: yaml
|
70
64
|
|
71
65
|
acl:
|
@@ -87,3 +81,9 @@ Privileges with ejabberd
|
|
87
81
|
outgoing: slidge_rule
|
88
82
|
mod_roster:
|
89
83
|
versioning: true
|
84
|
+
|
85
|
+
iq:
|
86
|
+
"http://jabber.org/protocol/pubsub":
|
87
|
+
both: slidge_rule
|
88
|
+
"http://jabber.org/protocol/pubsub#owner":
|
89
|
+
set: slidge_rule
|
@@ -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(
|
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
|
@@ -303,6 +303,10 @@ class AttachmentMixin(TextMessageMixin):
|
|
303
303
|
)
|
304
304
|
if attachment.name:
|
305
305
|
sfs["file"]["name"] = attachment.name
|
306
|
+
if attachment.disposition:
|
307
|
+
sfs["disposition"] = attachment.disposition
|
308
|
+
else:
|
309
|
+
del sfs["disposition"]
|
306
310
|
if thumbnail is not None:
|
307
311
|
sfs["file"].append(thumbnail)
|
308
312
|
stored.sfs = str(sfs)
|
@@ -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.
|
128
|
-
|
129
|
-
|
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
|
144
|
-
|
145
|
-
|
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
|
|
@@ -13,7 +13,7 @@ class BaseDiscoMixin(Base):
|
|
13
13
|
DISCO_NAME: str = NotImplemented
|
14
14
|
DISCO_LANG = None
|
15
15
|
|
16
|
-
def _get_disco_name(self):
|
16
|
+
def _get_disco_name(self) -> str | None:
|
17
17
|
if self.DISCO_NAME is NotImplemented:
|
18
18
|
return self.xmpp.COMPONENT_NAME
|
19
19
|
return self.DISCO_NAME or self.xmpp.COMPONENT_NAME
|
@@ -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))
|
@@ -478,7 +478,7 @@ class ParticipantStore:
|
|
478
478
|
|
479
479
|
@staticmethod
|
480
480
|
def get_all(
|
481
|
-
session, room_pk: int, user_included: bool = True
|
481
|
+
session: Session, room_pk: int, user_included: bool = True
|
482
482
|
) -> Iterator[Participant]:
|
483
483
|
query = select(Participant).where(Participant.room_id == room_pk)
|
484
484
|
if not user_included:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import abc
|
2
2
|
import logging
|
3
|
-
from typing import TYPE_CHECKING, Generic, Iterator, Optional, Type
|
3
|
+
from typing import TYPE_CHECKING, Generic, Iterator, Literal, Optional, Type, overload
|
4
4
|
|
5
5
|
from slixmpp import JID
|
6
6
|
from slixmpp.exceptions import XMPPError
|
@@ -119,13 +119,31 @@ class LegacyBookmarks(
|
|
119
119
|
return self.from_store(stored)
|
120
120
|
return None
|
121
121
|
|
122
|
-
|
122
|
+
@overload
|
123
|
+
async def by_legacy_id(self, legacy_id: LegacyGroupIdType) -> "LegacyMUCType": ...
|
124
|
+
|
125
|
+
@overload
|
126
|
+
async def by_legacy_id(
|
127
|
+
self, legacy_id: LegacyGroupIdType, create: Literal[False]
|
128
|
+
) -> "LegacyMUCType | None": ...
|
129
|
+
|
130
|
+
@overload
|
131
|
+
async def by_legacy_id(
|
132
|
+
self, legacy_id: LegacyGroupIdType, create: Literal[True]
|
133
|
+
) -> "LegacyMUCType": ...
|
134
|
+
|
135
|
+
async def by_legacy_id(
|
136
|
+
self, legacy_id: LegacyGroupIdType, create: bool = False
|
137
|
+
) -> LegacyMUCType | None:
|
123
138
|
async with self.lock(("legacy_id", legacy_id)):
|
124
139
|
local = await self.legacy_id_to_jid_local_part(legacy_id)
|
125
140
|
jid = JID(f"{local}@{self.xmpp.boundjid}")
|
126
141
|
if self.get_lock(("bare", jid.bare)):
|
127
142
|
self.session.log.debug("Already updating %s via by_jid()", jid)
|
128
|
-
|
143
|
+
if create:
|
144
|
+
return await self.by_jid(jid)
|
145
|
+
else:
|
146
|
+
return self.by_jid_only_if_exists(jid)
|
129
147
|
|
130
148
|
with self.xmpp.store.session() as orm:
|
131
149
|
stored = (
|
@@ -3,9 +3,20 @@ 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
|
-
from typing import
|
10
|
+
from typing import (
|
11
|
+
TYPE_CHECKING,
|
12
|
+
AsyncIterator,
|
13
|
+
Generic,
|
14
|
+
Literal,
|
15
|
+
Optional,
|
16
|
+
Type,
|
17
|
+
Union,
|
18
|
+
overload,
|
19
|
+
)
|
9
20
|
from uuid import uuid4
|
10
21
|
|
11
22
|
import sqlalchemy as sa
|
@@ -18,7 +29,6 @@ from slixmpp.plugins.xep_0469.stanza import NS as PINNING_NS
|
|
18
29
|
from slixmpp.plugins.xep_0492.stanza import NS as NOTIFY_NS
|
19
30
|
from slixmpp.plugins.xep_0492.stanza import WhenLiteral
|
20
31
|
from slixmpp.xmlstream import ET
|
21
|
-
from sqlalchemy.exc import InvalidRequestError
|
22
32
|
from sqlalchemy.orm import Session as OrmSession
|
23
33
|
|
24
34
|
from ..contact.contact import LegacyContact
|
@@ -28,7 +38,6 @@ from ..core.mixins.disco import ChatterDiscoMixin
|
|
28
38
|
from ..core.mixins.recipient import ReactionRecipientMixin, ThreadRecipientMixin
|
29
39
|
from ..db.models import Participant, Room
|
30
40
|
from ..util.jid_escaping import unescape_node
|
31
|
-
from ..util.lock import NamedLockMixin
|
32
41
|
from ..util.types import (
|
33
42
|
HoleBound,
|
34
43
|
LegacyGroupIdType,
|
@@ -56,7 +65,6 @@ class LegacyMUC(
|
|
56
65
|
LegacyGroupIdType, LegacyMessageType, LegacyParticipantType, LegacyUserIdType
|
57
66
|
],
|
58
67
|
AvatarMixin,
|
59
|
-
NamedLockMixin,
|
60
68
|
ChatterDiscoMixin,
|
61
69
|
ReactionRecipientMixin,
|
62
70
|
ThreadRecipientMixin,
|
@@ -242,10 +250,22 @@ class LegacyMUC(
|
|
242
250
|
)
|
243
251
|
self.commit()
|
244
252
|
|
253
|
+
@asynccontextmanager
|
254
|
+
async def lock(self, id_: str) -> AsyncIterator[None]:
|
255
|
+
async with self.session.lock((self.legacy_id, id_)):
|
256
|
+
yield
|
257
|
+
|
258
|
+
def get_lock(self, id_: str) -> Lock | None:
|
259
|
+
return self.session.get_lock((self.legacy_id, id_))
|
260
|
+
|
245
261
|
async def __fill_participants(self) -> None:
|
246
|
-
if self.participants_filled:
|
247
|
-
return
|
248
262
|
async with self.lock("fill participants"):
|
263
|
+
with self.xmpp.store.session(expire_on_commit=False) as orm:
|
264
|
+
orm.add(self.stored)
|
265
|
+
with orm.no_autoflush:
|
266
|
+
orm.refresh(self.stored, ["participants_filled"])
|
267
|
+
if self.participants_filled:
|
268
|
+
return
|
249
269
|
parts: list[Participant] = []
|
250
270
|
resources = set[str]()
|
251
271
|
# During fill_participants(), self.get_participant*() methods may
|
@@ -261,17 +281,13 @@ class LegacyMUC(
|
|
261
281
|
resources.add(participant.stored.resource)
|
262
282
|
with self.xmpp.store.session(expire_on_commit=False) as orm:
|
263
283
|
orm.add(self.stored)
|
264
|
-
# because self.
|
265
|
-
# this point
|
284
|
+
# because self.fill_participants() is async, self.stored may be stale at
|
285
|
+
# this point, and the only thing we want to update is the participant list
|
286
|
+
# and the participant_filled attribute.
|
266
287
|
with orm.no_autoflush:
|
267
288
|
orm.refresh(self.stored)
|
268
|
-
|
269
|
-
|
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
|
289
|
+
for part in parts:
|
290
|
+
orm.merge(part)
|
275
291
|
self.stored.participants_filled = True
|
276
292
|
orm.commit()
|
277
293
|
|
@@ -290,10 +306,14 @@ class LegacyMUC(
|
|
290
306
|
yield self.participant_from_store(db_participant)
|
291
307
|
|
292
308
|
async def __fill_history(self) -> None:
|
293
|
-
if self.stored.history_filled:
|
294
|
-
self.log.debug("History has already been fetched.")
|
295
|
-
return
|
296
309
|
async with self.lock("fill history"):
|
310
|
+
with self.xmpp.store.session(expire_on_commit=False) as orm:
|
311
|
+
orm.add(self.stored)
|
312
|
+
with orm.no_autoflush:
|
313
|
+
orm.refresh(self.stored, ["history_filled"])
|
314
|
+
if self.stored.history_filled:
|
315
|
+
self.log.debug("History has already been fetched.")
|
316
|
+
return
|
297
317
|
log.debug("Fetching history for %s", self)
|
298
318
|
try:
|
299
319
|
before, after = self.archive.get_hole_bounds()
|
@@ -314,16 +334,15 @@ class LegacyMUC(
|
|
314
334
|
self.stored.history_filled = True
|
315
335
|
self.commit(merge=True)
|
316
336
|
|
317
|
-
|
318
|
-
|
319
|
-
return self.name or "unnamed-room"
|
337
|
+
def _get_disco_name(self) -> str | None:
|
338
|
+
return self.name
|
320
339
|
|
321
340
|
@property
|
322
|
-
def name(self) -> str:
|
323
|
-
return self.stored.name
|
341
|
+
def name(self) -> str | None:
|
342
|
+
return self.stored.name
|
324
343
|
|
325
344
|
@name.setter
|
326
|
-
def name(self, n: str) -> None:
|
345
|
+
def name(self, n: str | None) -> None:
|
327
346
|
if self.name == n:
|
328
347
|
return
|
329
348
|
self.stored.name = n
|
@@ -662,7 +681,7 @@ class LegacyMUC(
|
|
662
681
|
since=since,
|
663
682
|
)
|
664
683
|
self.__get_subject_setter_participant().set_room_subject(
|
665
|
-
self.subject if self.HAS_SUBJECT else (self.description or self.name),
|
684
|
+
self.subject if self.HAS_SUBJECT else (self.description or self.name or ""),
|
666
685
|
user_full_jid,
|
667
686
|
self.subject_date,
|
668
687
|
)
|
@@ -753,9 +772,24 @@ class LegacyMUC(
|
|
753
772
|
"""
|
754
773
|
return self._participant_cls(self, Participant(), is_system=True)
|
755
774
|
|
775
|
+
@overload
|
756
776
|
async def get_participant_by_contact(
|
757
777
|
self, c: "LegacyContact"
|
758
|
-
) -> "LegacyParticipantType":
|
778
|
+
) -> "LegacyParticipantType": ...
|
779
|
+
|
780
|
+
@overload
|
781
|
+
async def get_participant_by_contact(
|
782
|
+
self, c: "LegacyContact", create: Literal[False]
|
783
|
+
) -> "LegacyParticipantType | None": ...
|
784
|
+
|
785
|
+
@overload
|
786
|
+
async def get_participant_by_contact(
|
787
|
+
self, c: "LegacyContact", create: Literal[True]
|
788
|
+
) -> "LegacyParticipantType": ...
|
789
|
+
|
790
|
+
async def get_participant_by_contact(
|
791
|
+
self, c: "LegacyContact", create: bool = True
|
792
|
+
) -> "LegacyParticipantType | None":
|
759
793
|
"""
|
760
794
|
Get a non-anonymous participant.
|
761
795
|
|
@@ -763,20 +797,23 @@ class LegacyMUC(
|
|
763
797
|
that the Contact jid is associated to this participant
|
764
798
|
|
765
799
|
:param c: The :class:`.LegacyContact` instance corresponding to this contact
|
800
|
+
:param create: Creates the participant if it does not exist.
|
766
801
|
:return:
|
767
802
|
"""
|
768
803
|
await self.session.contacts.ready
|
769
804
|
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
if
|
779
|
-
return
|
805
|
+
with self.xmpp.store.session() as orm:
|
806
|
+
self.stored = orm.merge(self.stored)
|
807
|
+
stored = (
|
808
|
+
orm.query(Participant)
|
809
|
+
.filter_by(contact=c.stored, room=self.stored)
|
810
|
+
.one_or_none()
|
811
|
+
)
|
812
|
+
if stored is None:
|
813
|
+
if not create:
|
814
|
+
return None
|
815
|
+
else:
|
816
|
+
return self.participant_from_store(stored=stored, contact=c)
|
780
817
|
|
781
818
|
nickname = c.name or unescape_node(c.jid.node)
|
782
819
|
|
@@ -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
|
-
|
171
|
-
|
172
|
-
|
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
|
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
|
|
@@ -72,6 +72,7 @@ MucRole = Literal["visitor", "participant", "moderator", "none"]
|
|
72
72
|
ClientType = Literal[
|
73
73
|
"bot", "console", "game", "handheld", "pc", "phone", "sms", "tablet", "web"
|
74
74
|
]
|
75
|
+
AttachmentDisposition = Literal["attachment", "inline"]
|
75
76
|
|
76
77
|
|
77
78
|
@dataclass
|
@@ -115,6 +116,7 @@ class LegacyAttachment:
|
|
115
116
|
legacy_file_id: Optional[Union[str, int]] = None
|
116
117
|
url: Optional[str] = None
|
117
118
|
caption: Optional[str] = None
|
119
|
+
disposition: Optional[AttachmentDisposition] = None
|
118
120
|
"""
|
119
121
|
A caption for this specific image. For a global caption for a list of attachments,
|
120
122
|
use the ``body`` parameter of :meth:`.AttachmentMixin.send_files`
|
@@ -74,15 +74,18 @@ class Base(Shakespeare, AvatarFixtureMixin):
|
|
74
74
|
use_values=False,
|
75
75
|
)
|
76
76
|
|
77
|
-
def _assert_file(self, url="http://url"):
|
77
|
+
def _assert_file(self, url="http://url", disposition: str = ''):
|
78
78
|
when = (
|
79
79
|
datetime.fromtimestamp(self.avatar_path.stat().st_mtime)
|
80
80
|
.isoformat()
|
81
81
|
.replace("+00:00", "Z")
|
82
82
|
)
|
83
|
+
if disposition:
|
84
|
+
el = f"disposition='{disposition}'"
|
85
|
+
else:
|
86
|
+
el = ""
|
83
87
|
self.send( # language=XML
|
84
|
-
f"""
|
85
|
-
<message type="chat"
|
88
|
+
f"""<message type="chat"
|
86
89
|
from="juliet@aim.shakespeare.lit/slidge"
|
87
90
|
to="romeo@montague.lit">
|
88
91
|
<reference xmlns="urn:xmpp:reference:0"
|
@@ -108,8 +111,7 @@ class Base(Shakespeare, AvatarFixtureMixin):
|
|
108
111
|
</file>
|
109
112
|
</media-sharing>
|
110
113
|
</reference>
|
111
|
-
<file-sharing xmlns="urn:xmpp:sfs:0"
|
112
|
-
disposition="inline">
|
114
|
+
<file-sharing xmlns="urn:xmpp:sfs:0" {el}>
|
113
115
|
<sources>
|
114
116
|
<url-data xmlns="http://jabber.org/protocol/url-data"
|
115
117
|
target="{url}" />
|
@@ -153,13 +155,13 @@ class TestBodyOnly(Base):
|
|
153
155
|
|
154
156
|
|
155
157
|
class TestAttachmentUpload(Base):
|
156
|
-
def __test_basic(self, attachment: LegacyAttachment, upload_kwargs: dict):
|
158
|
+
def __test_basic(self, attachment: LegacyAttachment, upload_kwargs: dict, disposition: str = ''):
|
157
159
|
"""
|
158
160
|
Basic test that file is uploaded.
|
159
161
|
"""
|
160
162
|
self.run_coro(self.juliet.send_files([attachment]))
|
161
163
|
self.http_upload.assert_called_with(**upload_kwargs)
|
162
|
-
self._assert_file()
|
164
|
+
self._assert_file(disposition=disposition)
|
163
165
|
|
164
166
|
def _test_reuse(self, attachment: LegacyAttachment, upload_kwargs: dict):
|
165
167
|
"""
|
@@ -185,6 +187,18 @@ class TestAttachmentUpload(Base):
|
|
185
187
|
),
|
186
188
|
)
|
187
189
|
|
190
|
+
def test_path_attachment(self):
|
191
|
+
self.__test_basic(
|
192
|
+
LegacyAttachment(path=self.avatar_path, disposition="attachment"),
|
193
|
+
dict(
|
194
|
+
filename=self.avatar_path,
|
195
|
+
content_type="image/png",
|
196
|
+
ifrom=self.xmpp.boundjid,
|
197
|
+
domain=None,
|
198
|
+
),
|
199
|
+
"attachment",
|
200
|
+
)
|
201
|
+
|
188
202
|
def test_thumbhash(self):
|
189
203
|
self.__test_basic(
|
190
204
|
LegacyAttachment(path=self.avatar_path, content_type="image/png"),
|
@@ -441,8 +455,7 @@ class TestAttachmentNoUpload(Base):
|
|
441
455
|
</file>
|
442
456
|
</media-sharing>
|
443
457
|
</reference>
|
444
|
-
<file-sharing xmlns="urn:xmpp:sfs:0"
|
445
|
-
disposition="inline">
|
458
|
+
<file-sharing xmlns="urn:xmpp:sfs:0">
|
446
459
|
<sources>
|
447
460
|
<url-data xmlns="http://jabber.org/protocol/url-data"
|
448
461
|
target="https://url/uuid/uuid/5x5.png" />
|
@@ -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"]
|
@@ -4189,9 +4189,7 @@ class TestMUCAdmin(Base):
|
|
4189
4189
|
</field>
|
4190
4190
|
<field label='Natural-Language Room Name'
|
4191
4191
|
type='text-single'
|
4192
|
-
var='muc#roomconfig_roomname'>
|
4193
|
-
<value>unnamed-room</value>
|
4194
|
-
</field>
|
4192
|
+
var='muc#roomconfig_roomname'></field>
|
4195
4193
|
<field label='Short Description of Room'
|
4196
4194
|
type='text-single'
|
4197
4195
|
var='muc#roomconfig_roomdesc'>
|
@@ -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>
|