slidge 0.3.0b4__tar.gz → 0.3.2__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.0b4 → slidge-0.3.2}/PKG-INFO +1 -1
- slidge-0.3.2/docs/source/admin/config/index.rst +57 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/conf.py +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/pyproject.toml +3 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/__init__.py +0 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/user.py +25 -6
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/contact/contact.py +4 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/contact/roster.py +6 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/config.py +43 -9
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/message/message.py +1 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/muc/misc.py +27 -2
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/presence.py +32 -26
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/registration.py +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/search.py +1 -5
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/util.py +3 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/gateway.py +12 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/attachment.py +62 -8
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/db.py +23 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/message_maker.py +3 -3
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/message_text.py +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/presence.py +28 -10
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/pubsub.py +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/session.py +13 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/models.py +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/store.py +29 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/group/archive.py +3 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/group/participant.py +19 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/group/room.py +17 -2
- slidge-0.3.2/slidge/slixfix/xep_0292/vcard4.py +24 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/test.py +3 -2
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/util.py +6 -4
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge.egg-info/PKG-INFO +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge.egg-info/SOURCES.txt +2 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/conftest.py +9 -5
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_attachment.py +131 -8
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_avatar.py +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_backfill.py +0 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_config.py +1 -1
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_db/test_store.py +41 -2
- slidge-0.3.2/tests/test_gateway_wide_reaction_restrictions.py +187 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_muc.py +25 -9
- slidge-0.3.0b4/tests/test_empty_subject.py → slidge-0.3.2/tests/test_muc_subject.py +70 -6
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_session.py +0 -4
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_session_2.py +1 -5
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_set_name_before_fill.py +0 -4
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_shakespeare.py +12 -13
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_util.py +11 -3
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_vcard.py +4 -5
- {slidge-0.3.0b4 → slidge-0.3.2}/uv.lock +17 -1
- slidge-0.3.0b4/docs/source/admin/config/index.rst +0 -35
- slidge-0.3.0b4/slidge/slixfix/xep_0292/vcard4.py +0 -14
- {slidge-0.3.0b4 → slidge-0.3.2}/.gitignore +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/.pre-commit-config.yaml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/.woodpecker/container-ci.yaml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/.woodpecker/docs.yaml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/.woodpecker/package.yaml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/.woodpecker/test.yaml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/Dockerfile +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/LICENSE +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/README.md +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/commitlint.config.js +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/assets/5x5.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/assets/slidge-color-small.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/assets/slidge-color.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/assets/slidge-mono-black.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/assets/slidge-mono-white.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/assets/slidge.svg +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/confs/movim.env +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/confs/nginx.conf +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/confs/slidge-dev.ini +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/confs/slidge-example.ini +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/hot-reload.sh +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/dev/prettify_tests.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/doap.xml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docker-compose.yml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/Makefile +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/attachments.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/component.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/daemon.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/examples/ejabberd.yaml +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/examples/index.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/examples/prosody.cfg.lua +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/index.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/install.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/note.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/admin/privilege.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/codeberg.svg +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/dev/contributing.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/dev/design.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/dev/howto.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/dev/index.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/dev/tutorial.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/glossary.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/index.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/commands.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/contacts.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/foxyproxy.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/gajim.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/index.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/low_profile.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/movim1.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/movim2.png +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/note.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/docs/source/user/register.rst +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/setup.cfg +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/__main__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/adhoc.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/admin.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/base.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/categories.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/chat_command.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/command/register.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/contact/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/caps.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/disco.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/message/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/message/chat_state.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/message/marker.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/muc/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/muc/admin.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/muc/mam.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/muc/owner.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/muc/ping.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/session_dispatcher.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/dispatcher/vcard.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/avatar.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/base.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/disco.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/message.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/core/mixins/recipient.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/alembic/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/alembic/env.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/alembic/script.py.mako +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/alembic/versions/cef02a8b1451_initial_schema.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/avatar.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/db/meta.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/group/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/group/bookmarks.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/main.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/migration.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/py.typed +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/delivery_receipt.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/link_preview/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/link_preview/link_preview.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/link_preview/stanza.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/roster.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0077/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0077/register.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0077/stanza.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0100/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0100/gateway.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0100/stanza.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0153/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0153/vcard_avatar.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/slixfix/xep_0292/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/archive_msg.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/conf.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/jid_escaping.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/lock.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge/util/types.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge.egg-info/dependency_links.txt +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge.egg-info/entry_points.txt +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge.egg-info/requires.txt +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/slidge.egg-info/top_level.txt +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/__init__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/__main__.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/contact.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/gateway.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/group.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/legacy_client.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/session.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/superduper/util.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_adhoc/test_access.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_adhoc/test_confirmation.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_adhoc/test_form.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_adhoc/test_reported.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_chat_commands.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_db/test_user.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_feature_restriction.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_mam_archivable.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_mds.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_resourceprep.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_stanza_link_preview.py +0 -0
- {slidge-0.3.0b4 → slidge-0.3.2}/tests/test_type_conversion.py +0 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
Configuration
|
2
|
+
=============
|
3
|
+
|
4
|
+
.. include:: ../note.rst
|
5
|
+
|
6
|
+
By default, slidge uses all config files found in ``/etc/slidge/conf.d/*``.
|
7
|
+
You can change this using the ``SLIDGE_CONF_DIR`` env var, eg
|
8
|
+
``SLIDGE_CONF_DIR=/path/dir1:/path/dir2:/path/dir3``.
|
9
|
+
|
10
|
+
It is recommended to use ``/etc/slidge/conf.d/`` to store configuration options
|
11
|
+
common to all slidge components (eg, attachment handling, logging options,
|
12
|
+
etc.), and to specify a plugin-specific file on startup, eg:
|
13
|
+
|
14
|
+
.. code-block:: bash
|
15
|
+
|
16
|
+
slidge -c /etc/slidge/superduper.conf
|
17
|
+
|
18
|
+
.. note::
|
19
|
+
For the debian unofficial package, just edit the ``/etc/slidge/conf.d/common.conf`` and
|
20
|
+
``/etc/slidge/*.conf`` files, and use :ref:`Debian packages (systemd)` to
|
21
|
+
launch slidge.
|
22
|
+
|
23
|
+
Command-line arguments
|
24
|
+
----------------------
|
25
|
+
|
26
|
+
.. code-block:: text
|
27
|
+
|
28
|
+
-h, --help show this help message and exit
|
29
|
+
-c, --config CONFIG Path to a INI config file. [env var: SLIDGE_CONFIG]
|
30
|
+
--log-config LOG_CONFIG
|
31
|
+
Path to a INI config file to personalise logging output.
|
32
|
+
-q, --quiet loglevel=WARNING (unused if --log-config is specified) [env var: SLIDGE_QUIET]
|
33
|
+
-d, --debug loglevel=DEBUG (unused if --log-config is specified) [env var: SLIDGE_DEBUG]
|
34
|
+
--version show program's version number and exit
|
35
|
+
|
36
|
+
|
37
|
+
Regarding the ``--log-config`` argument, refer to the `official python documentation
|
38
|
+
<https://docs.python.org/3/library/logging.config.html#configuration-file-format>`_
|
39
|
+
for the syntax.
|
40
|
+
|
41
|
+
Other options
|
42
|
+
-------------
|
43
|
+
|
44
|
+
.. warning::
|
45
|
+
|
46
|
+
Because of an ugly mess that will soon™ be fixed, it is impossible to use
|
47
|
+
the config file to turn off boolean arguments that are true by default.
|
48
|
+
As a workaround, use CLI args instead, e.g., ``--some-opt=false``.
|
49
|
+
|
50
|
+
The following options can be used:
|
51
|
+
|
52
|
+
* in a config file (see top of this page);
|
53
|
+
* as command line arguments, prepended with ``--``, e.g., ``--some-option=value``;
|
54
|
+
* as environment variables, upper case, prepended with ``SLIDGE_``,
|
55
|
+
and with dashes substituted with underscores, e.g., ``SLIDGE_SOME_OPTION=value``.
|
56
|
+
|
57
|
+
.. config-obj:: slidge.core.config
|
@@ -39,9 +39,9 @@ extensions = [
|
|
39
39
|
"sphinx.ext.extlinks",
|
40
40
|
# "sphinx.ext.viewcode", # crashes build unfortunately
|
41
41
|
"sphinx.ext.autodoc.typehints",
|
42
|
-
"sphinx.ext.autosectionlabel",
|
43
42
|
"sphinxarg.ext",
|
44
43
|
"autoapi.extension",
|
44
|
+
"slidge_sphinx_extensions.config_obj",
|
45
45
|
]
|
46
46
|
|
47
47
|
autodoc_typehints = "description"
|
@@ -63,6 +63,7 @@ dev = [
|
|
63
63
|
"types-pillow>=10.2.0.20240822",
|
64
64
|
"utidylib>=0.10",
|
65
65
|
"xmldiff>=2.7.0",
|
66
|
+
"slidge-sphinx-extensions>=0.2.1,<0.3",
|
66
67
|
]
|
67
68
|
|
68
69
|
[tool.mypy]
|
@@ -106,6 +107,8 @@ filterwarnings = [
|
|
106
107
|
"ignore::UserWarning:slidge",
|
107
108
|
"ignore:coroutine 'XMLStream._end_stream_wait' was never awaited.*:RuntimeWarning"
|
108
109
|
]
|
110
|
+
log_cli = true
|
111
|
+
log_level = "DEBUG"
|
109
112
|
|
110
113
|
[[tool.uv.index]]
|
111
114
|
name = "codeberg"
|
@@ -34,8 +34,9 @@ class Search(Command):
|
|
34
34
|
async def run(
|
35
35
|
self, session: Optional[AnyBaseSession], _ifrom: JID, *args: str
|
36
36
|
) -> Union[Form, SearchResult, None]:
|
37
|
+
assert session is not None
|
38
|
+
await session.ready
|
37
39
|
if args:
|
38
|
-
assert session is not None
|
39
40
|
return await session.on_search(
|
40
41
|
{self.xmpp.SEARCH_FIELDS[0].var: " ".join(args)}
|
41
42
|
)
|
@@ -70,6 +71,8 @@ class SyncContacts(Command):
|
|
70
71
|
CATEGORY = CONTACTS
|
71
72
|
|
72
73
|
async def run(self, session: Optional[AnyBaseSession], _ifrom, *_) -> Confirmation:
|
74
|
+
assert session is not None
|
75
|
+
await session.ready
|
73
76
|
return Confirmation(
|
74
77
|
prompt="Are you sure you want to sync your roster?",
|
75
78
|
success=None,
|
@@ -133,6 +136,7 @@ class ListContacts(Command):
|
|
133
136
|
self, session: Optional[AnyBaseSession], _ifrom: JID, *_
|
134
137
|
) -> TableResult:
|
135
138
|
assert session is not None
|
139
|
+
await session.ready
|
136
140
|
contacts = sorted(
|
137
141
|
session.contacts, key=lambda c: c.name.casefold() if c.name else ""
|
138
142
|
)
|
@@ -152,7 +156,7 @@ class ListGroups(Command):
|
|
152
156
|
|
153
157
|
async def run(self, session, _ifrom, *_):
|
154
158
|
assert session is not None
|
155
|
-
await session.
|
159
|
+
await session.ready
|
156
160
|
groups = sorted(session.bookmarks, key=lambda g: g.DISCO_NAME.casefold())
|
157
161
|
return TableResult(
|
158
162
|
description="Your groups",
|
@@ -201,6 +205,7 @@ class CreateGroup(Command):
|
|
201
205
|
|
202
206
|
async def run(self, session: Optional[AnyBaseSession], _ifrom, *_):
|
203
207
|
assert session is not None
|
208
|
+
await session.ready
|
204
209
|
contacts = session.contacts.known_contacts(only_friends=True)
|
205
210
|
return Form(
|
206
211
|
title="Create a new group",
|
@@ -260,20 +265,34 @@ class Preferences(Command):
|
|
260
265
|
instructions=self.HELP,
|
261
266
|
fields=fields,
|
262
267
|
handler=self.finish, # type:ignore
|
268
|
+
handler_kwargs={"previous": current},
|
263
269
|
)
|
264
270
|
|
265
271
|
async def finish(
|
266
|
-
self,
|
272
|
+
self,
|
273
|
+
form_values: UserPreferences,
|
274
|
+
session: Optional[AnyBaseSession],
|
275
|
+
*_,
|
276
|
+
previous,
|
267
277
|
) -> str:
|
268
278
|
assert session is not None
|
279
|
+
if previous == form_values:
|
280
|
+
return "No preference was changed"
|
281
|
+
|
269
282
|
user = session.user
|
270
283
|
user.preferences.update(form_values) # type:ignore
|
271
|
-
|
284
|
+
self.xmpp.store.users.update(user)
|
285
|
+
|
286
|
+
try:
|
287
|
+
await session.on_preferences(previous, form_values) # type:ignore[arg-type]
|
288
|
+
except NotImplementedError:
|
289
|
+
pass
|
290
|
+
|
291
|
+
if not previous["sync_avatar"] and form_values["sync_avatar"]:
|
272
292
|
await self.xmpp.fetch_user_avatar(session)
|
273
293
|
else:
|
274
294
|
user.avatar_hash = None
|
275
295
|
|
276
|
-
self.xmpp.store.users.update(user)
|
277
296
|
return "Your preferences have been updated."
|
278
297
|
|
279
298
|
|
@@ -308,7 +327,7 @@ class LeaveGroup(Command):
|
|
308
327
|
|
309
328
|
async def run(self, session, _ifrom, *_):
|
310
329
|
assert session is not None
|
311
|
-
await session.
|
330
|
+
await session.ready
|
312
331
|
groups = sorted(session.bookmarks, key=lambda g: g.DISCO_NAME.casefold())
|
313
332
|
return Form(
|
314
333
|
title="Leave a group",
|
@@ -325,6 +325,7 @@ class LegacyContact(
|
|
325
325
|
email: Optional[str] = None,
|
326
326
|
country: Optional[str] = None,
|
327
327
|
locality: Optional[str] = None,
|
328
|
+
pronouns: Optional[str] = None,
|
328
329
|
) -> None:
|
329
330
|
vcard = VCard4()
|
330
331
|
vcard.add_impp(f"xmpp:{self.jid.bare}")
|
@@ -357,6 +358,8 @@ class LegacyContact(
|
|
357
358
|
vcard.add_address(country, locality)
|
358
359
|
elif country:
|
359
360
|
vcard.add_address(country, locality)
|
361
|
+
if pronouns:
|
362
|
+
vcard["pronouns"]["text"] = pronouns
|
360
363
|
|
361
364
|
self.stored.vcard = str(vcard)
|
362
365
|
self.stored.vcard_fetched = True
|
@@ -408,7 +411,7 @@ class LegacyContact(
|
|
408
411
|
# we only broadcast pubsub events for contacts added to the roster
|
409
412
|
# so if something was set before, we need to push it now
|
410
413
|
self.added_to_roster = True
|
411
|
-
self.send_last_presence()
|
414
|
+
self.send_last_presence(force=True)
|
412
415
|
|
413
416
|
async def __broadcast_pubsub_items(self) -> None:
|
414
417
|
if not self.is_friend:
|
@@ -4,7 +4,7 @@ import warnings
|
|
4
4
|
from typing import TYPE_CHECKING, AsyncIterator, Generic, Iterator, Optional, Type
|
5
5
|
|
6
6
|
from slixmpp import JID
|
7
|
-
from slixmpp.exceptions import IqError, IqTimeout
|
7
|
+
from slixmpp.exceptions import IqError, IqTimeout, XMPPError
|
8
8
|
from sqlalchemy.orm import Session
|
9
9
|
from sqlalchemy.orm import Session as OrmSession
|
10
10
|
|
@@ -92,6 +92,10 @@ class LegacyRoster(
|
|
92
92
|
# :return:
|
93
93
|
# """
|
94
94
|
username = contact_jid.node
|
95
|
+
if not username:
|
96
|
+
raise XMPPError(
|
97
|
+
"bad-request", "Contacts must have a local part in their JID"
|
98
|
+
)
|
95
99
|
contact_jid = JID(contact_jid.bare)
|
96
100
|
async with self.lock(("username", username)):
|
97
101
|
legacy_id = await self.jid_username_to_legacy_id(username)
|
@@ -239,6 +243,7 @@ class LegacyRoster(
|
|
239
243
|
warnings.warn(f"Could not add to roster: {e}")
|
240
244
|
else:
|
241
245
|
contact.added_to_roster = True
|
246
|
+
contact.send_last_presence(force=True)
|
242
247
|
orm.commit()
|
243
248
|
self.__filling = False
|
244
249
|
|
@@ -1,22 +1,26 @@
|
|
1
|
-
from datetime import timedelta
|
2
1
|
from pathlib import Path
|
3
|
-
from typing import Optional
|
2
|
+
from typing import Optional
|
4
3
|
|
5
4
|
from slixmpp import JID as JIDType
|
6
5
|
|
6
|
+
# REQUIRED, so not default value
|
7
7
|
|
8
|
-
class _TimedeltaSeconds(timedelta):
|
9
|
-
def __new__(cls, s: str) -> Self:
|
10
|
-
return super().__new__(cls, seconds=int(s))
|
11
8
|
|
9
|
+
class _Categories:
|
10
|
+
MANDATORY = (0, "Mandatory settings")
|
11
|
+
BASE = (10, "Basic configuration")
|
12
|
+
ATTACHMENTS = (20, "Attachments")
|
13
|
+
LOG = (30, "Logging")
|
14
|
+
ADVANCED = (40, "Advanced settings")
|
12
15
|
|
13
|
-
# REQUIRED, so not default value
|
14
16
|
|
15
17
|
LEGACY_MODULE: str
|
16
18
|
LEGACY_MODULE__DOC = (
|
17
|
-
"Importable python module containing (at least) "
|
18
|
-
"
|
19
|
+
"Importable python module containing (at least) a BaseGateway and a LegacySession subclass. "
|
20
|
+
"NB: this is not needed if you use a gateway-specific entrypoint, e.g., `slidgram` or "
|
21
|
+
"`python -m slidgram`."
|
19
22
|
)
|
23
|
+
LEGACY_MODULE__CATEGORY = _Categories.BASE
|
20
24
|
|
21
25
|
SERVER: str = "localhost"
|
22
26
|
SERVER__DOC = (
|
@@ -27,17 +31,21 @@ SERVER__DOC = (
|
|
27
31
|
"you change this."
|
28
32
|
)
|
29
33
|
SERVER__SHORT = "s"
|
34
|
+
SERVER__CATEGORY = _Categories.BASE
|
30
35
|
|
31
36
|
SECRET: str
|
32
37
|
SECRET__DOC = "The gateway component's secret (required to connect to the XMPP server)"
|
38
|
+
SECRET__CATEGORY = _Categories.MANDATORY
|
33
39
|
|
34
40
|
JID: JIDType
|
35
41
|
JID__DOC = "The gateway component's JID"
|
36
42
|
JID__SHORT = "j"
|
43
|
+
JID__CATEGORY = _Categories.MANDATORY
|
37
44
|
|
38
45
|
PORT: str = "5347"
|
39
46
|
PORT__DOC = "The XMPP server's port for incoming component connections"
|
40
47
|
PORT__SHORT = "p"
|
48
|
+
PORT__CATEGORY = _Categories.BASE
|
41
49
|
|
42
50
|
# Dynamic default (depends on other values)
|
43
51
|
|
@@ -47,6 +55,7 @@ HOME_DIR__DOC = (
|
|
47
55
|
"Defaults to /var/lib/slidge/${SLIDGE_JID}. "
|
48
56
|
)
|
49
57
|
HOME_DIR__DYNAMIC_DEFAULT = True
|
58
|
+
HOME_DIR__CATEGORY = _Categories.BASE
|
50
59
|
|
51
60
|
DB_URL: str
|
52
61
|
DB_URL__DOC = (
|
@@ -54,6 +63,7 @@ DB_URL__DOC = (
|
|
54
63
|
"Defaults to sqlite:///${HOME_DIR}/slidge.sqlite"
|
55
64
|
)
|
56
65
|
DB_URL__DYNAMIC_DEFAULT = True
|
66
|
+
DB_URL__CATEGORY = _Categories.ADVANCED
|
57
67
|
|
58
68
|
USER_JID_VALIDATOR: str
|
59
69
|
USER_JID_VALIDATOR__DOC = (
|
@@ -62,11 +72,13 @@ USER_JID_VALIDATOR__DOC = (
|
|
62
72
|
"you probably want to change that to .*@example.com"
|
63
73
|
)
|
64
74
|
USER_JID_VALIDATOR__DYNAMIC_DEFAULT = True
|
75
|
+
USER_JID_VALIDATOR__CATEGORY = _Categories.BASE
|
65
76
|
|
66
77
|
# Optional, so default value + type hint if default is None
|
67
78
|
|
68
79
|
ADMINS: tuple[JIDType, ...] = ()
|
69
80
|
ADMINS__DOC = "JIDs of the gateway admins"
|
81
|
+
ADMINS__CATEGORY = _Categories.BASE
|
70
82
|
|
71
83
|
UPLOAD_SERVICE: Optional[str] = None
|
72
84
|
UPLOAD_SERVICE__DOC = (
|
@@ -74,11 +86,13 @@ UPLOAD_SERVICE__DOC = (
|
|
74
86
|
"This is optional, as it should be automatically determined via service"
|
75
87
|
"discovery."
|
76
88
|
)
|
89
|
+
UPLOAD_SERVICE__CATEGORY = _Categories.ATTACHMENTS
|
77
90
|
|
78
91
|
AVATAR_SIZE = 200
|
79
92
|
AVATAR_SIZE__DOC = (
|
80
93
|
"Maximum image size (width and height), image ratio will be preserved"
|
81
94
|
)
|
95
|
+
AVATAR_SIZE__CATEGORY = _Categories.ADVANCED
|
82
96
|
|
83
97
|
USE_ATTACHMENT_ORIGINAL_URLS = False
|
84
98
|
USE_ATTACHMENT_ORIGINAL_URLS__DOC = (
|
@@ -86,11 +100,13 @@ USE_ATTACHMENT_ORIGINAL_URLS__DOC = (
|
|
86
100
|
"let XMPP clients directly download them from this URL. Note that this will "
|
87
101
|
"probably leak your client IP to the legacy network."
|
88
102
|
)
|
103
|
+
USE_ATTACHMENT_ORIGINAL_URLS__CATEGORY = _Categories.ATTACHMENTS
|
89
104
|
|
90
105
|
UPLOAD_REQUESTER: Optional[str] = None
|
91
106
|
UPLOAD_REQUESTER__DOC = (
|
92
107
|
"Set which JID should request the upload slots. Defaults to the component JID."
|
93
108
|
)
|
109
|
+
UPLOAD_REQUESTER__CATEGORY = _Categories.ATTACHMENTS
|
94
110
|
|
95
111
|
NO_UPLOAD_PATH: Optional[str] = None
|
96
112
|
NO_UPLOAD_PATH__DOC = (
|
@@ -98,38 +114,45 @@ NO_UPLOAD_PATH__DOC = (
|
|
98
114
|
"You need to set NO_UPLOAD_URL_PREFIX too if you use this option, and configure "
|
99
115
|
"an web server to serve files in this dir."
|
100
116
|
)
|
117
|
+
NO_UPLOAD_PATH__CATEGORY = _Categories.ATTACHMENTS
|
101
118
|
|
102
119
|
NO_UPLOAD_URL_PREFIX: Optional[str] = None
|
103
120
|
NO_UPLOAD_URL_PREFIX__DOC = (
|
104
121
|
"Base URL that servers files in the dir set in the no-upload-path option, "
|
105
122
|
"eg https://example.com:666/slidge-attachments/"
|
106
123
|
)
|
124
|
+
NO_UPLOAD_URL_PREFIX__CATEGORY = _Categories.ATTACHMENTS
|
107
125
|
|
108
126
|
NO_UPLOAD_METHOD: str = "copy"
|
109
127
|
NO_UPLOAD_METHOD__DOC = (
|
110
128
|
"Whether to 'copy', 'move', 'hardlink' or 'symlink' the files in no-upload-path."
|
111
129
|
)
|
130
|
+
NO_UPLOAD_METHOD__CATEGORY = _Categories.ATTACHMENTS
|
112
131
|
|
113
132
|
NO_UPLOAD_FILE_READ_OTHERS = False
|
114
133
|
NO_UPLOAD_FILE_READ_OTHERS__DOC = (
|
115
134
|
"After writing a file in NO_UPLOAD_PATH, change its permission so that 'others' can"
|
116
135
|
" read it."
|
117
136
|
)
|
137
|
+
NO_UPLOAD_FILE_READ_OTHERS__CATEGORY = _Categories.ATTACHMENTS
|
118
138
|
|
119
|
-
IGNORE_DELAY_THRESHOLD =
|
139
|
+
IGNORE_DELAY_THRESHOLD = 300
|
120
140
|
IGNORE_DELAY_THRESHOLD__DOC = (
|
121
141
|
"Threshold, in seconds, below which the <delay> information is stripped "
|
122
142
|
"out of emitted stanzas."
|
123
143
|
)
|
144
|
+
IGNORE_DELAY_THRESHOLD__CATEGORY = _Categories.ADVANCED
|
124
145
|
|
125
146
|
PARTIAL_REGISTRATION_TIMEOUT = 3600
|
126
147
|
PARTIAL_REGISTRATION_TIMEOUT__DOC = (
|
127
148
|
"Timeout before registration and login. Only useful for legacy networks where "
|
128
149
|
"a single step registration process is not enough."
|
129
150
|
)
|
151
|
+
PARTIAL_REGISTRATION_TIMEOUT__CATEGORY = _Categories.ADVANCED
|
130
152
|
|
131
153
|
QR_TIMEOUT = 60
|
132
154
|
QR_TIMEOUT__DOC = "Timeout for QR code flashing confirmation."
|
155
|
+
QR_TIMEOUT__CATEGORY = _Categories.ADVANCED
|
133
156
|
|
134
157
|
FIX_FILENAME_SUFFIX_MIME_TYPE = False
|
135
158
|
FIX_FILENAME_SUFFIX_MIME_TYPE__DOC = (
|
@@ -138,9 +161,11 @@ FIX_FILENAME_SUFFIX_MIME_TYPE__DOC = (
|
|
138
161
|
" Therefore the MIME Type of the file is checked, if the suffix is not valid for"
|
139
162
|
" that MIME Type, a valid one will be picked."
|
140
163
|
)
|
164
|
+
FIX_FILENAME_SUFFIX_MIME_TYPE__CATEGORY = _Categories.ATTACHMENTS
|
141
165
|
|
142
166
|
LOG_FILE: Optional[Path] = None
|
143
167
|
LOG_FILE__DOC = "Log to a file instead of stdout/err"
|
168
|
+
LOG_FILE__CATEGORY = _Categories.LOG
|
144
169
|
|
145
170
|
LOG_FORMAT: str = "%(levelname)s:%(name)s:%(message)s"
|
146
171
|
LOG_FORMAT__DOC = (
|
@@ -148,41 +173,50 @@ LOG_FORMAT__DOC = (
|
|
148
173
|
"https://docs.python.org/3/library/logging.html#logrecord-attributes "
|
149
174
|
"for available options."
|
150
175
|
)
|
176
|
+
LOG_FORMAT__CATEGORY = _Categories.LOG
|
151
177
|
|
152
178
|
MAM_MAX_DAYS = 7
|
153
179
|
MAM_MAX_DAYS__DOC = "Maximum number of days for group archive retention."
|
180
|
+
MAM_MAX_DAYS__CATEGORY = _Categories.BASE
|
154
181
|
|
155
182
|
ATTACHMENT_MAXIMUM_FILE_NAME_LENGTH = 200
|
156
183
|
ATTACHMENT_MAXIMUM_FILE_NAME_LENGTH__DOC = (
|
157
184
|
"Some legacy network provide ridiculously long filenames, strip above this limit, "
|
158
185
|
"preserving suffix."
|
159
186
|
)
|
187
|
+
ATTACHMENT_MAXIMUM_FILE_NAME_LENGTH__CATEGORY = _Categories.ATTACHMENTS
|
160
188
|
|
161
189
|
AVATAR_RESAMPLING_THREADS = 2
|
162
190
|
AVATAR_RESAMPLING_THREADS__DOC = (
|
163
191
|
"Number of additional threads to use for avatar resampling. Even in a single-core "
|
164
192
|
"context, this makes avatar resampling non-blocking."
|
165
193
|
)
|
194
|
+
AVATAR_RESAMPLING_THREADS__CATEGORY = _Categories.ADVANCED
|
166
195
|
|
167
196
|
DEV_MODE = False
|
168
197
|
DEV_MODE__DOC = (
|
169
198
|
"Enables an interactive python shell via chat commands, for admins."
|
170
199
|
"Not safe to use in prod, but great during dev."
|
171
200
|
)
|
201
|
+
DEV_MODE__CATEGORY = _Categories.ADVANCED
|
202
|
+
|
172
203
|
|
173
204
|
STRIP_LEADING_EMOJI_ADHOC = False
|
174
205
|
STRIP_LEADING_EMOJI_ADHOC__DOC = (
|
175
206
|
"Strip the leading emoji in ad-hoc command names, if present, in case you "
|
176
207
|
"are a emoji-hater."
|
177
208
|
)
|
209
|
+
STRIP_LEADING_EMOJI_ADHOC__CATEGORY = _Categories.ADVANCED
|
178
210
|
|
179
211
|
COMPONENT_NAME: Optional[str] = None
|
180
212
|
COMPONENT_NAME__DOC = (
|
181
213
|
"Overrides the default component name with a custom one. This is seen in service discovery and as the nickname "
|
182
214
|
"of the component in chat windows."
|
183
215
|
)
|
216
|
+
COMPONENT_NAME__CATEGORY = _Categories.ADVANCED
|
184
217
|
|
185
218
|
WELCOME_MESSAGE: Optional[str] = None
|
186
219
|
WELCOME_MESSAGE__DOC = (
|
187
220
|
"Overrides the default welcome message received by newly registered users."
|
188
221
|
)
|
222
|
+
WELCOME_MESSAGE__CATEGORY = _Categories.ADVANCED
|
@@ -1,6 +1,14 @@
|
|
1
1
|
import logging
|
2
2
|
|
3
|
-
from slixmpp import
|
3
|
+
from slixmpp import (
|
4
|
+
JID,
|
5
|
+
CoroutineCallback,
|
6
|
+
Iq,
|
7
|
+
MatchXMLMask,
|
8
|
+
Message,
|
9
|
+
Presence,
|
10
|
+
StanzaPath,
|
11
|
+
)
|
4
12
|
from slixmpp.exceptions import XMPPError
|
5
13
|
|
6
14
|
from ..util import DispatcherMixin, exceptions_to_xmpp_errors
|
@@ -23,6 +31,15 @@ class MucMiscMixin(DispatcherMixin):
|
|
23
31
|
)
|
24
32
|
xmpp.add_event_handler("groupchat_subject", self.on_groupchat_subject)
|
25
33
|
xmpp.add_event_handler("groupchat_message_error", self.__on_group_chat_error)
|
34
|
+
xmpp.register_handler(
|
35
|
+
CoroutineCallback(
|
36
|
+
"muc_thread_subject",
|
37
|
+
MatchXMLMask(
|
38
|
+
"<message xmlns='jabber:component:accept' type='groupchat'><subject/><thread/></message>"
|
39
|
+
),
|
40
|
+
self.on_thread_subject,
|
41
|
+
)
|
42
|
+
)
|
26
43
|
|
27
44
|
async def __on_group_chat_error(self, msg: Message) -> None:
|
28
45
|
condition = msg["error"].get_condition()
|
@@ -43,7 +60,7 @@ class MucMiscMixin(DispatcherMixin):
|
|
43
60
|
# (not sure why?), but is of no consequence
|
44
61
|
log.debug("%s was not in the resources of %s", resource, muc)
|
45
62
|
else:
|
46
|
-
log.
|
63
|
+
log.debug(
|
47
64
|
"Removed %s from the resources of %s because of error", resource, muc
|
48
65
|
)
|
49
66
|
|
@@ -106,6 +123,14 @@ class MucMiscMixin(DispatcherMixin):
|
|
106
123
|
)
|
107
124
|
await muc.on_set_subject(msg["subject"])
|
108
125
|
|
126
|
+
@exceptions_to_xmpp_errors
|
127
|
+
async def on_thread_subject(self, msg: Message):
|
128
|
+
if msg["body"]:
|
129
|
+
return
|
130
|
+
session, muc, thread = await self._get_session_recipient_thread(msg)
|
131
|
+
assert thread is not None
|
132
|
+
await muc.on_set_thread_subject(thread, msg["subject"]) # type:ignore[union-attr]
|
133
|
+
|
109
134
|
|
110
135
|
KICKABLE_ERRORS = {
|
111
136
|
"gone",
|
@@ -4,6 +4,7 @@ from slixmpp import JID, Presence
|
|
4
4
|
from slixmpp.exceptions import XMPPError
|
5
5
|
|
6
6
|
from ...contact.roster import ContactIsUser
|
7
|
+
from ...util.types import AnyBaseSession
|
7
8
|
from ...util.util import merge_resources
|
8
9
|
from ..session import BaseSession
|
9
10
|
from .util import DispatcherMixin, exceptions_to_xmpp_errors
|
@@ -70,6 +71,7 @@ class PresenceHandlerMixin(DispatcherMixin):
|
|
70
71
|
return
|
71
72
|
|
72
73
|
await contact.on_friend_accept()
|
74
|
+
contact.send_last_presence(force=True)
|
73
75
|
|
74
76
|
@exceptions_to_xmpp_errors
|
75
77
|
async def _handle_unsubscribed(self, pres: Presence) -> None:
|
@@ -98,7 +100,7 @@ class PresenceHandlerMixin(DispatcherMixin):
|
|
98
100
|
reply.send()
|
99
101
|
|
100
102
|
@exceptions_to_xmpp_errors
|
101
|
-
async def on_presence(self, p: Presence):
|
103
|
+
async def on_presence(self, p: Presence) -> None:
|
102
104
|
if p.get_plugin("muc_join", check=True):
|
103
105
|
# handled in on_groupchat_join
|
104
106
|
# without this early return, since we switch from and to in this
|
@@ -112,31 +114,8 @@ class PresenceHandlerMixin(DispatcherMixin):
|
|
112
114
|
|
113
115
|
pto = p.get_to()
|
114
116
|
if pto == self.xmpp.boundjid.bare:
|
115
|
-
|
116
|
-
|
117
|
-
return
|
118
|
-
if not session.user.preferences.get("sync_presence", False):
|
119
|
-
session.log.debug("User does not want to sync their presence")
|
120
|
-
return
|
121
|
-
# NB: get_type() returns either a proper presence type or
|
122
|
-
# a presence show if available. Weird, weird, weird slix.
|
123
|
-
resources = self.xmpp.roster[self.xmpp.boundjid.bare][
|
124
|
-
p.get_from()
|
125
|
-
].resources
|
126
|
-
try:
|
127
|
-
await session.on_presence(
|
128
|
-
p.get_from().resource,
|
129
|
-
ptype, # type: ignore
|
130
|
-
p["status"],
|
131
|
-
resources,
|
132
|
-
merge_resources(resources),
|
133
|
-
)
|
134
|
-
except NotImplementedError:
|
135
|
-
pass
|
136
|
-
if p.get_type() == "available":
|
137
|
-
await self.xmpp.pubsub.on_presence_available(p, None)
|
138
|
-
for contact in session.contacts:
|
139
|
-
await self.xmpp.pubsub.on_presence_available(p, contact)
|
117
|
+
await self._on_presence_to_component(session, p)
|
118
|
+
return
|
140
119
|
|
141
120
|
if p.get_type() == "available":
|
142
121
|
try:
|
@@ -181,6 +160,33 @@ class PresenceHandlerMixin(DispatcherMixin):
|
|
181
160
|
)
|
182
161
|
error_stanza.send()
|
183
162
|
|
163
|
+
async def _on_presence_to_component(
|
164
|
+
self, session: AnyBaseSession, p: Presence
|
165
|
+
) -> None:
|
166
|
+
session.log.debug("Received a presence from %s", p.get_from())
|
167
|
+
if (ptype := p.get_type()) not in _USEFUL_PRESENCES:
|
168
|
+
return
|
169
|
+
if not session.user.preferences.get("sync_presence", False):
|
170
|
+
session.log.debug("User does not want to sync their presence")
|
171
|
+
return
|
172
|
+
# NB: get_type() returns either a proper presence type or
|
173
|
+
# a presence show if available. Weird, weird, weird slix.
|
174
|
+
resources = self.xmpp.roster[self.xmpp.boundjid.bare][p.get_from()].resources
|
175
|
+
try:
|
176
|
+
await session.on_presence(
|
177
|
+
p.get_from().resource,
|
178
|
+
ptype, # type: ignore
|
179
|
+
p["status"],
|
180
|
+
resources,
|
181
|
+
merge_resources(resources),
|
182
|
+
)
|
183
|
+
except NotImplementedError:
|
184
|
+
pass
|
185
|
+
if p.get_type() == "available":
|
186
|
+
await self.xmpp.pubsub.on_presence_available(p, None)
|
187
|
+
for contact in session.contacts:
|
188
|
+
await self.xmpp.pubsub.on_presence_available(p, contact)
|
189
|
+
|
184
190
|
|
185
191
|
_USEFUL_PRESENCES = {"available", "unavailable", "away", "chat", "dnd", "xa"}
|
186
192
|
|
@@ -3,7 +3,6 @@ from typing import TYPE_CHECKING
|
|
3
3
|
from slixmpp import JID, CoroutineCallback, Iq, StanzaPath
|
4
4
|
from slixmpp.exceptions import XMPPError
|
5
5
|
|
6
|
-
from ...db.models import GatewayUser
|
7
6
|
from .util import DispatcherMixin, exceptions_to_xmpp_errors
|
8
7
|
|
9
8
|
if TYPE_CHECKING:
|
@@ -32,10 +31,7 @@ class SearchMixin(DispatcherMixin):
|
|
32
31
|
"""
|
33
32
|
Prepare the search form using :attr:`.BaseSession.SEARCH_FIELDS`
|
34
33
|
"""
|
35
|
-
|
36
|
-
user = orm.query(GatewayUser).one_or_none()
|
37
|
-
if user is None:
|
38
|
-
raise XMPPError(text="Search is only allowed for registered users")
|
34
|
+
await self._get_session(iq)
|
39
35
|
|
40
36
|
xmpp = self.xmpp
|
41
37
|
|
@@ -172,7 +172,9 @@ def exceptions_to_xmpp_errors(cb: HandlerType) -> HandlerType:
|
|
172
172
|
except NotImplementedError:
|
173
173
|
log.debug("NotImplementedError raised in %s", cb)
|
174
174
|
raise XMPPError(
|
175
|
-
"feature-not-implemented",
|
175
|
+
"feature-not-implemented",
|
176
|
+
f"{cb.__name__} is not implemented by the legacy module",
|
177
|
+
clear=False,
|
176
178
|
)
|
177
179
|
except Exception as e:
|
178
180
|
log.error("Failed to handle incoming stanza: %s", args, exc_info=e)
|