slidge 0.2.6__py3-none-any.whl → 0.2.7__py3-none-any.whl

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/__version__.py CHANGED
@@ -2,4 +2,4 @@ from slidge.util.util import get_version # noqa: F401
2
2
 
3
3
  # this is modified before publish, but if someone cloned from the repo,
4
4
  # it can help
5
- __version__ = "v0.2.6"
5
+ __version__ = "v0.2.7"
slidge/command/adhoc.py CHANGED
@@ -235,12 +235,17 @@ class AdhocProvider:
235
235
  """
236
236
  Get items for a disco query
237
237
 
238
- :param jid: who is requesting the disco
238
+ :param jid: the entity that should return its items
239
239
  :param node: which command node is requested
240
240
  :param iq: the disco query IQ
241
241
  :return: commands accessible to the given JID will be listed
242
242
  """
243
- if not self.xmpp.jid_validator.match(str(jid)) and jid not in config.ADMINS:
243
+ ifrom = iq.get_from()
244
+ ifrom_str = str(ifrom)
245
+ if (
246
+ not self.xmpp.jid_validator.match(ifrom_str)
247
+ and ifrom_str not in config.ADMINS
248
+ ):
244
249
  raise XMPPError(
245
250
  "forbidden",
246
251
  "You are not authorized to execute adhoc commands on this gateway. "
@@ -253,8 +258,6 @@ class AdhocProvider:
253
258
  if not all_items:
254
259
  return DiscoItems()
255
260
 
256
- ifrom = iq.get_from()
257
-
258
261
  filtered_items = DiscoItems()
259
262
  filtered_items["node"] = self.xmpp.plugin["xep_0050"].stanza.Command.namespace
260
263
  for item in all_items:
slidge/group/room.py CHANGED
@@ -14,6 +14,7 @@ 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
16
16
  from slixmpp.plugins.xep_0082 import parse as str_to_datetime
17
+ from slixmpp.plugins.xep_0469.stanza import NS as PINNING_NS
17
18
  from slixmpp.xmlstream import ET
18
19
 
19
20
  from ..contact.contact import LegacyContact
@@ -26,6 +27,7 @@ from ..core.mixins.disco import ChatterDiscoMixin
26
27
  from ..core.mixins.lock import NamedLockMixin
27
28
  from ..core.mixins.recipient import ReactionRecipientMixin, ThreadRecipientMixin
28
29
  from ..db.models import Room
30
+ from ..slixfix.xep_0492.stanza import NS as NOTIFY_NS
29
31
  from ..slixfix.xep_0492.stanza import WhenLiteral
30
32
  from ..util import ABCSubclassableOnceAtMost
31
33
  from ..util.types import (
@@ -231,7 +233,7 @@ class LegacyMUC(
231
233
  self._participants_filled = True
232
234
  async for p in self.fill_participants():
233
235
  self.__participants_store.update(p)
234
- self.__store.set_participants_filled(self.pk)
236
+ self.__store.set_participants_filled(self.pk)
235
237
 
236
238
  async def get_participants(self) -> AsyncIterator[LegacyParticipant]:
237
239
  assert self.pk is not None
@@ -248,19 +250,21 @@ class LegacyMUC(
248
250
  async with self.lock("fill participants"):
249
251
  self._participants_filled = True
250
252
  # We only fill the participants list if/when the MUC is first
251
- # joined by an XMPP client. But we may have instantiated
253
+ # joined by an XMPP client. But we may have instantiated some before.
252
254
  resources = set[str]()
255
+ async for participant in self.fill_participants():
256
+ # TODO: batch SQL update at the end of this function for perf?
257
+ self.__store_participant(participant)
258
+ yield participant
259
+ resources.add(participant.jid.resource)
253
260
  for db_participant in self.xmpp.store.participants.get_all(
254
261
  self.pk, user_included=True
255
262
  ):
256
263
  participant = self.Participant.from_store(
257
264
  self.session, db_participant, muc=self
258
265
  )
259
- resources.add(participant.jid.resource)
260
- yield participant
261
- async for p in self.fill_participants():
262
- if p.jid.resource not in resources:
263
- yield p
266
+ if participant.jid.resource not in resources:
267
+ yield participant
264
268
  self.__store.set_participants_filled(self.pk)
265
269
  return
266
270
 
@@ -687,6 +691,8 @@ class LegacyMUC(
687
691
  assert self.pk is not None
688
692
  p.pk = self.__participants_store.add(self.pk, p.nickname)
689
693
  self.__participants_store.update(p)
694
+ if p._hats:
695
+ self.__participants_store.set_hats(p.pk, p._hats)
690
696
 
691
697
  async def get_participant(
692
698
  self,
@@ -995,6 +1001,32 @@ class LegacyMUC(
995
1001
  p["muc"]["status_codes"] = {110, 333}
996
1002
  p.send()
997
1003
 
1004
+ async def __get_bookmark(self) -> Item | None:
1005
+ item = Item()
1006
+ item["id"] = self.jid
1007
+
1008
+ iq = Iq(stype="get", sfrom=self.user_jid, sto=self.user_jid)
1009
+ iq["pubsub"]["items"]["node"] = self.xmpp["xep_0402"].stanza.NS
1010
+ iq["pubsub"]["items"].append(item)
1011
+
1012
+ try:
1013
+ ans = await self.xmpp["xep_0356"].send_privileged_iq(iq)
1014
+ if len(ans["pubsub"]["items"]) != 1:
1015
+ return None
1016
+ # this below creates the item if it wasn't here already
1017
+ # (slixmpp annoying magic)
1018
+ item = ans["pubsub"]["items"]["item"]
1019
+ item["id"] = self.jid
1020
+ return item
1021
+ except (IqError, IqTimeout) as exc:
1022
+ warnings.warn(f"Cannot fetch bookmark: {exc}")
1023
+ return None
1024
+ except PermissionError:
1025
+ warnings.warn(
1026
+ "IQ privileges (XEP0356) are not set, we cannot fetch the user bookmarks"
1027
+ )
1028
+ return None
1029
+
998
1030
  async def add_to_bookmarks(
999
1031
  self,
1000
1032
  auto_join=True,
@@ -1026,68 +1058,90 @@ class LegacyMUC(
1026
1058
  If set to ``None`` (default), the setting will be untouched. Only the "global"
1027
1059
  notification setting is supported (ie, per client type is not possible).
1028
1060
  """
1029
- item = Item()
1030
- item["id"] = self.jid
1061
+ existing = await self.__get_bookmark() if preserve else None
1031
1062
 
1032
- iq = Iq(stype="get", sfrom=self.user_jid, sto=self.user_jid)
1033
- iq["pubsub"]["items"]["node"] = self.xmpp["xep_0402"].stanza.NS
1034
- iq["pubsub"]["items"].append(item)
1063
+ new = Item()
1064
+ new["id"] = self.jid
1065
+ new["conference"]["nick"] = self.user_nick
1035
1066
 
1036
- is_update = False
1037
- if preserve:
1038
- try:
1039
- ans = await self.xmpp["xep_0356"].send_privileged_iq(iq)
1040
- is_update = len(ans["pubsub"]["items"]) == 1
1041
- # this below creates the item if it wasn't here already
1042
- # (slixmpp annoying magic)
1043
- item = ans["pubsub"]["items"]["item"]
1044
- item["id"] = self.jid
1045
- except (IqError, IqTimeout):
1046
- item["conference"]["autojoin"] = auto_join
1047
- except PermissionError:
1048
- warnings.warn(
1049
- "IQ privileges (XEP0356) are not set, we cannot fetch the user bookmarks"
1050
- )
1051
- else:
1052
- # if the bookmark is already present, we preserve it as much as
1053
- # possible, especially custom <extensions>
1054
- self.log.debug("Existing: %s", item)
1055
- # if it's an update, we do not touch the auto join flag
1056
- if not is_update:
1057
- item["conference"]["autojoin"] = auto_join
1067
+ if existing is None:
1068
+ change = True
1069
+ new["conference"]["autojoin"] = auto_join
1058
1070
  else:
1059
- item["conference"]["autojoin"] = auto_join
1060
-
1061
- item["conference"]["nick"] = self.user_nick
1071
+ change = False
1072
+ new["conference"]["autojoin"] = existing["conference"]["autojoin"]
1073
+
1074
+ existing_extensions = existing is not None and existing[
1075
+ "conference"
1076
+ ].get_plugin("extensions", check=True)
1077
+
1078
+ # preserving extensions we don't know about is a MUST
1079
+ if existing_extensions:
1080
+ assert existing is not None
1081
+ for el in existing["conference"]["extensions"].xml:
1082
+ if el.tag.startswith(f"{{{NOTIFY_NS}}}"):
1083
+ if notify is not None:
1084
+ continue
1085
+ if el.tag.startswith(f"{{{PINNING_NS}}}"):
1086
+ if pin is not None:
1087
+ continue
1088
+ new["conference"]["extensions"].append(el)
1062
1089
 
1063
1090
  if pin is not None:
1064
- item["conference"]["extensions"]["pinned"] = pin
1091
+ if existing_extensions:
1092
+ assert existing is not None
1093
+ existing_pin = (
1094
+ existing["conference"]["extensions"].get_plugin(
1095
+ "pinned", check=True
1096
+ )
1097
+ is not None
1098
+ )
1099
+ if existing_pin != pin:
1100
+ change = True
1101
+ new["conference"]["extensions"]["pinned"] = pin
1065
1102
 
1066
1103
  if notify is not None:
1067
- item["conference"]["extensions"]["notify"].configure(notify)
1068
-
1069
- iq = Iq(stype="set", sfrom=self.user_jid, sto=self.user_jid)
1070
- iq["pubsub"]["publish"]["node"] = self.xmpp["xep_0402"].stanza.NS
1071
- iq["pubsub"]["publish"].append(item)
1072
-
1073
- iq["pubsub"]["publish_options"] = _BOOKMARKS_OPTIONS
1104
+ new["conference"]["extensions"].enable("notify")
1105
+ if existing_extensions:
1106
+ assert existing is not None
1107
+ existing_notify = existing["conference"]["extensions"].get_plugin(
1108
+ "notify", check=True
1109
+ )
1110
+ if existing_notify is None:
1111
+ change = True
1112
+ else:
1113
+ if existing_notify.get_config() != notify:
1114
+ change = True
1115
+ for el in existing_notify:
1116
+ new["conference"]["extensions"]["notify"].append(el)
1117
+ new["conference"]["extensions"]["notify"].configure(notify)
1118
+
1119
+ if change:
1120
+ iq = Iq(stype="set", sfrom=self.user_jid, sto=self.user_jid)
1121
+ iq["pubsub"]["publish"]["node"] = self.xmpp["xep_0402"].stanza.NS
1122
+ iq["pubsub"]["publish"].append(new)
1123
+
1124
+ iq["pubsub"]["publish_options"] = _BOOKMARKS_OPTIONS
1074
1125
 
1075
- try:
1076
- await self.xmpp["xep_0356"].send_privileged_iq(iq)
1077
- except PermissionError:
1078
- warnings.warn(
1079
- "IQ privileges (XEP0356) are not set, we cannot add bookmarks for the user"
1080
- )
1081
- # fallback by forcing invitation
1082
- invite = True
1083
- except IqError as e:
1084
- warnings.warn(
1085
- f"Something went wrong while trying to set the bookmarks: {e}"
1086
- )
1087
- # fallback by forcing invitation
1088
- invite = True
1126
+ try:
1127
+ await self.xmpp["xep_0356"].send_privileged_iq(iq)
1128
+ except PermissionError:
1129
+ warnings.warn(
1130
+ "IQ privileges (XEP0356) are not set, we cannot add bookmarks for the user"
1131
+ )
1132
+ # fallback by forcing invitation
1133
+ invite = True
1134
+ except IqError as e:
1135
+ warnings.warn(
1136
+ f"Something went wrong while trying to set the bookmarks: {e}"
1137
+ )
1138
+ # fallback by forcing invitation
1139
+ invite = True
1140
+ else:
1141
+ self.log.debug("Bookmark does not need updating.")
1142
+ return
1089
1143
 
1090
- if invite or (config.ALWAYS_INVITE_WHEN_ADDING_BOOKMARKS and not is_update):
1144
+ if invite or (config.ALWAYS_INVITE_WHEN_ADDING_BOOKMARKS and existing is None):
1091
1145
  self.session.send_gateway_invite(
1092
1146
  self, reason="This group could not be added automatically for you"
1093
1147
  )
@@ -51,7 +51,7 @@ class Notify(ElementBase):
51
51
  self.append(element)
52
52
 
53
53
  def get_config(
54
- self, client_type: Optional[ClientType] = None
54
+ self, client_type: Optional[ClientType] = None
55
55
  ) -> Optional[WhenLiteral]:
56
56
  """
57
57
  Get the chat notification settings for this bookmark.
@@ -67,7 +67,6 @@ class Notify(ElementBase):
67
67
  return cast(WhenLiteral, child.name)
68
68
  return None
69
69
 
70
-
71
70
  class _Base(ElementBase):
72
71
  namespace = NS
73
72
  interfaces = {"client-type"}
@@ -75,14 +74,17 @@ class _Base(ElementBase):
75
74
 
76
75
  class Never(_Base):
77
76
  name = "never"
77
+ plugin_attrib = name
78
78
 
79
79
 
80
80
  class Always(_Base):
81
81
  name = "always"
82
+ plugin_attrib = name
82
83
 
83
84
 
84
85
  class OnMention(_Base):
85
86
  name = "on-mention"
87
+ plugin_attrib = name
86
88
 
87
89
 
88
90
  class Advanced(ElementBase):
@@ -100,3 +102,6 @@ _CLASS_MAP = {
100
102
  def register_plugin():
101
103
  register_stanza_plugin(Extensions, Notify)
102
104
  register_stanza_plugin(Notify, Advanced)
105
+ register_stanza_plugin(Notify, Never, iterable=True)
106
+ register_stanza_plugin(Notify, Always, iterable=True)
107
+ register_stanza_plugin(Notify, OnMention, iterable=True)
slidge/util/util.py CHANGED
@@ -218,18 +218,18 @@ class SlidgeLogger(logging.Logger):
218
218
  log = logging.getLogger(__name__)
219
219
 
220
220
 
221
- def get_version():
221
+ def get_version() -> str:
222
222
  try:
223
223
  git = subprocess.check_output(
224
- ["git", "rev-parse", "HEAD"], stderr=subprocess.DEVNULL
224
+ ["git", "rev-parse", "HEAD"],
225
+ stderr=subprocess.DEVNULL,
226
+ cwd=Path(__file__).parent,
225
227
  ).decode()
226
228
  except (FileNotFoundError, subprocess.CalledProcessError):
227
- pass
229
+ return "NO_VERSION"
228
230
  else:
229
231
  return "git-" + git[:10]
230
232
 
231
- return "NO_VERSION"
232
-
233
233
 
234
234
  def merge_resources(resources: dict[str, ResourceDict]) -> Optional[ResourceDict]:
235
235
  if len(resources) == 0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: slidge
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: XMPP bridging framework
5
5
  Author-email: Nicolas Cedilnik <nicoco@nicoco.fr>
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -1,11 +1,11 @@
1
1
  slidge/__init__.py,sha256=S0tUjqpZlzsr8G4Y_1Xt-KCYB07qaknTB0OwHU8k29U,1587
2
2
  slidge/__main__.py,sha256=ydjUklOoavS4YlGfjRX_8BQN2DaSbaXPMi47RkOgcFI,37
3
- slidge/__version__.py,sha256=LukT7r82VsYYhRUhnpDW_6t1xNzuYY3v380h-wU8KCg,165
3
+ slidge/__version__.py,sha256=4G6eK4xrrezi8g1TxDqa6IID1uzOe-SonV8sT5-MrUs,165
4
4
  slidge/main.py,sha256=vMJzhvUxbeuIXuHxXXs6lm_ShBjXiS9B5Li5Ge4vWPo,6238
5
5
  slidge/migration.py,sha256=4BJmPIRB56_WIhRTqBFIIBXuvnhhBjjOMl4CE7jY6oc,1541
6
6
  slidge/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  slidge/command/__init__.py,sha256=UYf1mjCYbZ5G7PIgaFTWSQRAzEJkQ6dTH8Fu_e_XnO0,613
8
- slidge/command/adhoc.py,sha256=FEkE5UapIP_yrmrzGn5yIHCubOZijoI_muu1AtCqGOM,10472
8
+ slidge/command/adhoc.py,sha256=bYLXcYJjbqPE9nBhrEQevqYFh9AS7Ei3m1vTZBIggrc,10557
9
9
  slidge/command/admin.py,sha256=TYrzgCIhjcTIwl1IUaFlUd3D98SPyao10gB20zo8b3Q,6187
10
10
  slidge/command/base.py,sha256=EDcEl5dJcooSmLarXI2fmBq6QtU7h-7MOM3DDsxXmTU,13447
11
11
  slidge/command/categories.py,sha256=vF0KGDV9sEn8TNkcMoDRw-u3gEyNHSXghOU2JRHQtKs,351
@@ -81,7 +81,7 @@ slidge/group/__init__.py,sha256=yFt7cHqeaKIMN6f9ZyhhspOcJJvBtLedGv-iICG7lto,258
81
81
  slidge/group/archive.py,sha256=IPqklzo0UN3lPHckfsKW9c4nl3m_9XGY4u0eehrhe8k,5281
82
82
  slidge/group/bookmarks.py,sha256=AvFL34bEX6n3OP1Np309T5hrLK9GnjkjdyLJ3uiLZyc,6616
83
83
  slidge/group/participant.py,sha256=cUuyJRGq8AIHrwtubje5cyb5hHY2hGLtGboBju4SI0c,17781
84
- slidge/group/room.py,sha256=Ar7mSSZRqjDPaXtRuq1da-ZqdJ-fibVtEZDcfpZtpXY,46856
84
+ slidge/group/room.py,sha256=IilOT_Z5P-gh0lo5KLFc054z6sOrxJQ6MvjPmLKXiRs,49011
85
85
  slidge/slixfix/__init__.py,sha256=Og6_EAuWst6paWmDiGqeqQH6Iof6V8Vkr5pyYisgjsw,4282
86
86
  slidge/slixfix/delivery_receipt.py,sha256=3bWdZH3-X3CZJXmnI_TpjkTUUK-EY4Ktm78lW0-40fc,1366
87
87
  slidge/slixfix/roster.py,sha256=KvDjh9q7pqaZf69H93okfib13cc95uVZUJ6rzpqmDaU,1704
@@ -100,15 +100,15 @@ slidge/slixfix/xep_0292/__init__.py,sha256=_MvS9wGra6ig3P_dPAVlCPDJkiOFvUWGjaRsH
100
100
  slidge/slixfix/xep_0292/vcard4.py,sha256=jL-TOW3eG2QXLduSLNq03L8HoUNmvy8kTZI5ojvo6GE,358
101
101
  slidge/slixfix/xep_0492/__init__.py,sha256=kjWVeX3SG_2ohHx0fuMh1gmM2G57Bl6SRo7Mfv6sglA,161
102
102
  slidge/slixfix/xep_0492/notify.py,sha256=8EPSdU3rTzWkHNm8oFr0tK2PmMJ6hBAIr88GoOmHTuQ,340
103
- slidge/slixfix/xep_0492/stanza.py,sha256=gL0ixpV07Q9eqTXIOjdLVPtim45izuwaLk0iCoZ8e7c,2649
103
+ slidge/slixfix/xep_0492/stanza.py,sha256=TlwyAHozA6zu32QoBb6M12xqWR-ytT0F9XVFqZkd4d4,2895
104
104
  slidge/util/__init__.py,sha256=BELovoTMPcPPGz3D48esBr8A4BRRHXTvavfgnArBgEc,301
105
105
  slidge/util/archive_msg.py,sha256=xXAR0BI5r3d6KKWjae9594izCOv6iI03z2WLuTecNw8,1724
106
106
  slidge/util/conf.py,sha256=1j2OnOsCBar1tOObErhXR5RC3Vl3faliOZ1U8J3My58,6613
107
107
  slidge/util/test.py,sha256=l1VHBsw5Uzk2t7wtkfb9kWvtehcYhw1t_d567JAJFKA,14135
108
108
  slidge/util/types.py,sha256=R_xfS5mRL0XUJIoDpnaAkZlTOoLPerduXBFftaVwIAI,5489
109
- slidge/util/util.py,sha256=4GdRZwHYUPkteEi8oux--qLwMiXnVLl_ojMDaKbEQCE,9629
110
- slidge-0.2.6.dist-info/METADATA,sha256=ShWfovgJtP9yPJYaEZqHg0Rd62blhfP78go2AsRfeoM,44841
111
- slidge-0.2.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
112
- slidge-0.2.6.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
113
- slidge-0.2.6.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
114
- slidge-0.2.6.dist-info/RECORD,,
109
+ slidge/util/util.py,sha256=IfyYLkujW6Pk0kvHpfkpQwejFDHSe5oR4_bczEUnhjs,9678
110
+ slidge-0.2.7.dist-info/METADATA,sha256=u5B3zAw9h1inyIcHrGvr23-GNtI7Ba4gHNXLRmTtktc,44841
111
+ slidge-0.2.7.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
112
+ slidge-0.2.7.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
113
+ slidge-0.2.7.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
114
+ slidge-0.2.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5