slidge 0.2.0b0__tar.gz → 0.2.1__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {slidge-0.2.0b0 → slidge-0.2.1}/PKG-INFO +1 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/pyproject.toml +2 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/__version__.py +1 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/command/adhoc.py +31 -15
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/command/admin.py +11 -4
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/command/base.py +5 -2
- slidge-0.2.1/slidge/command/categories.py +13 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/command/chat_command.py +14 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/command/register.py +2 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/command/user.py +17 -9
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/contact/contact.py +3 -3
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/contact/roster.py +3 -3
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/config.py +6 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/presence.py +4 -5
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/session_dispatcher.py +2 -2
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/gateway.py +3 -3
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/attachment.py +2 -2
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/message.py +1 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +2 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/3071e0fa69d4_add_contact_client_type.py +1 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +6 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/abba1ae0edb3_store_avatar_legacy_id_in_the_contact_.py +7 -6
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +4 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/models.py +4 -2
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/group/room.py +2 -2
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/main.py +1 -1
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/__init__.py +29 -32
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/util/util.py +18 -0
- slidge-0.2.0b0/slidge/command/categories.py +0 -3
- {slidge-0.2.0b0 → slidge-0.2.1}/LICENSE +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/README.md +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/__main__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/command/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/contact/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/caps.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/disco.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/message/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/message/chat_state.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/message/marker.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/message/message.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/muc/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/muc/admin.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/muc/mam.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/muc/misc.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/muc/owner.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/muc/ping.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/registration.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/search.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/util.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/dispatcher/vcard.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/avatar.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/base.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/db.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/disco.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/lock.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/message_maker.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/message_text.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/presence.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/mixins/recipient.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/pubsub.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/core/session.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/env.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/old_user_store.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/script.py.mako +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/45c24cc73c91_add_bob.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/avatar.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/meta.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/store.py +2 -2
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/group/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/group/archive.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/group/bookmarks.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/group/participant.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/migration.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/py.typed +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/delivery_receipt.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/link_preview/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/link_preview/link_preview.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/link_preview/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/roster.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0077/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0077/register.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0077/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0100/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0100/gateway.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0100/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0153/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0153/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0153/vcard_avatar.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0264/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0264/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0264/thumbnail.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0292/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0292/vcard4.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0313/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0313/mam.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0313/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0317/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0317/hats.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0317/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0356_old/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0356_old/privilege.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0356_old/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0424/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0424/retraction.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0424/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0490/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0490/mds.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/slixfix/xep_0490/stanza.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/util/__init__.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/util/archive_msg.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/util/conf.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/util/db.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/util/test.py +0 -0
- {slidge-0.2.0b0 → slidge-0.2.1}/slidge/util/types.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "slidge"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.1"
|
4
4
|
description = "XMPP bridging framework"
|
5
5
|
authors = ["Nicolas Cedilnik <nicoco@nicoco.fr>"]
|
6
6
|
readme = "README.md"
|
@@ -51,6 +51,7 @@ xmldiff = "^2.5"
|
|
51
51
|
types-pillow = "^9.5.0.0"
|
52
52
|
pre-commit = "^3.3.0"
|
53
53
|
coverage = "^7.2.7"
|
54
|
+
emoji = "*"
|
54
55
|
|
55
56
|
[tool.poetry.group.dev.dependencies.slidge-dev-helpers]
|
56
57
|
git = "https://git.sr.ht/~nicoco/slidge-dev-helpers"
|
@@ -9,8 +9,11 @@ from slixmpp.exceptions import XMPPError
|
|
9
9
|
from slixmpp.plugins.xep_0004 import Form as SlixForm # type: ignore[attr-defined]
|
10
10
|
from slixmpp.plugins.xep_0030.stanza.items import DiscoItems
|
11
11
|
|
12
|
+
from ..core import config
|
13
|
+
from ..util.util import strip_leading_emoji
|
12
14
|
from . import Command, CommandResponseType, Confirmation, Form, TableResult
|
13
15
|
from .base import FormField
|
16
|
+
from .categories import CommandCategory
|
14
17
|
|
15
18
|
if TYPE_CHECKING:
|
16
19
|
from ..core.gateway import BaseGateway
|
@@ -46,19 +49,19 @@ class AdhocProvider:
|
|
46
49
|
return await self.__handle_result(session, result, adhoc_session)
|
47
50
|
|
48
51
|
async def __handle_category_list(
|
49
|
-
self, category:
|
52
|
+
self, category: CommandCategory, iq: Iq, adhoc_session: AdhocSessionType
|
50
53
|
) -> AdhocSessionType:
|
51
54
|
try:
|
52
55
|
session = self.xmpp.get_session_from_stanza(iq)
|
53
56
|
except XMPPError:
|
54
57
|
session = None
|
55
|
-
commands =
|
56
|
-
for command in self._categories[category]:
|
58
|
+
commands: dict[str, Command] = {}
|
59
|
+
for command in self._categories[category.node]:
|
57
60
|
try:
|
58
61
|
command.raise_if_not_authorized(iq.get_from())
|
59
62
|
except XMPPError:
|
60
63
|
continue
|
61
|
-
commands.
|
64
|
+
commands[command.NODE] = command
|
62
65
|
if len(commands) == 0:
|
63
66
|
raise XMPPError(
|
64
67
|
"not-authorized", "There is no command you can run in this category"
|
@@ -66,7 +69,7 @@ class AdhocProvider:
|
|
66
69
|
return await self.__handle_result(
|
67
70
|
session,
|
68
71
|
Form(
|
69
|
-
category,
|
72
|
+
category.name,
|
70
73
|
"",
|
71
74
|
[
|
72
75
|
FormField(
|
@@ -74,8 +77,11 @@ class AdhocProvider:
|
|
74
77
|
label="Command",
|
75
78
|
type="list-single",
|
76
79
|
options=[
|
77
|
-
{
|
78
|
-
|
80
|
+
{
|
81
|
+
"label": strip_leading_emoji_if_needed(command.NAME),
|
82
|
+
"value": command.NODE,
|
83
|
+
}
|
84
|
+
for command in commands.values()
|
79
85
|
],
|
80
86
|
)
|
81
87
|
],
|
@@ -86,12 +92,12 @@ class AdhocProvider:
|
|
86
92
|
|
87
93
|
async def __handle_category_choice(
|
88
94
|
self,
|
89
|
-
commands:
|
95
|
+
commands: dict[str, Command],
|
90
96
|
form_values: dict[str, str],
|
91
97
|
session: "BaseSession[Any, Any]",
|
92
98
|
jid: JID,
|
93
99
|
):
|
94
|
-
command = commands[
|
100
|
+
command = commands[form_values["command"]]
|
95
101
|
result = await self.__wrap_handler(command.run, session, jid)
|
96
102
|
return result
|
97
103
|
|
@@ -207,19 +213,23 @@ class AdhocProvider:
|
|
207
213
|
self.xmpp.plugin["xep_0050"].add_command( # type: ignore[no-untyped-call]
|
208
214
|
jid=jid,
|
209
215
|
node=command.NODE,
|
210
|
-
name=command.NAME,
|
216
|
+
name=strip_leading_emoji_if_needed(command.NAME),
|
211
217
|
handler=partial(self.__wrap_initial_handler, command),
|
212
218
|
)
|
213
219
|
else:
|
214
|
-
if category
|
215
|
-
|
220
|
+
if isinstance(category, str):
|
221
|
+
category = CommandCategory(category, category)
|
222
|
+
node = category.node
|
223
|
+
name = category.name
|
224
|
+
if node not in self._categories:
|
225
|
+
self._categories[node] = list[Command]()
|
216
226
|
self.xmpp.plugin["xep_0050"].add_command( # type: ignore[no-untyped-call]
|
217
227
|
jid=jid,
|
218
|
-
node=
|
219
|
-
name=
|
228
|
+
node=node,
|
229
|
+
name=strip_leading_emoji_if_needed(name),
|
220
230
|
handler=partial(self.__handle_category_list, category),
|
221
231
|
)
|
222
|
-
self._categories[
|
232
|
+
self._categories[node].append(command)
|
223
233
|
|
224
234
|
async def get_items(self, jid: JID, node: str, iq: Iq) -> DiscoItems:
|
225
235
|
"""
|
@@ -262,4 +272,10 @@ class AdhocProvider:
|
|
262
272
|
return filtered_items
|
263
273
|
|
264
274
|
|
275
|
+
def strip_leading_emoji_if_needed(text: str) -> str:
|
276
|
+
if config.STRIP_LEADING_EMOJI_ADHOC:
|
277
|
+
return strip_leading_emoji(text)
|
278
|
+
return text
|
279
|
+
|
280
|
+
|
265
281
|
log = logging.getLogger(__name__)
|
@@ -11,6 +11,7 @@ from slixmpp.exceptions import XMPPError
|
|
11
11
|
from ..core import config
|
12
12
|
from ..util.types import AnyBaseSession
|
13
13
|
from .base import (
|
14
|
+
NODE_PREFIX,
|
14
15
|
Command,
|
15
16
|
CommandAccess,
|
16
17
|
Confirmation,
|
@@ -21,6 +22,8 @@ from .base import (
|
|
21
22
|
)
|
22
23
|
from .categories import ADMINISTRATION
|
23
24
|
|
25
|
+
NODE_PREFIX = NODE_PREFIX + "admin/"
|
26
|
+
|
24
27
|
|
25
28
|
class AdminCommand(Command):
|
26
29
|
ACCESS = CommandAccess.ADMIN_ONLY
|
@@ -30,7 +33,8 @@ class AdminCommand(Command):
|
|
30
33
|
class ListUsers(AdminCommand):
|
31
34
|
NAME = "👤 List registered users"
|
32
35
|
HELP = "List the users registered to this gateway"
|
33
|
-
|
36
|
+
CHAT_COMMAND = "list_users"
|
37
|
+
NODE = NODE_PREFIX + CHAT_COMMAND
|
34
38
|
|
35
39
|
async def run(self, _session, _ifrom, *_):
|
36
40
|
items = []
|
@@ -51,7 +55,8 @@ class ListUsers(AdminCommand):
|
|
51
55
|
class SlidgeInfo(AdminCommand):
|
52
56
|
NAME = "ℹ️ Server information"
|
53
57
|
HELP = "List the users registered to this gateway"
|
54
|
-
|
58
|
+
CHAT_COMMAND = "info"
|
59
|
+
NODE = NODE_PREFIX + CHAT_COMMAND
|
55
60
|
ACCESS = CommandAccess.ANY
|
56
61
|
|
57
62
|
async def run(self, _session, _ifrom, *_):
|
@@ -105,7 +110,8 @@ class SlidgeInfo(AdminCommand):
|
|
105
110
|
class DeleteUser(AdminCommand):
|
106
111
|
NAME = "❌ Delete a user"
|
107
112
|
HELP = "Unregister a user from the gateway"
|
108
|
-
|
113
|
+
CHAT_COMMAND = "delete_user"
|
114
|
+
NODE = NODE_PREFIX + CHAT_COMMAND
|
109
115
|
|
110
116
|
async def run(self, _session, _ifrom, *_):
|
111
117
|
return Form(
|
@@ -141,7 +147,8 @@ class DeleteUser(AdminCommand):
|
|
141
147
|
class ChangeLoglevel(AdminCommand):
|
142
148
|
NAME = "📋 Change the verbosity of the logs"
|
143
149
|
HELP = "Set the logging level"
|
144
|
-
|
150
|
+
CHAT_COMMAND = "loglevel"
|
151
|
+
NODE = NODE_PREFIX + CHAT_COMMAND
|
145
152
|
|
146
153
|
async def run(self, _session, _ifrom, *_):
|
147
154
|
return Form(
|
@@ -25,9 +25,12 @@ from slixmpp.types import JidStr
|
|
25
25
|
from ..core import config
|
26
26
|
from ..util.types import AnyBaseSession, FieldType
|
27
27
|
|
28
|
+
NODE_PREFIX = "https://slidge.im/command/core/"
|
29
|
+
|
28
30
|
if TYPE_CHECKING:
|
29
31
|
from ..core.gateway import BaseGateway
|
30
32
|
from ..core.session import BaseSession
|
33
|
+
from .categories import CommandCategory
|
31
34
|
|
32
35
|
|
33
36
|
HandlerType = Union[
|
@@ -178,8 +181,8 @@ class Form:
|
|
178
181
|
"""
|
179
182
|
form = SlixForm() # type: ignore[no-untyped-call]
|
180
183
|
form["type"] = "form"
|
181
|
-
form["instructions"] = self.instructions
|
182
184
|
form["title"] = self.title
|
185
|
+
form["instructions"] = self.instructions
|
183
186
|
for fi in self.fields:
|
184
187
|
form.append(fi.get_xml())
|
185
188
|
return form
|
@@ -347,7 +350,7 @@ class Command(ABC):
|
|
347
350
|
Who can use this command
|
348
351
|
"""
|
349
352
|
|
350
|
-
CATEGORY: Optional[str] = None
|
353
|
+
CATEGORY: Optional[Union[str, "CommandCategory"]] = None
|
351
354
|
"""
|
352
355
|
If used, the command will be under this top-level category.
|
353
356
|
Use the same string for several commands to group them.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from typing import NamedTuple
|
2
|
+
|
3
|
+
from .base import NODE_PREFIX
|
4
|
+
|
5
|
+
|
6
|
+
class CommandCategory(NamedTuple):
|
7
|
+
name: str
|
8
|
+
node: str
|
9
|
+
|
10
|
+
|
11
|
+
ADMINISTRATION = CommandCategory("🛷️ Slidge administration", NODE_PREFIX + "admin")
|
12
|
+
CONTACTS = CommandCategory("👤 Contacts", NODE_PREFIX + "contacts")
|
13
|
+
GROUPS = CommandCategory("👥 Groups", NODE_PREFIX + "groups")
|
@@ -13,6 +13,7 @@ from slixmpp.exceptions import XMPPError
|
|
13
13
|
from slixmpp.types import JidStr, MessageTypes
|
14
14
|
|
15
15
|
from . import Command, CommandResponseType, Confirmation, Form, TableResult
|
16
|
+
from .categories import CommandCategory
|
16
17
|
|
17
18
|
if TYPE_CHECKING:
|
18
19
|
from ..core.gateway import BaseGateway
|
@@ -280,7 +281,19 @@ class ChatCommandProvider:
|
|
280
281
|
def _help(self, mfrom: JID):
|
281
282
|
msg = "Available commands:"
|
282
283
|
for c in sorted(
|
283
|
-
self._commands.values(),
|
284
|
+
self._commands.values(),
|
285
|
+
key=lambda co: (
|
286
|
+
(
|
287
|
+
co.CATEGORY
|
288
|
+
if isinstance(co.CATEGORY, str)
|
289
|
+
else (
|
290
|
+
co.CATEGORY.name
|
291
|
+
if isinstance(co.CATEGORY, CommandCategory)
|
292
|
+
else ""
|
293
|
+
)
|
294
|
+
),
|
295
|
+
co.CHAT_COMMAND,
|
296
|
+
),
|
284
297
|
):
|
285
298
|
try:
|
286
299
|
c.raise_if_not_authorized(mfrom)
|
@@ -75,7 +75,8 @@ class Register(Command):
|
|
75
75
|
self.xmpp.event("user_register", Iq(sfrom=ifrom.bare))
|
76
76
|
return self.SUCCESS_MESSAGE
|
77
77
|
|
78
|
-
async def run(self, _session,
|
78
|
+
async def run(self, _session, ifrom: JID, *_):
|
79
|
+
self.xmpp.raise_if_not_allowed_jid(ifrom)
|
79
80
|
return Form(
|
80
81
|
title=f"Registration to '{self.xmpp.COMPONENT_NAME}'",
|
81
82
|
instructions=self.xmpp.REGISTRATION_INSTRUCTIONS,
|
@@ -26,8 +26,8 @@ if TYPE_CHECKING:
|
|
26
26
|
class Search(Command):
|
27
27
|
NAME = "🔎 Search for contacts"
|
28
28
|
HELP = "Search for contacts via this gateway"
|
29
|
-
NODE = "search"
|
30
29
|
CHAT_COMMAND = "find"
|
30
|
+
NODE = CONTACTS.node + "/" + CHAT_COMMAND
|
31
31
|
ACCESS = CommandAccess.USER_LOGGED
|
32
32
|
CATEGORY = CONTACTS
|
33
33
|
|
@@ -64,7 +64,8 @@ class SyncContacts(Command):
|
|
64
64
|
"Synchronize your XMPP roster with your legacy contacts. "
|
65
65
|
"Slidge will only add/remove/modify contacts in its dedicated roster group"
|
66
66
|
)
|
67
|
-
|
67
|
+
CHAT_COMMAND = "sync-contacts"
|
68
|
+
NODE = CONTACTS.node + "/" + CHAT_COMMAND
|
68
69
|
ACCESS = CommandAccess.USER_LOGGED
|
69
70
|
CATEGORY = CONTACTS
|
70
71
|
|
@@ -123,7 +124,8 @@ class SyncContacts(Command):
|
|
123
124
|
|
124
125
|
class ListContacts(Command):
|
125
126
|
NAME = HELP = "👤 List your legacy contacts"
|
126
|
-
|
127
|
+
CHAT_COMMAND = "contacts"
|
128
|
+
NODE = CONTACTS.node + "/" + CHAT_COMMAND
|
127
129
|
ACCESS = CommandAccess.USER_LOGGED
|
128
130
|
CATEGORY = CONTACTS
|
129
131
|
|
@@ -143,7 +145,8 @@ class ListContacts(Command):
|
|
143
145
|
|
144
146
|
class ListGroups(Command):
|
145
147
|
NAME = HELP = "👥 List your legacy groups"
|
146
|
-
|
148
|
+
CHAT_COMMAND = "groups"
|
149
|
+
NODE = GROUPS.node + "/" + CHAT_COMMAND
|
147
150
|
ACCESS = CommandAccess.USER_LOGGED
|
148
151
|
CATEGORY = GROUPS
|
149
152
|
|
@@ -162,7 +165,8 @@ class ListGroups(Command):
|
|
162
165
|
class Login(Command):
|
163
166
|
NAME = "🔐 Re-login to the legacy network"
|
164
167
|
HELP = "Login to the legacy service"
|
165
|
-
|
168
|
+
CHAT_COMMAND = "re-login"
|
169
|
+
NODE = "https://slidge.im/command/core/" + CHAT_COMMAND
|
166
170
|
|
167
171
|
ACCESS = CommandAccess.USER_NON_LOGGED
|
168
172
|
|
@@ -184,7 +188,8 @@ class Login(Command):
|
|
184
188
|
class CreateGroup(Command):
|
185
189
|
NAME = "🆕 New legacy group"
|
186
190
|
HELP = "Create a group on the legacy service"
|
187
|
-
|
191
|
+
CHAT_COMMAND = "create-group"
|
192
|
+
NODE = GROUPS.node + "/" + CHAT_COMMAND
|
188
193
|
CATEGORY = GROUPS
|
189
194
|
|
190
195
|
ACCESS = CommandAccess.USER_LOGGED
|
@@ -233,7 +238,8 @@ class CreateGroup(Command):
|
|
233
238
|
class Preferences(Command):
|
234
239
|
NAME = "⚙️ Preferences"
|
235
240
|
HELP = "Customize the gateway behaviour to your liking"
|
236
|
-
|
241
|
+
CHAT_COMMAND = "preferences"
|
242
|
+
NODE = "https://slidge.im/command/core/preferences"
|
237
243
|
ACCESS = CommandAccess.USER
|
238
244
|
|
239
245
|
async def run(
|
@@ -268,7 +274,8 @@ class Preferences(Command):
|
|
268
274
|
class Unregister(Command):
|
269
275
|
NAME = "❌ Unregister from the gateway"
|
270
276
|
HELP = "Unregister from the gateway"
|
271
|
-
|
277
|
+
CHAT_COMMAND = "unregister"
|
278
|
+
NODE = "https://slidge.im/command/core/unregister"
|
272
279
|
ACCESS = CommandAccess.USER
|
273
280
|
|
274
281
|
async def run(
|
@@ -290,7 +297,8 @@ class Unregister(Command):
|
|
290
297
|
|
291
298
|
class LeaveGroup(Command):
|
292
299
|
NAME = HELP = "❌ Leave a legacy group"
|
293
|
-
|
300
|
+
CHAT_COMMAND = "leave-group"
|
301
|
+
NODE = GROUPS.node + "/" + CHAT_COMMAND
|
294
302
|
ACCESS = CommandAccess.USER_LOGGED
|
295
303
|
CATEGORY = GROUPS
|
296
304
|
|
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Generic, Iterable, Optional, Self, Union
|
|
6
6
|
from xml.etree import ElementTree as ET
|
7
7
|
|
8
8
|
from slixmpp import JID, Message, Presence
|
9
|
-
from slixmpp.exceptions import IqError
|
9
|
+
from slixmpp.exceptions import IqError, IqTimeout
|
10
10
|
from slixmpp.plugins.xep_0292.stanza import VCard4
|
11
11
|
from slixmpp.types import MessageTypes
|
12
12
|
|
@@ -454,7 +454,7 @@ class LegacyContact(
|
|
454
454
|
except PermissionError:
|
455
455
|
warnings.warn(
|
456
456
|
"Slidge does not have privileges to add contacts to the roster. Refer"
|
457
|
-
" to https://slidge.
|
457
|
+
" to https://slidge.im/core/admin/privilege.html for"
|
458
458
|
" more info."
|
459
459
|
)
|
460
460
|
if config.ROSTER_PUSH_PRESENCE_SUBSCRIPTION_REQUEST_FALLBACK:
|
@@ -463,7 +463,7 @@ class LegacyContact(
|
|
463
463
|
"slidge is not allowed to manage your roster."
|
464
464
|
)
|
465
465
|
return
|
466
|
-
except IqError as e:
|
466
|
+
except (IqError, IqTimeout) as e:
|
467
467
|
self.log.warning("Could not add to roster", exc_info=e)
|
468
468
|
else:
|
469
469
|
# we only broadcast pubsub events for contacts added to the roster
|
@@ -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, XMPPError
|
7
|
+
from slixmpp.exceptions import IqError, IqTimeout, XMPPError
|
8
8
|
from slixmpp.jid import JID_UNESCAPE_TRANSFORMATIONS, _unescape_node
|
9
9
|
|
10
10
|
from ..core.mixins.lock import NamedLockMixin
|
@@ -210,7 +210,7 @@ class LegacyRoster(
|
|
210
210
|
self.session.user_jid.bare
|
211
211
|
)
|
212
212
|
user_roster = iq["roster"]["items"]
|
213
|
-
except (PermissionError, IqError):
|
213
|
+
except (PermissionError, IqError, IqTimeout):
|
214
214
|
user_roster = None
|
215
215
|
|
216
216
|
with self.__store.session() as orm:
|
@@ -232,7 +232,7 @@ class LegacyRoster(
|
|
232
232
|
self.session.user_jid.bare,
|
233
233
|
item,
|
234
234
|
)
|
235
|
-
except (PermissionError, IqError) as e:
|
235
|
+
except (PermissionError, IqError, IqTimeout) as e:
|
236
236
|
warnings.warn(f"Could not add to roster: {e}")
|
237
237
|
else:
|
238
238
|
contact._added_to_roster = True
|
@@ -214,3 +214,9 @@ DEV_MODE__DOC = (
|
|
214
214
|
"Enables an interactive python shell via chat commands, for admins."
|
215
215
|
"Not safe to use in prod, but great during dev."
|
216
216
|
)
|
217
|
+
|
218
|
+
STRIP_LEADING_EMOJI_ADHOC = False
|
219
|
+
STRIP_LEADING_EMOJI_ADHOC__DOC = (
|
220
|
+
"Strip the leading emoji in ad-hoc command names, if present, in case you "
|
221
|
+
"are a emoji-hater."
|
222
|
+
)
|
@@ -154,14 +154,13 @@ class PresenceHandlerMixin(DispatcherMixin):
|
|
154
154
|
# when setting a status message, or going away, etc.
|
155
155
|
return
|
156
156
|
|
157
|
-
# We can't use XMPPError here because
|
157
|
+
# We can't use XMPPError here because XMPPError does not have a way to
|
158
|
+
# add the <x xmlns="http://jabber.org/protocol/muc" /> element
|
158
159
|
|
159
|
-
error_from = JID(muc.jid)
|
160
|
-
error_from.resource = muc.user_nick
|
161
160
|
error_stanza = p.error()
|
162
161
|
error_stanza.set_to(p.get_from())
|
163
|
-
error_stanza.set_from(
|
164
|
-
error_stanza.enable("muc_join")
|
162
|
+
error_stanza.set_from(pto)
|
163
|
+
error_stanza.enable("muc_join") # <x xmlns="http://jabber.org/protocol/muc" />
|
165
164
|
error_stanza.enable("error")
|
166
165
|
error_stanza["error"]["type"] = "cancel"
|
167
166
|
error_stanza["error"]["by"] = muc.jid
|
@@ -2,7 +2,7 @@ import logging
|
|
2
2
|
from typing import TYPE_CHECKING
|
3
3
|
|
4
4
|
from slixmpp import Message
|
5
|
-
from slixmpp.exceptions import IqError
|
5
|
+
from slixmpp.exceptions import IqError, IqTimeout
|
6
6
|
from slixmpp.plugins.xep_0084.stanza import Info
|
7
7
|
|
8
8
|
from ..session import BaseSession
|
@@ -59,7 +59,7 @@ class SessionDispatcher(
|
|
59
59
|
iq = await self.xmpp.plugin["xep_0084"].retrieve_avatar(
|
60
60
|
session.user_jid, hash_, ifrom=self.xmpp.boundjid.bare
|
61
61
|
)
|
62
|
-
except IqError as e:
|
62
|
+
except (IqError, IqTimeout) as e:
|
63
63
|
session.log.warning("Could not fetch the user's avatar: %s", e)
|
64
64
|
return
|
65
65
|
bytes_ = iq["pubsub"]["items"]["item"]["avatar_data"]["value"]
|
@@ -429,7 +429,7 @@ class BaseGateway(
|
|
429
429
|
try:
|
430
430
|
await self["xep_0100"].add_component_to_roster(user.jid)
|
431
431
|
await self.__add_component_to_mds_whitelist(user.jid)
|
432
|
-
except IqError as e:
|
432
|
+
except (IqError, IqTimeout) as e:
|
433
433
|
# TODO: remove the user when this happens? or at least
|
434
434
|
# this can happen when the user has unsubscribed from the XMPP server
|
435
435
|
log.warning(
|
@@ -464,7 +464,7 @@ class BaseGateway(
|
|
464
464
|
"create the MDS node of %s",
|
465
465
|
user_jid,
|
466
466
|
)
|
467
|
-
except IqError as e:
|
467
|
+
except (IqError, IqTimeout) as e:
|
468
468
|
# conflict this means the node already exists, we can ignore that
|
469
469
|
if e.condition != "conflict":
|
470
470
|
log.exception(
|
@@ -548,7 +548,7 @@ class BaseGateway(
|
|
548
548
|
self.xmpp.plugin["xep_0084"].stanza.MetaData.namespace,
|
549
549
|
ifrom=self.boundjid.bare,
|
550
550
|
)
|
551
|
-
except IqError:
|
551
|
+
except (IqError, IqTimeout):
|
552
552
|
self.xmpp.store.users.set_avatar_hash(session.user_pk, None)
|
553
553
|
return
|
554
554
|
await self.__dispatcher.on_avatar_metadata_info(
|
@@ -19,7 +19,7 @@ from xml.etree import ElementTree as ET
|
|
19
19
|
import thumbhash
|
20
20
|
from PIL import Image, ImageOps
|
21
21
|
from slixmpp import JID, Message
|
22
|
-
from slixmpp.exceptions import IqError
|
22
|
+
from slixmpp.exceptions import IqError, IqTimeout
|
23
23
|
from slixmpp.plugins.xep_0363 import FileUploadError
|
24
24
|
from slixmpp.plugins.xep_0447.stanza import StatelessFileSharing
|
25
25
|
|
@@ -65,7 +65,7 @@ class AttachmentMixin(TextMessageMixin):
|
|
65
65
|
ifrom=config.UPLOAD_REQUESTER or self.xmpp.boundjid,
|
66
66
|
domain=JID(domain),
|
67
67
|
)
|
68
|
-
except (FileUploadError, IqError) as e:
|
68
|
+
except (FileUploadError, IqError, IqTimeout) as e:
|
69
69
|
warnings.warn(f"Something is wrong with the upload service: {e!r}")
|
70
70
|
return None
|
71
71
|
finally:
|
@@ -172,7 +172,7 @@ class CarbonMessageMixin(ContentMessageMixin, MarkerMixin):
|
|
172
172
|
warnings.warn(
|
173
173
|
"Slidge does not have privileges to send message on behalf of"
|
174
174
|
" user.Refer to"
|
175
|
-
" https://slidge.
|
175
|
+
" https://slidge.im/core/admin/privilege.html"
|
176
176
|
" for more info."
|
177
177
|
)
|
178
178
|
|
@@ -95,6 +95,12 @@ def upgrade() -> None:
|
|
95
95
|
op.add_column("room", sa.Column("description", sa.String(), nullable=True))
|
96
96
|
op.add_column("room", sa.Column("subject", sa.String(), nullable=True))
|
97
97
|
op.add_column("room", sa.Column("subject_date", sa.DateTime(), nullable=True))
|
98
|
+
|
99
|
+
if op.get_bind().engine.name == "postgresql":
|
100
|
+
op.execute(
|
101
|
+
"CREATE TYPE muctype AS ENUM ('GROUP', 'CHANNEL', 'CHANNEL_NON_ANONYMOUS')"
|
102
|
+
)
|
103
|
+
|
98
104
|
op.add_column(
|
99
105
|
"room",
|
100
106
|
sa.Column(
|
@@ -37,12 +37,13 @@ def upgrade() -> None:
|
|
37
37
|
|
38
38
|
with op.batch_alter_table("room", schema=None) as batch_op:
|
39
39
|
batch_op.add_column(sa.Column("avatar_legacy_id", sa.String(), nullable=True))
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
if op.get_bind().engine.name != "postgresql":
|
41
|
+
batch_op.create_unique_constraint(
|
42
|
+
"uq_room_user_account_id_jid", ["user_account_id", "jid"]
|
43
|
+
)
|
44
|
+
batch_op.create_unique_constraint(
|
45
|
+
"uq_room_user_account_id_legacy_id", ["user_account_id", "legacy_id"]
|
46
|
+
)
|
46
47
|
|
47
48
|
for room_pk, avatar_legacy_id in room_avatars:
|
48
49
|
conn.execute(
|
@@ -24,6 +24,10 @@ def upgrade() -> None:
|
|
24
24
|
# since we don't want source to be nullable, we drop all rows first.
|
25
25
|
# This is what you get by using alpha versions!
|
26
26
|
op.execute(sa.delete(ArchivedMessage))
|
27
|
+
|
28
|
+
if op.get_bind().engine.name == "postgresql":
|
29
|
+
op.execute("CREATE TYPE archivedmessagesource AS ENUM ('LIVE', 'BACKFILL')")
|
30
|
+
|
27
31
|
# ### commands auto generated by Alembic - please adjust! ###
|
28
32
|
|
29
33
|
with op.batch_alter_table("mam", schema=None) as batch_op:
|
@@ -235,7 +235,9 @@ class Room(Base):
|
|
235
235
|
updated: Mapped[bool] = mapped_column(default=False)
|
236
236
|
|
237
237
|
participants: Mapped[list["Participant"]] = relationship(
|
238
|
-
back_populates="room",
|
238
|
+
back_populates="room",
|
239
|
+
primaryjoin="Participant.room_id == Room.id",
|
240
|
+
cascade="all, delete-orphan",
|
239
241
|
)
|
240
242
|
|
241
243
|
avatar_legacy_id: Mapped[Optional[str]] = mapped_column(nullable=True)
|
@@ -317,7 +319,7 @@ class LegacyIdsMulti(Base):
|
|
317
319
|
|
318
320
|
legacy_id: Mapped[str] = mapped_column(nullable=False)
|
319
321
|
xmpp_ids: Mapped[list["XmppIdsMulti"]] = relationship(
|
320
|
-
back_populates="legacy_ids_multi"
|
322
|
+
back_populates="legacy_ids_multi", cascade="all, delete-orphan"
|
321
323
|
)
|
322
324
|
|
323
325
|
|
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, AsyncIterator, Generic, Optional, Self, Union
|
|
9
9
|
from uuid import uuid4
|
10
10
|
|
11
11
|
from slixmpp import JID, Iq, Message, Presence
|
12
|
-
from slixmpp.exceptions import IqError, XMPPError
|
12
|
+
from slixmpp.exceptions import IqError, IqTimeout, XMPPError
|
13
13
|
from slixmpp.jid import _unescape_node
|
14
14
|
from slixmpp.plugins.xep_0004 import Form
|
15
15
|
from slixmpp.plugins.xep_0060.stanza import Item
|
@@ -1029,7 +1029,7 @@ class LegacyMUC(
|
|
1029
1029
|
# (slixmpp annoying magic)
|
1030
1030
|
item = ans["pubsub"]["items"]["item"]
|
1031
1031
|
item["id"] = self.jid
|
1032
|
-
except IqError:
|
1032
|
+
except (IqError, IqTimeout):
|
1033
1033
|
item["conference"]["autojoin"] = auto_join
|
1034
1034
|
except PermissionError:
|
1035
1035
|
warnings.warn(
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# This module contains patches for slixmpp; some have pending requests upstream
|
2
2
|
# and should be removed on the next slixmpp release.
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
# ruff: noqa: F401
|
5
5
|
|
6
6
|
import slixmpp.plugins
|
7
|
-
from slixmpp import Message
|
7
|
+
from slixmpp import Iq, Message
|
8
|
+
from slixmpp.exceptions import XMPPError
|
8
9
|
from slixmpp.plugins.xep_0050 import XEP_0050, Command
|
9
|
-
from slixmpp.plugins.
|
10
|
+
from slixmpp.plugins.xep_0231 import XEP_0231
|
10
11
|
from slixmpp.xmlstream import StanzaBase
|
11
12
|
|
12
13
|
from . import ( # xep_0356,
|
@@ -23,36 +24,33 @@ from . import ( # xep_0356,
|
|
23
24
|
xep_0490,
|
24
25
|
)
|
25
26
|
|
26
|
-
# ruff: noqa: F401
|
27
27
|
|
28
|
+
async def _handle_bob_iq(self, iq: Iq):
|
29
|
+
cid = iq["bob"]["cid"]
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
"""
|
33
|
-
|
31
|
+
if iq["type"] == "result":
|
32
|
+
await self.api["set_bob"](iq["from"], None, iq["to"], args=iq["bob"])
|
33
|
+
self.xmpp.event("bob", iq)
|
34
|
+
elif iq["type"] == "get":
|
35
|
+
data = await self.api["get_bob"](iq["to"], None, iq["from"], args=cid)
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
if
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
self.xmpp.event("privileges_advertised")
|
53
|
-
|
54
|
-
|
55
|
-
XEP_0356._handle_privilege = _handle_privilege
|
37
|
+
if data is None:
|
38
|
+
raise XMPPError(
|
39
|
+
"item-not-found",
|
40
|
+
f"Bits of binary '{cid}' is not available.",
|
41
|
+
)
|
42
|
+
|
43
|
+
if isinstance(data, Iq):
|
44
|
+
data["id"] = iq["id"]
|
45
|
+
data.send()
|
46
|
+
return
|
47
|
+
|
48
|
+
iq = iq.reply()
|
49
|
+
iq.append(data)
|
50
|
+
iq.send()
|
51
|
+
|
52
|
+
|
53
|
+
XEP_0231._handle_bob_iq = _handle_bob_iq
|
56
54
|
|
57
55
|
|
58
56
|
def session_bind(self, jid):
|
@@ -98,4 +96,3 @@ slixmpp.plugins.PLUGINS.extend(
|
|
98
96
|
|
99
97
|
|
100
98
|
Message.reply = reply # type: ignore
|
101
|
-
log = logging.getLogger(__name__)
|
@@ -9,6 +9,13 @@ from pathlib import Path
|
|
9
9
|
from time import time
|
10
10
|
from typing import TYPE_CHECKING, Callable, NamedTuple, Optional, Type, TypeVar
|
11
11
|
|
12
|
+
try:
|
13
|
+
import emoji
|
14
|
+
except ImportError:
|
15
|
+
EMOJI_LIB_AVAILABLE = False
|
16
|
+
else:
|
17
|
+
EMOJI_LIB_AVAILABLE = True
|
18
|
+
|
12
19
|
from .types import Mention, ResourceDict
|
13
20
|
|
14
21
|
if TYPE_CHECKING:
|
@@ -318,3 +325,14 @@ def timeit(func):
|
|
318
325
|
return r
|
319
326
|
|
320
327
|
return wrapped
|
328
|
+
|
329
|
+
|
330
|
+
def strip_leading_emoji(text: str) -> str:
|
331
|
+
if not EMOJI_LIB_AVAILABLE:
|
332
|
+
return text
|
333
|
+
words = text.split(" ")
|
334
|
+
# is_emoji returns False for 🛷️ for obscure reasons,
|
335
|
+
# purely_emoji seems better
|
336
|
+
if len(words) > 1 and emoji.purely_emoji(words[0]):
|
337
|
+
return " ".join(words[1:])
|
338
|
+
return text
|
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
|
File without changes
|
{slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{slidge-0.2.0b0 → slidge-0.2.1}/slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1001,9 +1001,9 @@ class ParticipantStore(EngineMixin):
|
|
1001
1001
|
def __init__(self, *a, **kw):
|
1002
1002
|
super().__init__(*a, **kw)
|
1003
1003
|
with self.session() as session:
|
1004
|
-
session.execute(delete(Participant))
|
1005
|
-
session.execute(delete(Hat))
|
1006
1004
|
session.execute(delete(participant_hats))
|
1005
|
+
session.execute(delete(Hat))
|
1006
|
+
session.execute(delete(Participant))
|
1007
1007
|
session.commit()
|
1008
1008
|
|
1009
1009
|
def add(self, room_pk: int, nickname: str) -> int:
|
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
|