Mercurial > libervia-backend
comparison sat/memory/memory.py @ 4037:524856bd7b19
massive refactoring to switch from camelCase to snake_case:
historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a
pre-PEP8 code, to use the same coding style as in Twisted.
However, snake_case is more readable and it's better to follow PEP8 best practices, so it
has been decided to move on full snake_case. Because Libervia has a huge codebase, this
ended with a ugly mix of camelCase and snake_case.
To fix that, this patch does a big refactoring by renaming every function and method
(including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case.
This is a massive change, and may result in some bugs.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 08 Apr 2023 13:54:42 +0200 |
parents | 7af29260ecb8 |
children |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
63 """ | 63 """ |
64 self._sessions = dict() | 64 self._sessions = dict() |
65 self.timeout = timeout or Sessions.DEFAULT_TIMEOUT | 65 self.timeout = timeout or Sessions.DEFAULT_TIMEOUT |
66 self.resettable_timeout = resettable_timeout | 66 self.resettable_timeout = resettable_timeout |
67 | 67 |
68 def newSession(self, session_data=None, session_id=None, profile=None): | 68 def new_session(self, session_data=None, session_id=None, profile=None): |
69 """Create a new session | 69 """Create a new session |
70 | 70 |
71 @param session_data: mutable data to use, default to a dict | 71 @param session_data: mutable data to use, default to a dict |
72 @param session_id (str): force the session_id to the given string | 72 @param session_id (str): force the session_id to the given string |
73 @param profile: if set, the session is owned by the profile, | 73 @param profile: if set, the session is owned by the profile, |
74 and profileGet must be used instead of __getitem__ | 74 and profile_get must be used instead of __getitem__ |
75 @return: session_id, session_data | 75 @return: session_id, session_data |
76 """ | 76 """ |
77 if session_id is None: | 77 if session_id is None: |
78 session_id = str(uuid4()) | 78 session_id = str(uuid4()) |
79 elif session_id in self._sessions: | 79 elif session_id in self._sessions: |
80 raise exceptions.ConflictError( | 80 raise exceptions.ConflictError( |
81 "Session id {} is already used".format(session_id) | 81 "Session id {} is already used".format(session_id) |
82 ) | 82 ) |
83 timer = reactor.callLater(self.timeout, self._purgeSession, session_id) | 83 timer = reactor.callLater(self.timeout, self._purge_session, session_id) |
84 if session_data is None: | 84 if session_data is None: |
85 session_data = {} | 85 session_data = {} |
86 self._sessions[session_id] = ( | 86 self._sessions[session_id] = ( |
87 (timer, session_data) if profile is None else (timer, session_data, profile) | 87 (timer, session_data) if profile is None else (timer, session_data, profile) |
88 ) | 88 ) |
89 return session_id, session_data | 89 return session_id, session_data |
90 | 90 |
91 def _purgeSession(self, session_id): | 91 def _purge_session(self, session_id): |
92 try: | 92 try: |
93 timer, session_data, profile = self._sessions[session_id] | 93 timer, session_data, profile = self._sessions[session_id] |
94 except ValueError: | 94 except ValueError: |
95 timer, session_data = self._sessions[session_id] | 95 timer, session_data = self._sessions[session_id] |
96 profile = None | 96 profile = None |
111 return len(self._sessions) | 111 return len(self._sessions) |
112 | 112 |
113 def __contains__(self, session_id): | 113 def __contains__(self, session_id): |
114 return session_id in self._sessions | 114 return session_id in self._sessions |
115 | 115 |
116 def profileGet(self, session_id, profile): | 116 def profile_get(self, session_id, profile): |
117 try: | 117 try: |
118 timer, session_data, profile_set = self._sessions[session_id] | 118 timer, session_data, profile_set = self._sessions[session_id] |
119 except ValueError: | 119 except ValueError: |
120 raise exceptions.InternalError( | 120 raise exceptions.InternalError( |
121 "You need to use __getitem__ when profile is not set" | 121 "You need to use __getitem__ when profile is not set" |
131 def __getitem__(self, session_id): | 131 def __getitem__(self, session_id): |
132 try: | 132 try: |
133 timer, session_data = self._sessions[session_id] | 133 timer, session_data = self._sessions[session_id] |
134 except ValueError: | 134 except ValueError: |
135 raise exceptions.InternalError( | 135 raise exceptions.InternalError( |
136 "You need to use profileGet instead of __getitem__ when profile is set" | 136 "You need to use profile_get instead of __getitem__ when profile is set" |
137 ) | 137 ) |
138 except KeyError: | 138 except KeyError: |
139 raise failure.Failure(KeyError(MSG_NO_SESSION)) | 139 raise failure.Failure(KeyError(MSG_NO_SESSION)) |
140 if self.resettable_timeout: | 140 if self.resettable_timeout: |
141 timer.reset(self.timeout) | 141 timer.reset(self.timeout) |
142 return session_data | 142 return session_data |
143 | 143 |
144 def __setitem__(self, key, value): | 144 def __setitem__(self, key, value): |
145 raise NotImplementedError("You need do use newSession to create a session") | 145 raise NotImplementedError("You need do use new_session to create a session") |
146 | 146 |
147 def __delitem__(self, session_id): | 147 def __delitem__(self, session_id): |
148 """ delete the session data """ | 148 """ delete the session data """ |
149 self._purgeSession(session_id) | 149 self._purge_session(session_id) |
150 | 150 |
151 def keys(self): | 151 def keys(self): |
152 return list(self._sessions.keys()) | 152 return list(self._sessions.keys()) |
153 | 153 |
154 def iterkeys(self): | 154 def iterkeys(self): |
158 class ProfileSessions(Sessions): | 158 class ProfileSessions(Sessions): |
159 """ProfileSessions extends the Sessions class, but here the profile can be | 159 """ProfileSessions extends the Sessions class, but here the profile can be |
160 used as the key to retrieve data or delete a session (instead of session id). | 160 used as the key to retrieve data or delete a session (instead of session id). |
161 """ | 161 """ |
162 | 162 |
163 def _profileGetAllIds(self, profile): | 163 def _profile_get_all_ids(self, profile): |
164 """Return a list of the sessions ids that are associated to the given profile. | 164 """Return a list of the sessions ids that are associated to the given profile. |
165 | 165 |
166 @param profile: %(doc_profile)s | 166 @param profile: %(doc_profile)s |
167 @return: a list containing the sessions ids | 167 @return: a list containing the sessions ids |
168 """ | 168 """ |
174 continue | 174 continue |
175 if profile == profile_set: | 175 if profile == profile_set: |
176 ret.append(session_id) | 176 ret.append(session_id) |
177 return ret | 177 return ret |
178 | 178 |
179 def profileGetUnique(self, profile): | 179 def profile_get_unique(self, profile): |
180 """Return the data of the unique session that is associated to the given profile. | 180 """Return the data of the unique session that is associated to the given profile. |
181 | 181 |
182 @param profile: %(doc_profile)s | 182 @param profile: %(doc_profile)s |
183 @return: | 183 @return: |
184 - mutable data (default: dict) of the unique session | 184 - mutable data (default: dict) of the unique session |
185 - None if no session is associated to the profile | 185 - None if no session is associated to the profile |
186 - raise an error if more than one session are found | 186 - raise an error if more than one session are found |
187 """ | 187 """ |
188 ids = self._profileGetAllIds(profile) | 188 ids = self._profile_get_all_ids(profile) |
189 if len(ids) > 1: | 189 if len(ids) > 1: |
190 raise exceptions.InternalError( | 190 raise exceptions.InternalError( |
191 "profileGetUnique has been used but more than one session has been found!" | 191 "profile_get_unique has been used but more than one session has been found!" |
192 ) | 192 ) |
193 return ( | 193 return ( |
194 self.profileGet(ids[0], profile) if len(ids) == 1 else None | 194 self.profile_get(ids[0], profile) if len(ids) == 1 else None |
195 ) # XXX: timeout might be reset | 195 ) # XXX: timeout might be reset |
196 | 196 |
197 def profileDelUnique(self, profile): | 197 def profile_del_unique(self, profile): |
198 """Delete the unique session that is associated to the given profile. | 198 """Delete the unique session that is associated to the given profile. |
199 | 199 |
200 @param profile: %(doc_profile)s | 200 @param profile: %(doc_profile)s |
201 @return: None, but raise an error if more than one session are found | 201 @return: None, but raise an error if more than one session are found |
202 """ | 202 """ |
203 ids = self._profileGetAllIds(profile) | 203 ids = self._profile_get_all_ids(profile) |
204 if len(ids) > 1: | 204 if len(ids) > 1: |
205 raise exceptions.InternalError( | 205 raise exceptions.InternalError( |
206 "profileDelUnique has been used but more than one session has been found!" | 206 "profile_del_unique has been used but more than one session has been found!" |
207 ) | 207 ) |
208 if len(ids) == 1: | 208 if len(ids) == 1: |
209 del self._sessions[ids[0]] | 209 del self._sessions[ids[0]] |
210 | 210 |
211 | 211 |
215 # must actually be purged and later, when the personal key is needed, the | 215 # must actually be purged and later, when the personal key is needed, the |
216 # profile password should be asked again in order to decrypt it. | 216 # profile password should be asked again in order to decrypt it. |
217 def __init__(self, timeout=None): | 217 def __init__(self, timeout=None): |
218 ProfileSessions.__init__(self, timeout, resettable_timeout=False) | 218 ProfileSessions.__init__(self, timeout, resettable_timeout=False) |
219 | 219 |
220 def _purgeSession(self, session_id): | 220 def _purge_session(self, session_id): |
221 log.debug( | 221 log.debug( |
222 "FIXME: PasswordSessions should ask for the profile password after the session expired" | 222 "FIXME: PasswordSessions should ask for the profile password after the session expired" |
223 ) | 223 ) |
224 | 224 |
225 | 225 |
235 # where main key is resource, or None for bare jid | 235 # where main key is resource, or None for bare jid |
236 self._key_signals = set() # key which need a signal to frontends when updated | 236 self._key_signals = set() # key which need a signal to frontends when updated |
237 self.subscriptions = {} | 237 self.subscriptions = {} |
238 self.auth_sessions = PasswordSessions() # remember the authenticated profiles | 238 self.auth_sessions = PasswordSessions() # remember the authenticated profiles |
239 self.disco = Discovery(host) | 239 self.disco = Discovery(host) |
240 self.config = tools_config.parseMainConf(log_filenames=True) | 240 self.config = tools_config.parse_main_conf(log_filenames=True) |
241 self._cache_path = Path(self.getConfig("", "local_dir"), C.CACHE_DIR) | 241 self._cache_path = Path(self.config_get("", "local_dir"), C.CACHE_DIR) |
242 self.admins = self.getConfig("", "admins_list", []) | 242 self.admins = self.config_get("", "admins_list", []) |
243 self.admin_jids = set() | 243 self.admin_jids = set() |
244 | 244 |
245 | 245 |
246 async def initialise(self): | 246 async def initialise(self): |
247 self.storage = Storage() | 247 self.storage = Storage() |
254 self.memory_data = PersistentDict("memory") | 254 self.memory_data = PersistentDict("memory") |
255 await self.memory_data.load() | 255 await self.memory_data.load() |
256 await self.disco.load() | 256 await self.disco.load() |
257 for admin in self.admins: | 257 for admin in self.admins: |
258 try: | 258 try: |
259 admin_jid_s = await self.asyncGetParamA( | 259 admin_jid_s = await self.param_get_a_async( |
260 "JabberID", "Connection", profile_key=admin | 260 "JabberID", "Connection", profile_key=admin |
261 ) | 261 ) |
262 except Exception as e: | 262 except Exception as e: |
263 log.warning(f"Can't retrieve jid of admin {admin!r}: {e}") | 263 log.warning(f"Can't retrieve jid of admin {admin!r}: {e}") |
264 else: | 264 else: |
271 self.admin_jids.add(admin_jid) | 271 self.admin_jids.add(admin_jid) |
272 | 272 |
273 | 273 |
274 ## Configuration ## | 274 ## Configuration ## |
275 | 275 |
276 def getConfig(self, section, name, default=None): | 276 def config_get(self, section, name, default=None): |
277 """Get the main configuration option | 277 """Get the main configuration option |
278 | 278 |
279 @param section: section of the config file (None or '' for DEFAULT) | 279 @param section: section of the config file (None or '' for DEFAULT) |
280 @param name: name of the option | 280 @param name: name of the option |
281 @param default: value to use if not found | 281 @param default: value to use if not found |
282 @return: str, list or dict | 282 @return: str, list or dict |
283 """ | 283 """ |
284 return tools_config.getConfig(self.config, section, name, default) | 284 return tools_config.config_get(self.config, section, name, default) |
285 | 285 |
286 def load_xml(self, filename): | 286 def load_xml(self, filename): |
287 """Load parameters template from xml file | 287 """Load parameters template from xml file |
288 | 288 |
289 @param filename (str): input file | 289 @param filename (str): input file |
320 return False | 320 return False |
321 | 321 |
322 def load(self): | 322 def load(self): |
323 """Load parameters and all memory things from db""" | 323 """Load parameters and all memory things from db""" |
324 # parameters data | 324 # parameters data |
325 return self.params.loadGenParams() | 325 return self.params.load_gen_params() |
326 | 326 |
327 def loadIndividualParams(self, profile): | 327 def load_individual_params(self, profile): |
328 """Load individual parameters for a profile | 328 """Load individual parameters for a profile |
329 @param profile: %(doc_profile)s""" | 329 @param profile: %(doc_profile)s""" |
330 return self.params.loadIndParams(profile) | 330 return self.params.load_ind_params(profile) |
331 | 331 |
332 ## Profiles/Sessions management ## | 332 ## Profiles/Sessions management ## |
333 | 333 |
334 def startSession(self, password, profile): | 334 def start_session(self, password, profile): |
335 """"Iniatialise session for a profile | 335 """"Iniatialise session for a profile |
336 | 336 |
337 @param password(unicode): profile session password | 337 @param password(unicode): profile session password |
338 or empty string is no password is set | 338 or empty string is no password is set |
339 @param profile: %(doc_profile)s | 339 @param profile: %(doc_profile)s |
340 @raise exceptions.ProfileUnknownError if profile doesn't exists | 340 @raise exceptions.ProfileUnknownError if profile doesn't exists |
341 @raise exceptions.PasswordError: the password does not match | 341 @raise exceptions.PasswordError: the password does not match |
342 """ | 342 """ |
343 profile = self.getProfileName(profile) | 343 profile = self.get_profile_name(profile) |
344 | 344 |
345 def createSession(__): | 345 def create_session(__): |
346 """Called once params are loaded.""" | 346 """Called once params are loaded.""" |
347 self._entities_cache[profile] = {} | 347 self._entities_cache[profile] = {} |
348 log.info("[{}] Profile session started".format(profile)) | 348 log.info("[{}] Profile session started".format(profile)) |
349 return False | 349 return False |
350 | 350 |
351 def backendInitialised(__): | 351 def backend_initialised(__): |
352 def doStartSession(__=None): | 352 def do_start_session(__=None): |
353 if self.isSessionStarted(profile): | 353 if self.is_session_started(profile): |
354 log.info("Session already started!") | 354 log.info("Session already started!") |
355 return True | 355 return True |
356 try: | 356 try: |
357 # if there is a value at this point in self._entities_cache, | 357 # if there is a value at this point in self._entities_cache, |
358 # it is the loadIndividualParams Deferred, the session is starting | 358 # it is the load_individual_params Deferred, the session is starting |
359 session_d = self._entities_cache[profile] | 359 session_d = self._entities_cache[profile] |
360 except KeyError: | 360 except KeyError: |
361 # else we do request the params | 361 # else we do request the params |
362 session_d = self._entities_cache[profile] = self.loadIndividualParams( | 362 session_d = self._entities_cache[profile] = self.load_individual_params( |
363 profile | 363 profile |
364 ) | 364 ) |
365 session_d.addCallback(createSession) | 365 session_d.addCallback(create_session) |
366 finally: | 366 finally: |
367 return session_d | 367 return session_d |
368 | 368 |
369 auth_d = defer.ensureDeferred(self.profileAuthenticate(password, profile)) | 369 auth_d = defer.ensureDeferred(self.profile_authenticate(password, profile)) |
370 auth_d.addCallback(doStartSession) | 370 auth_d.addCallback(do_start_session) |
371 return auth_d | 371 return auth_d |
372 | 372 |
373 if self.host.initialised.called: | 373 if self.host.initialised.called: |
374 return defer.succeed(None).addCallback(backendInitialised) | 374 return defer.succeed(None).addCallback(backend_initialised) |
375 else: | 375 else: |
376 return self.host.initialised.addCallback(backendInitialised) | 376 return self.host.initialised.addCallback(backend_initialised) |
377 | 377 |
378 def stopSession(self, profile): | 378 def stop_session(self, profile): |
379 """Delete a profile session | 379 """Delete a profile session |
380 | 380 |
381 @param profile: %(doc_profile)s | 381 @param profile: %(doc_profile)s |
382 """ | 382 """ |
383 if self.host.isConnected(profile): | 383 if self.host.is_connected(profile): |
384 log.debug("Disconnecting profile because of session stop") | 384 log.debug("Disconnecting profile because of session stop") |
385 self.host.disconnect(profile) | 385 self.host.disconnect(profile) |
386 self.auth_sessions.profileDelUnique(profile) | 386 self.auth_sessions.profile_del_unique(profile) |
387 try: | 387 try: |
388 self._entities_cache[profile] | 388 self._entities_cache[profile] |
389 except KeyError: | 389 except KeyError: |
390 log.warning("Profile was not in cache") | 390 log.warning("Profile was not in cache") |
391 | 391 |
392 def _isSessionStarted(self, profile_key): | 392 def _is_session_started(self, profile_key): |
393 return self.isSessionStarted(self.getProfileName(profile_key)) | 393 return self.is_session_started(self.get_profile_name(profile_key)) |
394 | 394 |
395 def isSessionStarted(self, profile): | 395 def is_session_started(self, profile): |
396 try: | 396 try: |
397 # XXX: if the value in self._entities_cache is a Deferred, | 397 # XXX: if the value in self._entities_cache is a Deferred, |
398 # the session is starting but not started yet | 398 # the session is starting but not started yet |
399 return not isinstance(self._entities_cache[profile], defer.Deferred) | 399 return not isinstance(self._entities_cache[profile], defer.Deferred) |
400 except KeyError: | 400 except KeyError: |
401 return False | 401 return False |
402 | 402 |
403 async def profileAuthenticate(self, password, profile): | 403 async def profile_authenticate(self, password, profile): |
404 """Authenticate the profile. | 404 """Authenticate the profile. |
405 | 405 |
406 @param password (unicode): the SàT profile password | 406 @param password (unicode): the SàT profile password |
407 @return: None in case of success (an exception is raised otherwise) | 407 @return: None in case of success (an exception is raised otherwise) |
408 @raise exceptions.PasswordError: the password does not match | 408 @raise exceptions.PasswordError: the password does not match |
409 """ | 409 """ |
410 if not password and self.auth_sessions.profileGetUnique(profile): | 410 if not password and self.auth_sessions.profile_get_unique(profile): |
411 # XXX: this allows any frontend to connect with the empty password as soon as | 411 # XXX: this allows any frontend to connect with the empty password as soon as |
412 # the profile has been authenticated at least once before. It is OK as long as | 412 # the profile has been authenticated at least once before. It is OK as long as |
413 # submitting a form with empty passwords is restricted to local frontends. | 413 # submitting a form with empty passwords is restricted to local frontends. |
414 return | 414 return |
415 | 415 |
416 sat_cipher = await self.asyncGetParamA( | 416 sat_cipher = await self.param_get_a_async( |
417 C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile | 417 C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile |
418 ) | 418 ) |
419 valid = PasswordHasher.verify(password, sat_cipher) | 419 valid = PasswordHasher.verify(password, sat_cipher) |
420 if not valid: | 420 if not valid: |
421 log.warning(_("Authentication failure of profile {profile}").format( | 421 log.warning(_("Authentication failure of profile {profile}").format( |
422 profile=profile)) | 422 profile=profile)) |
423 raise exceptions.PasswordError("The provided profile password doesn't match.") | 423 raise exceptions.PasswordError("The provided profile password doesn't match.") |
424 return await self.newAuthSession(password, profile) | 424 return await self.new_auth_session(password, profile) |
425 | 425 |
426 async def newAuthSession(self, key, profile): | 426 async def new_auth_session(self, key, profile): |
427 """Start a new session for the authenticated profile. | 427 """Start a new session for the authenticated profile. |
428 | 428 |
429 If there is already an existing session, no new one is created | 429 If there is already an existing session, no new one is created |
430 The personal key is loaded encrypted from a PersistentDict before being decrypted. | 430 The personal key is loaded encrypted from a PersistentDict before being decrypted. |
431 | 431 |
433 @param profile: %(doc_profile)s | 433 @param profile: %(doc_profile)s |
434 """ | 434 """ |
435 data = await PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() | 435 data = await PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() |
436 personal_key = BlockCipher.decrypt(key, data[C.MEMORY_CRYPTO_KEY]) | 436 personal_key = BlockCipher.decrypt(key, data[C.MEMORY_CRYPTO_KEY]) |
437 # Create the session for this profile and store the personal key | 437 # Create the session for this profile and store the personal key |
438 session_data = self.auth_sessions.profileGetUnique(profile) | 438 session_data = self.auth_sessions.profile_get_unique(profile) |
439 if not session_data: | 439 if not session_data: |
440 self.auth_sessions.newSession( | 440 self.auth_sessions.new_session( |
441 {C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile | 441 {C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile |
442 ) | 442 ) |
443 log.debug("auth session created for profile %s" % profile) | 443 log.debug("auth session created for profile %s" % profile) |
444 | 444 |
445 def purgeProfileSession(self, profile): | 445 def purge_profile_session(self, profile): |
446 """Delete cache of data of profile | 446 """Delete cache of data of profile |
447 @param profile: %(doc_profile)s""" | 447 @param profile: %(doc_profile)s""" |
448 log.info(_("[%s] Profile session purge" % profile)) | 448 log.info(_("[%s] Profile session purge" % profile)) |
449 self.params.purgeProfile(profile) | 449 self.params.purge_profile(profile) |
450 try: | 450 try: |
451 del self._entities_cache[profile] | 451 del self._entities_cache[profile] |
452 except KeyError: | 452 except KeyError: |
453 log.error( | 453 log.error( |
454 _( | 454 _( |
455 "Trying to purge roster status cache for a profile not in memory: [%s]" | 455 "Trying to purge roster status cache for a profile not in memory: [%s]" |
456 ) | 456 ) |
457 % profile | 457 % profile |
458 ) | 458 ) |
459 | 459 |
460 def getProfilesList(self, clients=True, components=False): | 460 def get_profiles_list(self, clients=True, components=False): |
461 """retrieve profiles list | 461 """retrieve profiles list |
462 | 462 |
463 @param clients(bool): if True return clients profiles | 463 @param clients(bool): if True return clients profiles |
464 @param components(bool): if True return components profiles | 464 @param components(bool): if True return components profiles |
465 @return (list[unicode]): selected profiles | 465 @return (list[unicode]): selected profiles |
466 """ | 466 """ |
467 if not clients and not components: | 467 if not clients and not components: |
468 log.warning(_("requesting no profiles at all")) | 468 log.warning(_("requesting no profiles at all")) |
469 return [] | 469 return [] |
470 profiles = self.storage.getProfilesList() | 470 profiles = self.storage.get_profiles_list() |
471 if clients and components: | 471 if clients and components: |
472 return sorted(profiles) | 472 return sorted(profiles) |
473 isComponent = self.storage.profileIsComponent | 473 is_component = self.storage.profile_is_component |
474 if clients: | 474 if clients: |
475 p_filter = lambda p: not isComponent(p) | 475 p_filter = lambda p: not is_component(p) |
476 else: | 476 else: |
477 p_filter = lambda p: isComponent(p) | 477 p_filter = lambda p: is_component(p) |
478 | 478 |
479 return sorted(p for p in profiles if p_filter(p)) | 479 return sorted(p for p in profiles if p_filter(p)) |
480 | 480 |
481 def getProfileName(self, profile_key, return_profile_keys=False): | 481 def get_profile_name(self, profile_key, return_profile_keys=False): |
482 """Return name of profile from keyword | 482 """Return name of profile from keyword |
483 | 483 |
484 @param profile_key: can be the profile name or a keyword (like @DEFAULT@) | 484 @param profile_key: can be the profile name or a keyword (like @DEFAULT@) |
485 @param return_profile_keys: if True, return unmanaged profile keys (like "@ALL@"). This keys must be managed by the caller | 485 @param return_profile_keys: if True, return unmanaged profile keys (like "@ALL@"). This keys must be managed by the caller |
486 @return: requested profile name | 486 @return: requested profile name |
487 @raise exceptions.ProfileUnknownError if profile doesn't exists | 487 @raise exceptions.ProfileUnknownError if profile doesn't exists |
488 """ | 488 """ |
489 return self.params.getProfileName(profile_key, return_profile_keys) | 489 return self.params.get_profile_name(profile_key, return_profile_keys) |
490 | 490 |
491 def profileSetDefault(self, profile): | 491 def profile_set_default(self, profile): |
492 """Set default profile | 492 """Set default profile |
493 | 493 |
494 @param profile: %(doc_profile)s | 494 @param profile: %(doc_profile)s |
495 """ | 495 """ |
496 # we want to be sure that the profile exists | 496 # we want to be sure that the profile exists |
497 profile = self.getProfileName(profile) | 497 profile = self.get_profile_name(profile) |
498 | 498 |
499 self.memory_data["Profile_default"] = profile | 499 self.memory_data["Profile_default"] = profile |
500 | 500 |
501 def createProfile(self, name, password, component=None): | 501 def create_profile(self, name, password, component=None): |
502 """Create a new profile | 502 """Create a new profile |
503 | 503 |
504 @param name(unicode): profile name | 504 @param name(unicode): profile name |
505 @param password(unicode): profile password | 505 @param password(unicode): profile password |
506 Can be empty to disable password | 506 Can be empty to disable password |
530 # FIXME: PLUGIN_INFO is not currently accessible after import, but type shoul be tested here | 530 # FIXME: PLUGIN_INFO is not currently accessible after import, but type shoul be tested here |
531 # if self.host.plugins[component].PLUGIN_INFO[u"type"] != C.PLUG_TYPE_ENTRY_POINT: | 531 # if self.host.plugins[component].PLUGIN_INFO[u"type"] != C.PLUG_TYPE_ENTRY_POINT: |
532 # raise ValueError(_(u"Plugin {component} is not an entry point !".format( | 532 # raise ValueError(_(u"Plugin {component} is not an entry point !".format( |
533 # component = component))) | 533 # component = component))) |
534 | 534 |
535 d = self.params.createProfile(name, component) | 535 d = self.params.create_profile(name, component) |
536 | 536 |
537 def initPersonalKey(__): | 537 def init_personal_key(__): |
538 # be sure to call this after checking that the profile doesn't exist yet | 538 # be sure to call this after checking that the profile doesn't exist yet |
539 | 539 |
540 # generated once for all and saved in a PersistentDict | 540 # generated once for all and saved in a PersistentDict |
541 personal_key = BlockCipher.getRandomKey( | 541 personal_key = BlockCipher.get_random_key( |
542 base64=True | 542 base64=True |
543 ).decode('utf-8') | 543 ).decode('utf-8') |
544 self.auth_sessions.newSession( | 544 self.auth_sessions.new_session( |
545 {C.MEMORY_CRYPTO_KEY: personal_key}, profile=name | 545 {C.MEMORY_CRYPTO_KEY: personal_key}, profile=name |
546 ) # will be encrypted by setParam | 546 ) # will be encrypted by param_set |
547 | 547 |
548 def startFakeSession(__): | 548 def start_fake_session(__): |
549 # avoid ProfileNotConnected exception in setParam | 549 # avoid ProfileNotConnected exception in param_set |
550 self._entities_cache[name] = None | 550 self._entities_cache[name] = None |
551 self.params.loadIndParams(name) | 551 self.params.load_ind_params(name) |
552 | 552 |
553 def stopFakeSession(__): | 553 def stop_fake_session(__): |
554 del self._entities_cache[name] | 554 del self._entities_cache[name] |
555 self.params.purgeProfile(name) | 555 self.params.purge_profile(name) |
556 | 556 |
557 d.addCallback(initPersonalKey) | 557 d.addCallback(init_personal_key) |
558 d.addCallback(startFakeSession) | 558 d.addCallback(start_fake_session) |
559 d.addCallback( | 559 d.addCallback( |
560 lambda __: self.setParam( | 560 lambda __: self.param_set( |
561 C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=name | 561 C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=name |
562 ) | 562 ) |
563 ) | 563 ) |
564 d.addCallback(stopFakeSession) | 564 d.addCallback(stop_fake_session) |
565 d.addCallback(lambda __: self.auth_sessions.profileDelUnique(name)) | 565 d.addCallback(lambda __: self.auth_sessions.profile_del_unique(name)) |
566 return d | 566 return d |
567 | 567 |
568 def asyncDeleteProfile(self, name, force=False): | 568 def profile_delete_async(self, name, force=False): |
569 """Delete an existing profile | 569 """Delete an existing profile |
570 | 570 |
571 @param name: Name of the profile | 571 @param name: Name of the profile |
572 @param force: force the deletion even if the profile is connected. | 572 @param force: force the deletion even if the profile is connected. |
573 To be used for direct calls only (not through the bridge). | 573 To be used for direct calls only (not through the bridge). |
574 @return: a Deferred instance | 574 @return: a Deferred instance |
575 """ | 575 """ |
576 | 576 |
577 def cleanMemory(__): | 577 def clean_memory(__): |
578 self.auth_sessions.profileDelUnique(name) | 578 self.auth_sessions.profile_del_unique(name) |
579 try: | 579 try: |
580 del self._entities_cache[name] | 580 del self._entities_cache[name] |
581 except KeyError: | 581 except KeyError: |
582 pass | 582 pass |
583 | 583 |
584 d = self.params.asyncDeleteProfile(name, force) | 584 d = self.params.profile_delete_async(name, force) |
585 d.addCallback(cleanMemory) | 585 d.addCallback(clean_memory) |
586 return d | 586 return d |
587 | 587 |
588 def isComponent(self, profile_name): | 588 def is_component(self, profile_name): |
589 """Tell if a profile is a component | 589 """Tell if a profile is a component |
590 | 590 |
591 @param profile_name(unicode): name of the profile | 591 @param profile_name(unicode): name of the profile |
592 @return (bool): True if profile is a component | 592 @return (bool): True if profile is a component |
593 @raise exceptions.NotFound: profile doesn't exist | 593 @raise exceptions.NotFound: profile doesn't exist |
594 """ | 594 """ |
595 return self.storage.profileIsComponent(profile_name) | 595 return self.storage.profile_is_component(profile_name) |
596 | 596 |
597 def getEntryPoint(self, profile_name): | 597 def get_entry_point(self, profile_name): |
598 """Get a component entry point | 598 """Get a component entry point |
599 | 599 |
600 @param profile_name(unicode): name of the profile | 600 @param profile_name(unicode): name of the profile |
601 @return (bool): True if profile is a component | 601 @return (bool): True if profile is a component |
602 @raise exceptions.NotFound: profile doesn't exist | 602 @raise exceptions.NotFound: profile doesn't exist |
603 """ | 603 """ |
604 return self.storage.getEntryPoint(profile_name) | 604 return self.storage.get_entry_point(profile_name) |
605 | 605 |
606 ## History ## | 606 ## History ## |
607 | 607 |
608 def addToHistory(self, client, data): | 608 def add_to_history(self, client, data): |
609 return self.storage.addToHistory(data, client.profile) | 609 return self.storage.add_to_history(data, client.profile) |
610 | 610 |
611 def _historyGetSerialise(self, history_data): | 611 def _history_get_serialise(self, history_data): |
612 return [ | 612 return [ |
613 (uid, timestamp, from_jid, to_jid, message, subject, mess_type, | 613 (uid, timestamp, from_jid, to_jid, message, subject, mess_type, |
614 data_format.serialise(extra)) for uid, timestamp, from_jid, to_jid, message, | 614 data_format.serialise(extra)) for uid, timestamp, from_jid, to_jid, message, |
615 subject, mess_type, extra in history_data | 615 subject, mess_type, extra in history_data |
616 ] | 616 ] |
617 | 617 |
618 def _historyGet(self, from_jid_s, to_jid_s, limit=C.HISTORY_LIMIT_NONE, between=True, | 618 def _history_get(self, from_jid_s, to_jid_s, limit=C.HISTORY_LIMIT_NONE, between=True, |
619 filters=None, profile=C.PROF_KEY_NONE): | 619 filters=None, profile=C.PROF_KEY_NONE): |
620 d = self.historyGet(jid.JID(from_jid_s), jid.JID(to_jid_s), limit, between, | 620 d = self.history_get(jid.JID(from_jid_s), jid.JID(to_jid_s), limit, between, |
621 filters, profile) | 621 filters, profile) |
622 d.addCallback(self._historyGetSerialise) | 622 d.addCallback(self._history_get_serialise) |
623 return d | 623 return d |
624 | 624 |
625 def historyGet(self, from_jid, to_jid, limit=C.HISTORY_LIMIT_NONE, between=True, | 625 def history_get(self, from_jid, to_jid, limit=C.HISTORY_LIMIT_NONE, between=True, |
626 filters=None, profile=C.PROF_KEY_NONE): | 626 filters=None, profile=C.PROF_KEY_NONE): |
627 """Retrieve messages in history | 627 """Retrieve messages in history |
628 | 628 |
629 @param from_jid (JID): source JID (full, or bare for catchall) | 629 @param from_jid (JID): source JID (full, or bare for catchall) |
630 @param to_jid (JID): dest JID (full, or bare for catchall) | 630 @param to_jid (JID): dest JID (full, or bare for catchall) |
634 - C.HISTORY_LIMIT_DEFAULT to use the HISTORY_LIMIT parameter value | 634 - C.HISTORY_LIMIT_DEFAULT to use the HISTORY_LIMIT parameter value |
635 @param between (bool): confound source and dest (ignore the direction) | 635 @param between (bool): confound source and dest (ignore the direction) |
636 @param filters (dict[unicode, unicode]): pattern to filter the history results | 636 @param filters (dict[unicode, unicode]): pattern to filter the history results |
637 (see bridge API for details) | 637 (see bridge API for details) |
638 @param profile (str): %(doc_profile)s | 638 @param profile (str): %(doc_profile)s |
639 @return (D(list)): list of message data as in [messageNew] | 639 @return (D(list)): list of message data as in [message_new] |
640 """ | 640 """ |
641 assert profile != C.PROF_KEY_NONE | 641 assert profile != C.PROF_KEY_NONE |
642 if limit == C.HISTORY_LIMIT_DEFAULT: | 642 if limit == C.HISTORY_LIMIT_DEFAULT: |
643 limit = int(self.getParamA(C.HISTORY_LIMIT, "General", profile_key=profile)) | 643 limit = int(self.param_get_a(C.HISTORY_LIMIT, "General", profile_key=profile)) |
644 elif limit == C.HISTORY_LIMIT_NONE: | 644 elif limit == C.HISTORY_LIMIT_NONE: |
645 limit = None | 645 limit = None |
646 if limit == 0: | 646 if limit == 0: |
647 return defer.succeed([]) | 647 return defer.succeed([]) |
648 return self.storage.historyGet(from_jid, to_jid, limit, between, filters, profile) | 648 return self.storage.history_get(from_jid, to_jid, limit, between, filters, profile) |
649 | 649 |
650 ## Statuses ## | 650 ## Statuses ## |
651 | 651 |
652 def _getPresenceStatuses(self, profile_key): | 652 def _get_presence_statuses(self, profile_key): |
653 ret = self.getPresenceStatuses(profile_key) | 653 ret = self.presence_statuses_get(profile_key) |
654 return {entity.full(): data for entity, data in ret.items()} | 654 return {entity.full(): data for entity, data in ret.items()} |
655 | 655 |
656 def getPresenceStatuses(self, profile_key): | 656 def presence_statuses_get(self, profile_key): |
657 """Get all the presence statuses of a profile | 657 """Get all the presence statuses of a profile |
658 | 658 |
659 @param profile_key: %(doc_profile_key)s | 659 @param profile_key: %(doc_profile_key)s |
660 @return: presence data: key=entity JID, value=presence data for this entity | 660 @return: presence data: key=entity JID, value=presence data for this entity |
661 """ | 661 """ |
662 client = self.host.getClient(profile_key) | 662 client = self.host.get_client(profile_key) |
663 profile_cache = self._getProfileCache(client) | 663 profile_cache = self._get_profile_cache(client) |
664 entities_presence = {} | 664 entities_presence = {} |
665 | 665 |
666 for entity_jid, entity_data in profile_cache.items(): | 666 for entity_jid, entity_data in profile_cache.items(): |
667 for resource, resource_data in entity_data.items(): | 667 for resource, resource_data in entity_data.items(): |
668 full_jid = copy.copy(entity_jid) | 668 full_jid = copy.copy(entity_jid) |
669 full_jid.resource = resource | 669 full_jid.resource = resource |
670 try: | 670 try: |
671 presence_data = self.getEntityDatum(client, full_jid, "presence") | 671 presence_data = self.get_entity_datum(client, full_jid, "presence") |
672 except KeyError: | 672 except KeyError: |
673 continue | 673 continue |
674 entities_presence.setdefault(entity_jid, {})[ | 674 entities_presence.setdefault(entity_jid, {})[ |
675 resource or "" | 675 resource or "" |
676 ] = presence_data | 676 ] = presence_data |
677 | 677 |
678 return entities_presence | 678 return entities_presence |
679 | 679 |
680 def setPresenceStatus(self, entity_jid, show, priority, statuses, profile_key): | 680 def set_presence_status(self, entity_jid, show, priority, statuses, profile_key): |
681 """Change the presence status of an entity | 681 """Change the presence status of an entity |
682 | 682 |
683 @param entity_jid: jid.JID of the entity | 683 @param entity_jid: jid.JID of the entity |
684 @param show: show status | 684 @param show: show status |
685 @param priority: priority | 685 @param priority: priority |
686 @param statuses: dictionary of statuses | 686 @param statuses: dictionary of statuses |
687 @param profile_key: %(doc_profile_key)s | 687 @param profile_key: %(doc_profile_key)s |
688 """ | 688 """ |
689 client = self.host.getClient(profile_key) | 689 client = self.host.get_client(profile_key) |
690 presence_data = PresenceTuple(show, priority, statuses) | 690 presence_data = PresenceTuple(show, priority, statuses) |
691 self.updateEntityData( | 691 self.update_entity_data( |
692 client, entity_jid, "presence", presence_data | 692 client, entity_jid, "presence", presence_data |
693 ) | 693 ) |
694 if entity_jid.resource and show != C.PRESENCE_UNAVAILABLE: | 694 if entity_jid.resource and show != C.PRESENCE_UNAVAILABLE: |
695 # If a resource is available, bare jid should not have presence information | 695 # If a resource is available, bare jid should not have presence information |
696 try: | 696 try: |
697 self.delEntityDatum(client, entity_jid.userhostJID(), "presence") | 697 self.del_entity_datum(client, entity_jid.userhostJID(), "presence") |
698 except (KeyError, exceptions.UnknownEntityError): | 698 except (KeyError, exceptions.UnknownEntityError): |
699 pass | 699 pass |
700 | 700 |
701 ## Resources ## | 701 ## Resources ## |
702 | 702 |
703 def _getAllResource(self, jid_s, profile_key): | 703 def _get_all_resource(self, jid_s, profile_key): |
704 client = self.host.getClient(profile_key) | 704 client = self.host.get_client(profile_key) |
705 jid_ = jid.JID(jid_s) | 705 jid_ = jid.JID(jid_s) |
706 return self.getAllResources(client, jid_) | 706 return self.get_all_resources(client, jid_) |
707 | 707 |
708 def getAllResources(self, client, entity_jid): | 708 def get_all_resources(self, client, entity_jid): |
709 """Return all resource from jid for which we have had data in this session | 709 """Return all resource from jid for which we have had data in this session |
710 | 710 |
711 @param entity_jid: bare jid of the entity | 711 @param entity_jid: bare jid of the entity |
712 return (set[unicode]): set of resources | 712 return (set[unicode]): set of resources |
713 | 713 |
715 @raise ValueError: entity_jid has a resource | 715 @raise ValueError: entity_jid has a resource |
716 """ | 716 """ |
717 # FIXME: is there a need to keep cache data for resources which are not connected anymore? | 717 # FIXME: is there a need to keep cache data for resources which are not connected anymore? |
718 if entity_jid.resource: | 718 if entity_jid.resource: |
719 raise ValueError( | 719 raise ValueError( |
720 "getAllResources must be used with a bare jid (got {})".format(entity_jid) | 720 "get_all_resources must be used with a bare jid (got {})".format(entity_jid) |
721 ) | 721 ) |
722 profile_cache = self._getProfileCache(client) | 722 profile_cache = self._get_profile_cache(client) |
723 try: | 723 try: |
724 entity_data = profile_cache[entity_jid.userhostJID()] | 724 entity_data = profile_cache[entity_jid.userhostJID()] |
725 except KeyError: | 725 except KeyError: |
726 raise exceptions.UnknownEntityError( | 726 raise exceptions.UnknownEntityError( |
727 "Entity {} not in cache".format(entity_jid) | 727 "Entity {} not in cache".format(entity_jid) |
728 ) | 728 ) |
729 resources = set(entity_data.keys()) | 729 resources = set(entity_data.keys()) |
730 resources.discard(None) | 730 resources.discard(None) |
731 return resources | 731 return resources |
732 | 732 |
733 def getAvailableResources(self, client, entity_jid): | 733 def get_available_resources(self, client, entity_jid): |
734 """Return available resource for entity_jid | 734 """Return available resource for entity_jid |
735 | 735 |
736 This method differs from getAllResources by returning only available resources | 736 This method differs from get_all_resources by returning only available resources |
737 @param entity_jid: bare jid of the entit | 737 @param entity_jid: bare jid of the entit |
738 return (list[unicode]): list of available resources | 738 return (list[unicode]): list of available resources |
739 | 739 |
740 @raise exceptions.UnknownEntityError: if entity is not in cache | 740 @raise exceptions.UnknownEntityError: if entity is not in cache |
741 """ | 741 """ |
742 available = [] | 742 available = [] |
743 for resource in self.getAllResources(client, entity_jid): | 743 for resource in self.get_all_resources(client, entity_jid): |
744 full_jid = copy.copy(entity_jid) | 744 full_jid = copy.copy(entity_jid) |
745 full_jid.resource = resource | 745 full_jid.resource = resource |
746 try: | 746 try: |
747 presence_data = self.getEntityDatum(client, full_jid, "presence") | 747 presence_data = self.get_entity_datum(client, full_jid, "presence") |
748 except KeyError: | 748 except KeyError: |
749 log.debug("Can't get presence data for {}".format(full_jid)) | 749 log.debug("Can't get presence data for {}".format(full_jid)) |
750 else: | 750 else: |
751 if presence_data.show != C.PRESENCE_UNAVAILABLE: | 751 if presence_data.show != C.PRESENCE_UNAVAILABLE: |
752 available.append(resource) | 752 available.append(resource) |
753 return available | 753 return available |
754 | 754 |
755 def _getMainResource(self, jid_s, profile_key): | 755 def _get_main_resource(self, jid_s, profile_key): |
756 client = self.host.getClient(profile_key) | 756 client = self.host.get_client(profile_key) |
757 jid_ = jid.JID(jid_s) | 757 jid_ = jid.JID(jid_s) |
758 return self.getMainResource(client, jid_) or "" | 758 return self.main_resource_get(client, jid_) or "" |
759 | 759 |
760 def getMainResource(self, client, entity_jid): | 760 def main_resource_get(self, client, entity_jid): |
761 """Return the main resource used by an entity | 761 """Return the main resource used by an entity |
762 | 762 |
763 @param entity_jid: bare entity jid | 763 @param entity_jid: bare entity jid |
764 @return (unicode): main resource or None | 764 @return (unicode): main resource or None |
765 """ | 765 """ |
766 if entity_jid.resource: | 766 if entity_jid.resource: |
767 raise ValueError( | 767 raise ValueError( |
768 "getMainResource must be used with a bare jid (got {})".format(entity_jid) | 768 "main_resource_get must be used with a bare jid (got {})".format(entity_jid) |
769 ) | 769 ) |
770 try: | 770 try: |
771 if self.host.plugins["XEP-0045"].isJoinedRoom(client, entity_jid): | 771 if self.host.plugins["XEP-0045"].is_joined_room(client, entity_jid): |
772 return None # MUC rooms have no main resource | 772 return None # MUC rooms have no main resource |
773 except KeyError: # plugin not found | 773 except KeyError: # plugin not found |
774 pass | 774 pass |
775 try: | 775 try: |
776 resources = self.getAllResources(client, entity_jid) | 776 resources = self.get_all_resources(client, entity_jid) |
777 except exceptions.UnknownEntityError: | 777 except exceptions.UnknownEntityError: |
778 log.warning("Entity is not in cache, we can't find any resource") | 778 log.warning("Entity is not in cache, we can't find any resource") |
779 return None | 779 return None |
780 priority_resources = [] | 780 priority_resources = [] |
781 for resource in resources: | 781 for resource in resources: |
782 full_jid = copy.copy(entity_jid) | 782 full_jid = copy.copy(entity_jid) |
783 full_jid.resource = resource | 783 full_jid.resource = resource |
784 try: | 784 try: |
785 presence_data = self.getEntityDatum(client, full_jid, "presence") | 785 presence_data = self.get_entity_datum(client, full_jid, "presence") |
786 except KeyError: | 786 except KeyError: |
787 log.debug("No presence information for {}".format(full_jid)) | 787 log.debug("No presence information for {}".format(full_jid)) |
788 continue | 788 continue |
789 priority_resources.append((resource, presence_data.priority)) | 789 priority_resources.append((resource, presence_data.priority)) |
790 try: | 790 try: |
793 log.warning("No resource found at all for {}".format(entity_jid)) | 793 log.warning("No resource found at all for {}".format(entity_jid)) |
794 return None | 794 return None |
795 | 795 |
796 ## Entities data ## | 796 ## Entities data ## |
797 | 797 |
798 def _getProfileCache(self, client): | 798 def _get_profile_cache(self, client): |
799 """Check profile validity and return its cache | 799 """Check profile validity and return its cache |
800 | 800 |
801 @param client: SatXMPPClient | 801 @param client: SatXMPPClient |
802 @return (dict): profile cache | 802 @return (dict): profile cache |
803 """ | 803 """ |
804 return self._entities_cache[client.profile] | 804 return self._entities_cache[client.profile] |
805 | 805 |
806 def setSignalOnUpdate(self, key, signal=True): | 806 def set_signal_on_update(self, key, signal=True): |
807 """Set a signal flag on the key | 807 """Set a signal flag on the key |
808 | 808 |
809 When the key will be updated, a signal will be sent to frontends | 809 When the key will be updated, a signal will be sent to frontends |
810 @param key: key to signal | 810 @param key: key to signal |
811 @param signal(boolean): if True, do the signal | 811 @param signal(boolean): if True, do the signal |
813 if signal: | 813 if signal: |
814 self._key_signals.add(key) | 814 self._key_signals.add(key) |
815 else: | 815 else: |
816 self._key_signals.discard(key) | 816 self._key_signals.discard(key) |
817 | 817 |
818 def getAllEntitiesIter(self, client, with_bare=False): | 818 def get_all_entities_iter(self, client, with_bare=False): |
819 """Return an iterator of full jids of all entities in cache | 819 """Return an iterator of full jids of all entities in cache |
820 | 820 |
821 @param with_bare: if True, include bare jids | 821 @param with_bare: if True, include bare jids |
822 @return (list[unicode]): list of jids | 822 @return (list[unicode]): list of jids |
823 """ | 823 """ |
824 profile_cache = self._getProfileCache(client) | 824 profile_cache = self._get_profile_cache(client) |
825 # we construct a list of all known full jids (bare jid of entities x resources) | 825 # we construct a list of all known full jids (bare jid of entities x resources) |
826 for bare_jid, entity_data in profile_cache.items(): | 826 for bare_jid, entity_data in profile_cache.items(): |
827 for resource in entity_data.keys(): | 827 for resource in entity_data.keys(): |
828 if resource is None: | 828 if resource is None: |
829 continue | 829 continue |
830 full_jid = copy.copy(bare_jid) | 830 full_jid = copy.copy(bare_jid) |
831 full_jid.resource = resource | 831 full_jid.resource = resource |
832 yield full_jid | 832 yield full_jid |
833 | 833 |
834 def updateEntityData( | 834 def update_entity_data( |
835 self, client, entity_jid, key, value, silent=False | 835 self, client, entity_jid, key, value, silent=False |
836 ): | 836 ): |
837 """Set a misc data for an entity | 837 """Set a misc data for an entity |
838 | 838 |
839 If key was registered with setSignalOnUpdate, a signal will be sent to frontends | 839 If key was registered with set_signal_on_update, a signal will be sent to frontends |
840 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of | 840 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of |
841 all entities, C.ENTITY_ALL for all entities (all resources + bare jids) | 841 all entities, C.ENTITY_ALL for all entities (all resources + bare jids) |
842 @param key: key to set (eg: C.ENTITY_TYPE) | 842 @param key: key to set (eg: C.ENTITY_TYPE) |
843 @param value: value for this key (eg: C.ENTITY_TYPE_MUC) | 843 @param value: value for this key (eg: C.ENTITY_TYPE_MUC) |
844 @param silent(bool): if True, doesn't send signal to frontend, even if there is a | 844 @param silent(bool): if True, doesn't send signal to frontend, even if there is a |
845 signal flag (see setSignalOnUpdate) | 845 signal flag (see set_signal_on_update) |
846 """ | 846 """ |
847 profile_cache = self._getProfileCache(client) | 847 profile_cache = self._get_profile_cache(client) |
848 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): | 848 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): |
849 entities = self.getAllEntitiesIter(client, entity_jid == C.ENTITY_ALL) | 849 entities = self.get_all_entities_iter(client, entity_jid == C.ENTITY_ALL) |
850 else: | 850 else: |
851 entities = (entity_jid,) | 851 entities = (entity_jid,) |
852 | 852 |
853 for jid_ in entities: | 853 for jid_ in entities: |
854 entity_data = profile_cache.setdefault(jid_.userhostJID(), {}).setdefault( | 854 entity_data = profile_cache.setdefault(jid_.userhostJID(), {}).setdefault( |
855 jid_.resource, {} | 855 jid_.resource, {} |
856 ) | 856 ) |
857 | 857 |
858 entity_data[key] = value | 858 entity_data[key] = value |
859 if key in self._key_signals and not silent: | 859 if key in self._key_signals and not silent: |
860 self.host.bridge.entityDataUpdated( | 860 self.host.bridge.entity_data_updated( |
861 jid_.full(), | 861 jid_.full(), |
862 key, | 862 key, |
863 data_format.serialise(value), | 863 data_format.serialise(value), |
864 client.profile | 864 client.profile |
865 ) | 865 ) |
866 | 866 |
867 def delEntityDatum(self, client, entity_jid, key): | 867 def del_entity_datum(self, client, entity_jid, key): |
868 """Delete a data for an entity | 868 """Delete a data for an entity |
869 | 869 |
870 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of all entities, | 870 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of all entities, |
871 C.ENTITY_ALL for all entities (all resources + bare jids) | 871 C.ENTITY_ALL for all entities (all resources + bare jids) |
872 @param key: key to delete (eg: C.ENTITY_TYPE) | 872 @param key: key to delete (eg: C.ENTITY_TYPE) |
873 | 873 |
874 @raise exceptions.UnknownEntityError: if entity is not in cache | 874 @raise exceptions.UnknownEntityError: if entity is not in cache |
875 @raise KeyError: key is not in cache | 875 @raise KeyError: key is not in cache |
876 """ | 876 """ |
877 profile_cache = self._getProfileCache(client) | 877 profile_cache = self._get_profile_cache(client) |
878 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): | 878 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): |
879 entities = self.getAllEntitiesIter(client, entity_jid == C.ENTITY_ALL) | 879 entities = self.get_all_entities_iter(client, entity_jid == C.ENTITY_ALL) |
880 else: | 880 else: |
881 entities = (entity_jid,) | 881 entities = (entity_jid,) |
882 | 882 |
883 for jid_ in entities: | 883 for jid_ in entities: |
884 try: | 884 try: |
893 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): | 893 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): |
894 continue # we ignore KeyError when deleting keys from several entities | 894 continue # we ignore KeyError when deleting keys from several entities |
895 else: | 895 else: |
896 raise e | 896 raise e |
897 | 897 |
898 def _getEntitiesData(self, entities_jids, keys_list, profile_key): | 898 def _get_entities_data(self, entities_jids, keys_list, profile_key): |
899 client = self.host.getClient(profile_key) | 899 client = self.host.get_client(profile_key) |
900 ret = self.getEntitiesData( | 900 ret = self.entities_data_get( |
901 client, [jid.JID(jid_) for jid_ in entities_jids], keys_list | 901 client, [jid.JID(jid_) for jid_ in entities_jids], keys_list |
902 ) | 902 ) |
903 return { | 903 return { |
904 jid_.full(): {k: data_format.serialise(v) for k,v in data.items()} | 904 jid_.full(): {k: data_format.serialise(v) for k,v in data.items()} |
905 for jid_, data in ret.items() | 905 for jid_, data in ret.items() |
906 } | 906 } |
907 | 907 |
908 def getEntitiesData(self, client, entities_jids, keys_list=None): | 908 def entities_data_get(self, client, entities_jids, keys_list=None): |
909 """Get a list of cached values for several entities at once | 909 """Get a list of cached values for several entities at once |
910 | 910 |
911 @param entities_jids: jids of the entities, or empty list for all entities in cache | 911 @param entities_jids: jids of the entities, or empty list for all entities in cache |
912 @param keys_list (iterable,None): list of keys to get, None for everything | 912 @param keys_list (iterable,None): list of keys to get, None for everything |
913 @param profile_key: %(doc_profile_key)s | 913 @param profile_key: %(doc_profile_key)s |
918 in resulting dict | 918 in resulting dict |
919 | 919 |
920 @raise exceptions.UnknownEntityError: if entity is not in cache | 920 @raise exceptions.UnknownEntityError: if entity is not in cache |
921 """ | 921 """ |
922 | 922 |
923 def fillEntityData(entity_cache_data): | 923 def fill_entity_data(entity_cache_data): |
924 entity_data = {} | 924 entity_data = {} |
925 if keys_list is None: | 925 if keys_list is None: |
926 entity_data = entity_cache_data | 926 entity_data = entity_cache_data |
927 else: | 927 else: |
928 for key in keys_list: | 928 for key in keys_list: |
930 entity_data[key] = entity_cache_data[key] | 930 entity_data[key] = entity_cache_data[key] |
931 except KeyError: | 931 except KeyError: |
932 continue | 932 continue |
933 return entity_data | 933 return entity_data |
934 | 934 |
935 profile_cache = self._getProfileCache(client) | 935 profile_cache = self._get_profile_cache(client) |
936 ret_data = {} | 936 ret_data = {} |
937 if entities_jids: | 937 if entities_jids: |
938 for entity in entities_jids: | 938 for entity in entities_jids: |
939 try: | 939 try: |
940 entity_cache_data = profile_cache[entity.userhostJID()][ | 940 entity_cache_data = profile_cache[entity.userhostJID()][ |
941 entity.resource | 941 entity.resource |
942 ] | 942 ] |
943 except KeyError: | 943 except KeyError: |
944 continue | 944 continue |
945 ret_data[entity.full()] = fillEntityData(entity_cache_data, keys_list) | 945 ret_data[entity.full()] = fill_entity_data(entity_cache_data, keys_list) |
946 else: | 946 else: |
947 for bare_jid, data in profile_cache.items(): | 947 for bare_jid, data in profile_cache.items(): |
948 for resource, entity_cache_data in data.items(): | 948 for resource, entity_cache_data in data.items(): |
949 full_jid = copy.copy(bare_jid) | 949 full_jid = copy.copy(bare_jid) |
950 full_jid.resource = resource | 950 full_jid.resource = resource |
951 ret_data[full_jid] = fillEntityData(entity_cache_data) | 951 ret_data[full_jid] = fill_entity_data(entity_cache_data) |
952 | 952 |
953 return ret_data | 953 return ret_data |
954 | 954 |
955 def _getEntityData(self, entity_jid_s, keys_list=None, profile=C.PROF_KEY_NONE): | 955 def _get_entity_data(self, entity_jid_s, keys_list=None, profile=C.PROF_KEY_NONE): |
956 return self.getEntityData( | 956 return self.entity_data_get( |
957 self.host.getClient(profile), jid.JID(entity_jid_s), keys_list) | 957 self.host.get_client(profile), jid.JID(entity_jid_s), keys_list) |
958 | 958 |
959 def getEntityData(self, client, entity_jid, keys_list=None): | 959 def entity_data_get(self, client, entity_jid, keys_list=None): |
960 """Get a list of cached values for entity | 960 """Get a list of cached values for entity |
961 | 961 |
962 @param entity_jid: JID of the entity | 962 @param entity_jid: JID of the entity |
963 @param keys_list (iterable,None): list of keys to get, None for everything | 963 @param keys_list (iterable,None): list of keys to get, None for everything |
964 @param profile_key: %(doc_profile_key)s | 964 @param profile_key: %(doc_profile_key)s |
966 if there is no value of a given key, resulting dict will | 966 if there is no value of a given key, resulting dict will |
967 have nothing with that key nether | 967 have nothing with that key nether |
968 | 968 |
969 @raise exceptions.UnknownEntityError: if entity is not in cache | 969 @raise exceptions.UnknownEntityError: if entity is not in cache |
970 """ | 970 """ |
971 profile_cache = self._getProfileCache(client) | 971 profile_cache = self._get_profile_cache(client) |
972 try: | 972 try: |
973 entity_data = profile_cache[entity_jid.userhostJID()][entity_jid.resource] | 973 entity_data = profile_cache[entity_jid.userhostJID()][entity_jid.resource] |
974 except KeyError: | 974 except KeyError: |
975 raise exceptions.UnknownEntityError( | 975 raise exceptions.UnknownEntityError( |
976 "Entity {} not in cache (was requesting {})".format( | 976 "Entity {} not in cache (was requesting {})".format( |
980 if keys_list is None: | 980 if keys_list is None: |
981 return entity_data | 981 return entity_data |
982 | 982 |
983 return {key: entity_data[key] for key in keys_list if key in entity_data} | 983 return {key: entity_data[key] for key in keys_list if key in entity_data} |
984 | 984 |
985 def getEntityDatum(self, client, entity_jid, key): | 985 def get_entity_datum(self, client, entity_jid, key): |
986 """Get a datum from entity | 986 """Get a datum from entity |
987 | 987 |
988 @param entity_jid: JID of the entity | 988 @param entity_jid: JID of the entity |
989 @param key: key to get | 989 @param key: key to get |
990 @return: requested value | 990 @return: requested value |
991 | 991 |
992 @raise exceptions.UnknownEntityError: if entity is not in cache | 992 @raise exceptions.UnknownEntityError: if entity is not in cache |
993 @raise KeyError: if there is no value for this key and this entity | 993 @raise KeyError: if there is no value for this key and this entity |
994 """ | 994 """ |
995 return self.getEntityData(client, entity_jid, (key,))[key] | 995 return self.entity_data_get(client, entity_jid, (key,))[key] |
996 | 996 |
997 def delEntityCache( | 997 def del_entity_cache( |
998 self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE | 998 self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE |
999 ): | 999 ): |
1000 """Remove all cached data for entity | 1000 """Remove all cached data for entity |
1001 | 1001 |
1002 @param entity_jid: JID of the entity to delete | 1002 @param entity_jid: JID of the entity to delete |
1003 @param delete_all_resources: if True also delete all known resources from cache (a bare jid must be given in this case) | 1003 @param delete_all_resources: if True also delete all known resources from cache (a bare jid must be given in this case) |
1004 @param profile_key: %(doc_profile_key)s | 1004 @param profile_key: %(doc_profile_key)s |
1005 | 1005 |
1006 @raise exceptions.UnknownEntityError: if entity is not in cache | 1006 @raise exceptions.UnknownEntityError: if entity is not in cache |
1007 """ | 1007 """ |
1008 client = self.host.getClient(profile_key) | 1008 client = self.host.get_client(profile_key) |
1009 profile_cache = self._getProfileCache(client) | 1009 profile_cache = self._get_profile_cache(client) |
1010 | 1010 |
1011 if delete_all_resources: | 1011 if delete_all_resources: |
1012 if entity_jid.resource: | 1012 if entity_jid.resource: |
1013 raise ValueError(_("Need a bare jid to delete all resources")) | 1013 raise ValueError(_("Need a bare jid to delete all resources")) |
1014 try: | 1014 try: |
1025 "Entity {} not in cache".format(entity_jid) | 1025 "Entity {} not in cache".format(entity_jid) |
1026 ) | 1026 ) |
1027 | 1027 |
1028 ## Encryption ## | 1028 ## Encryption ## |
1029 | 1029 |
1030 def encryptValue(self, value, profile): | 1030 def encrypt_value(self, value, profile): |
1031 """Encrypt a value for the given profile. The personal key must be loaded | 1031 """Encrypt a value for the given profile. The personal key must be loaded |
1032 already in the profile session, that should be the case if the profile is | 1032 already in the profile session, that should be the case if the profile is |
1033 already authenticated. | 1033 already authenticated. |
1034 | 1034 |
1035 @param value (str): the value to encrypt | 1035 @param value (str): the value to encrypt |
1036 @param profile (str): %(doc_profile)s | 1036 @param profile (str): %(doc_profile)s |
1037 @return: the deferred encrypted value | 1037 @return: the deferred encrypted value |
1038 """ | 1038 """ |
1039 try: | 1039 try: |
1040 personal_key = self.auth_sessions.profileGetUnique(profile)[ | 1040 personal_key = self.auth_sessions.profile_get_unique(profile)[ |
1041 C.MEMORY_CRYPTO_KEY | 1041 C.MEMORY_CRYPTO_KEY |
1042 ] | 1042 ] |
1043 except TypeError: | 1043 except TypeError: |
1044 raise exceptions.InternalError( | 1044 raise exceptions.InternalError( |
1045 _("Trying to encrypt a value for %s while the personal key is undefined!") | 1045 _("Trying to encrypt a value for %s while the personal key is undefined!") |
1046 % profile | 1046 % profile |
1047 ) | 1047 ) |
1048 return BlockCipher.encrypt(personal_key, value) | 1048 return BlockCipher.encrypt(personal_key, value) |
1049 | 1049 |
1050 def decryptValue(self, value, profile): | 1050 def decrypt_value(self, value, profile): |
1051 """Decrypt a value for the given profile. The personal key must be loaded | 1051 """Decrypt a value for the given profile. The personal key must be loaded |
1052 already in the profile session, that should be the case if the profile is | 1052 already in the profile session, that should be the case if the profile is |
1053 already authenticated. | 1053 already authenticated. |
1054 | 1054 |
1055 @param value (str): the value to decrypt | 1055 @param value (str): the value to decrypt |
1056 @param profile (str): %(doc_profile)s | 1056 @param profile (str): %(doc_profile)s |
1057 @return: the deferred decrypted value | 1057 @return: the deferred decrypted value |
1058 """ | 1058 """ |
1059 try: | 1059 try: |
1060 personal_key = self.auth_sessions.profileGetUnique(profile)[ | 1060 personal_key = self.auth_sessions.profile_get_unique(profile)[ |
1061 C.MEMORY_CRYPTO_KEY | 1061 C.MEMORY_CRYPTO_KEY |
1062 ] | 1062 ] |
1063 except TypeError: | 1063 except TypeError: |
1064 raise exceptions.InternalError( | 1064 raise exceptions.InternalError( |
1065 _("Trying to decrypt a value for %s while the personal key is undefined!") | 1065 _("Trying to decrypt a value for %s while the personal key is undefined!") |
1066 % profile | 1066 % profile |
1067 ) | 1067 ) |
1068 return BlockCipher.decrypt(personal_key, value) | 1068 return BlockCipher.decrypt(personal_key, value) |
1069 | 1069 |
1070 def encryptPersonalData(self, data_key, data_value, crypto_key, profile): | 1070 def encrypt_personal_data(self, data_key, data_value, crypto_key, profile): |
1071 """Re-encrypt a personal data (saved to a PersistentDict). | 1071 """Re-encrypt a personal data (saved to a PersistentDict). |
1072 | 1072 |
1073 @param data_key: key for the individual PersistentDict instance | 1073 @param data_key: key for the individual PersistentDict instance |
1074 @param data_value: the value to be encrypted | 1074 @param data_value: the value to be encrypted |
1075 @param crypto_key: the key to encrypt the value | 1075 @param crypto_key: the key to encrypt the value |
1076 @param profile: %(profile_doc)s | 1076 @param profile: %(profile_doc)s |
1077 @return: a deferred None value | 1077 @return: a deferred None value |
1078 """ | 1078 """ |
1079 | 1079 |
1080 def gotIndMemory(data): | 1080 def got_ind_memory(data): |
1081 data[data_key] = BlockCipher.encrypt(crypto_key, data_value) | 1081 data[data_key] = BlockCipher.encrypt(crypto_key, data_value) |
1082 return data.force(data_key) | 1082 return data.force(data_key) |
1083 | 1083 |
1084 def done(__): | 1084 def done(__): |
1085 log.debug( | 1085 log.debug( |
1086 _("Personal data (%(ns)s, %(key)s) has been successfuly encrypted") | 1086 _("Personal data (%(ns)s, %(key)s) has been successfuly encrypted") |
1087 % {"ns": C.MEMORY_CRYPTO_NAMESPACE, "key": data_key} | 1087 % {"ns": C.MEMORY_CRYPTO_NAMESPACE, "key": data_key} |
1088 ) | 1088 ) |
1089 | 1089 |
1090 d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() | 1090 d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() |
1091 return d.addCallback(gotIndMemory).addCallback(done) | 1091 return d.addCallback(got_ind_memory).addCallback(done) |
1092 | 1092 |
1093 ## Subscription requests ## | 1093 ## Subscription requests ## |
1094 | 1094 |
1095 def addWaitingSub(self, type_, entity_jid, profile_key): | 1095 def add_waiting_sub(self, type_, entity_jid, profile_key): |
1096 """Called when a subcription request is received""" | 1096 """Called when a subcription request is received""" |
1097 profile = self.getProfileName(profile_key) | 1097 profile = self.get_profile_name(profile_key) |
1098 assert profile | 1098 assert profile |
1099 if profile not in self.subscriptions: | 1099 if profile not in self.subscriptions: |
1100 self.subscriptions[profile] = {} | 1100 self.subscriptions[profile] = {} |
1101 self.subscriptions[profile][entity_jid] = type_ | 1101 self.subscriptions[profile][entity_jid] = type_ |
1102 | 1102 |
1103 def delWaitingSub(self, entity_jid, profile_key): | 1103 def del_waiting_sub(self, entity_jid, profile_key): |
1104 """Called when a subcription request is finished""" | 1104 """Called when a subcription request is finished""" |
1105 profile = self.getProfileName(profile_key) | 1105 profile = self.get_profile_name(profile_key) |
1106 assert profile | 1106 assert profile |
1107 if profile in self.subscriptions and entity_jid in self.subscriptions[profile]: | 1107 if profile in self.subscriptions and entity_jid in self.subscriptions[profile]: |
1108 del self.subscriptions[profile][entity_jid] | 1108 del self.subscriptions[profile][entity_jid] |
1109 | 1109 |
1110 def getWaitingSub(self, profile_key): | 1110 def sub_waiting_get(self, profile_key): |
1111 """Called to get a list of currently waiting subscription requests""" | 1111 """Called to get a list of currently waiting subscription requests""" |
1112 profile = self.getProfileName(profile_key) | 1112 profile = self.get_profile_name(profile_key) |
1113 if not profile: | 1113 if not profile: |
1114 log.error(_("Asking waiting subscriptions for a non-existant profile")) | 1114 log.error(_("Asking waiting subscriptions for a non-existant profile")) |
1115 return {} | 1115 return {} |
1116 if profile not in self.subscriptions: | 1116 if profile not in self.subscriptions: |
1117 return {} | 1117 return {} |
1118 | 1118 |
1119 return self.subscriptions[profile] | 1119 return self.subscriptions[profile] |
1120 | 1120 |
1121 ## Parameters ## | 1121 ## Parameters ## |
1122 | 1122 |
1123 def getStringParamA(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): | 1123 def get_string_param_a(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): |
1124 return self.params.getStringParamA(name, category, attr, profile_key) | 1124 return self.params.get_string_param_a(name, category, attr, profile_key) |
1125 | 1125 |
1126 def getParamA(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): | 1126 def param_get_a(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): |
1127 return self.params.getParamA(name, category, attr, profile_key=profile_key) | 1127 return self.params.param_get_a(name, category, attr, profile_key=profile_key) |
1128 | 1128 |
1129 def asyncGetParamA( | 1129 def param_get_a_async( |
1130 self, | 1130 self, |
1131 name, | 1131 name, |
1132 category, | 1132 category, |
1133 attr="value", | 1133 attr="value", |
1134 security_limit=C.NO_SECURITY_LIMIT, | 1134 security_limit=C.NO_SECURITY_LIMIT, |
1135 profile_key=C.PROF_KEY_NONE, | 1135 profile_key=C.PROF_KEY_NONE, |
1136 ): | 1136 ): |
1137 return self.params.asyncGetParamA( | 1137 return self.params.param_get_a_async( |
1138 name, category, attr, security_limit, profile_key | 1138 name, category, attr, security_limit, profile_key |
1139 ) | 1139 ) |
1140 | 1140 |
1141 def _getParamsValuesFromCategory( | 1141 def _get_params_values_from_category( |
1142 self, category, security_limit, app, extra_s, profile_key | 1142 self, category, security_limit, app, extra_s, profile_key |
1143 ): | 1143 ): |
1144 return self.params._getParamsValuesFromCategory( | 1144 return self.params._get_params_values_from_category( |
1145 category, security_limit, app, extra_s, profile_key | 1145 category, security_limit, app, extra_s, profile_key |
1146 ) | 1146 ) |
1147 | 1147 |
1148 def asyncGetStringParamA( | 1148 def async_get_string_param_a( |
1149 self, name, category, attribute="value", security_limit=C.NO_SECURITY_LIMIT, | 1149 self, name, category, attribute="value", security_limit=C.NO_SECURITY_LIMIT, |
1150 profile_key=C.PROF_KEY_NONE): | 1150 profile_key=C.PROF_KEY_NONE): |
1151 | 1151 |
1152 profile = self.getProfileName(profile_key) | 1152 profile = self.get_profile_name(profile_key) |
1153 return defer.ensureDeferred(self.params.asyncGetStringParamA( | 1153 return defer.ensureDeferred(self.params.async_get_string_param_a( |
1154 name, category, attribute, security_limit, profile | 1154 name, category, attribute, security_limit, profile |
1155 )) | 1155 )) |
1156 | 1156 |
1157 def _getParamsUI(self, security_limit, app, extra_s, profile_key): | 1157 def _get_params_ui(self, security_limit, app, extra_s, profile_key): |
1158 return self.params._getParamsUI(security_limit, app, extra_s, profile_key) | 1158 return self.params._get_params_ui(security_limit, app, extra_s, profile_key) |
1159 | 1159 |
1160 def getParamsCategories(self): | 1160 def params_categories_get(self): |
1161 return self.params.getParamsCategories() | 1161 return self.params.params_categories_get() |
1162 | 1162 |
1163 def setParam( | 1163 def param_set( |
1164 self, | 1164 self, |
1165 name, | 1165 name, |
1166 value, | 1166 value, |
1167 category, | 1167 category, |
1168 security_limit=C.NO_SECURITY_LIMIT, | 1168 security_limit=C.NO_SECURITY_LIMIT, |
1169 profile_key=C.PROF_KEY_NONE, | 1169 profile_key=C.PROF_KEY_NONE, |
1170 ): | 1170 ): |
1171 return self.params.setParam(name, value, category, security_limit, profile_key) | 1171 return self.params.param_set(name, value, category, security_limit, profile_key) |
1172 | 1172 |
1173 def updateParams(self, xml): | 1173 def update_params(self, xml): |
1174 return self.params.updateParams(xml) | 1174 return self.params.update_params(xml) |
1175 | 1175 |
1176 def paramsRegisterApp(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=""): | 1176 def params_register_app(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=""): |
1177 return self.params.paramsRegisterApp(xml, security_limit, app) | 1177 return self.params.params_register_app(xml, security_limit, app) |
1178 | 1178 |
1179 def setDefault(self, name, category, callback, errback=None): | 1179 def set_default(self, name, category, callback, errback=None): |
1180 return self.params.setDefault(name, category, callback, errback) | 1180 return self.params.set_default(name, category, callback, errback) |
1181 | 1181 |
1182 ## Private Data ## | 1182 ## Private Data ## |
1183 | 1183 |
1184 def _privateDataSet(self, namespace, key, data_s, profile_key): | 1184 def _private_data_set(self, namespace, key, data_s, profile_key): |
1185 client = self.host.getClient(profile_key) | 1185 client = self.host.get_client(profile_key) |
1186 # we accept any type | 1186 # we accept any type |
1187 data = data_format.deserialise(data_s, type_check=None) | 1187 data = data_format.deserialise(data_s, type_check=None) |
1188 return defer.ensureDeferred(self.storage.setPrivateValue( | 1188 return defer.ensureDeferred(self.storage.set_private_value( |
1189 namespace, key, data, binary=True, profile=client.profile)) | 1189 namespace, key, data, binary=True, profile=client.profile)) |
1190 | 1190 |
1191 def _privateDataGet(self, namespace, key, profile_key): | 1191 def _private_data_get(self, namespace, key, profile_key): |
1192 client = self.host.getClient(profile_key) | 1192 client = self.host.get_client(profile_key) |
1193 d = defer.ensureDeferred( | 1193 d = defer.ensureDeferred( |
1194 self.storage.getPrivates( | 1194 self.storage.get_privates( |
1195 namespace, [key], binary=True, profile=client.profile) | 1195 namespace, [key], binary=True, profile=client.profile) |
1196 ) | 1196 ) |
1197 d.addCallback(lambda data_dict: data_format.serialise(data_dict.get(key))) | 1197 d.addCallback(lambda data_dict: data_format.serialise(data_dict.get(key))) |
1198 return d | 1198 return d |
1199 | 1199 |
1200 def _privateDataDelete(self, namespace, key, profile_key): | 1200 def _private_data_delete(self, namespace, key, profile_key): |
1201 client = self.host.getClient(profile_key) | 1201 client = self.host.get_client(profile_key) |
1202 return defer.ensureDeferred(self.storage.delPrivateValue( | 1202 return defer.ensureDeferred(self.storage.del_private_value( |
1203 namespace, key, binary=True, profile=client.profile)) | 1203 namespace, key, binary=True, profile=client.profile)) |
1204 | 1204 |
1205 ## Files ## | 1205 ## Files ## |
1206 | 1206 |
1207 def checkFilePermission( | 1207 def check_file_permission( |
1208 self, | 1208 self, |
1209 file_data: dict, | 1209 file_data: dict, |
1210 peer_jid: Optional[jid.JID], | 1210 peer_jid: Optional[jid.JID], |
1211 perms_to_check: Optional[Tuple[str]], | 1211 perms_to_check: Optional[Tuple[str]], |
1212 set_affiliation: bool = False | 1212 set_affiliation: bool = False |
1213 ) -> None: | 1213 ) -> None: |
1214 """Check that an entity has the right permission on a file | 1214 """Check that an entity has the right permission on a file |
1215 | 1215 |
1216 @param file_data: data of one file, as returned by getFiles | 1216 @param file_data: data of one file, as returned by get_files |
1217 @param peer_jid: entity trying to access the file | 1217 @param peer_jid: entity trying to access the file |
1218 @param perms_to_check: permissions to check | 1218 @param perms_to_check: permissions to check |
1219 tuple of C.ACCESS_PERM_* | 1219 tuple of C.ACCESS_PERM_* |
1220 @param check_parents: if True, also check all parents until root node | 1220 @param check_parents: if True, also check all parents until root node |
1221 @parma set_affiliation: if True, "affiliation" metadata will be set | 1221 @parma set_affiliation: if True, "affiliation" metadata will be set |
1266 else: | 1266 else: |
1267 raise exceptions.InternalError( | 1267 raise exceptions.InternalError( |
1268 _("unknown access type: {type}").format(type=perm_type) | 1268 _("unknown access type: {type}").format(type=perm_type) |
1269 ) | 1269 ) |
1270 | 1270 |
1271 async def checkPermissionToRoot(self, client, file_data, peer_jid, perms_to_check): | 1271 async def check_permission_to_root(self, client, file_data, peer_jid, perms_to_check): |
1272 """do checkFilePermission on file_data and all its parents until root""" | 1272 """do check_file_permission on file_data and all its parents until root""" |
1273 current = file_data | 1273 current = file_data |
1274 while True: | 1274 while True: |
1275 self.checkFilePermission(current, peer_jid, perms_to_check) | 1275 self.check_file_permission(current, peer_jid, perms_to_check) |
1276 parent = current["parent"] | 1276 parent = current["parent"] |
1277 if not parent: | 1277 if not parent: |
1278 break | 1278 break |
1279 files_data = await self.getFiles( | 1279 files_data = await self.get_files( |
1280 client, peer_jid=None, file_id=parent, perms_to_check=None | 1280 client, peer_jid=None, file_id=parent, perms_to_check=None |
1281 ) | 1281 ) |
1282 try: | 1282 try: |
1283 current = files_data[0] | 1283 current = files_data[0] |
1284 except IndexError: | 1284 except IndexError: |
1285 raise exceptions.DataError("Missing parent") | 1285 raise exceptions.DataError("Missing parent") |
1286 | 1286 |
1287 async def _getParentDir( | 1287 async def _get_parent_dir( |
1288 self, client, path, parent, namespace, owner, peer_jid, perms_to_check | 1288 self, client, path, parent, namespace, owner, peer_jid, perms_to_check |
1289 ): | 1289 ): |
1290 """Retrieve parent node from a path, or last existing directory | 1290 """Retrieve parent node from a path, or last existing directory |
1291 | 1291 |
1292 each directory of the path will be retrieved, until the last existing one | 1292 each directory of the path will be retrieved, until the last existing one |
1306 | 1306 |
1307 # we retrieve all directories from path until we get the parent container | 1307 # we retrieve all directories from path until we get the parent container |
1308 # non existing directories will be created | 1308 # non existing directories will be created |
1309 parent = "" | 1309 parent = "" |
1310 for idx, path_elt in enumerate(path_elts): | 1310 for idx, path_elt in enumerate(path_elts): |
1311 directories = await self.storage.getFiles( | 1311 directories = await self.storage.get_files( |
1312 client, | 1312 client, |
1313 parent=parent, | 1313 parent=parent, |
1314 type_=C.FILE_TYPE_DIRECTORY, | 1314 type_=C.FILE_TYPE_DIRECTORY, |
1315 name=path_elt, | 1315 name=path_elt, |
1316 namespace=namespace, | 1316 namespace=namespace, |
1323 raise exceptions.InternalError( | 1323 raise exceptions.InternalError( |
1324 _("Several directories found, this should not happen") | 1324 _("Several directories found, this should not happen") |
1325 ) | 1325 ) |
1326 else: | 1326 else: |
1327 directory = directories[0] | 1327 directory = directories[0] |
1328 self.checkFilePermission(directory, peer_jid, perms_to_check) | 1328 self.check_file_permission(directory, peer_jid, perms_to_check) |
1329 parent = directory["id"] | 1329 parent = directory["id"] |
1330 return (parent, []) | 1330 return (parent, []) |
1331 | 1331 |
1332 def getFileAffiliations(self, file_data: dict) -> Dict[jid.JID, str]: | 1332 def get_file_affiliations(self, file_data: dict) -> Dict[jid.JID, str]: |
1333 """Convert file access to pubsub like affiliations""" | 1333 """Convert file access to pubsub like affiliations""" |
1334 affiliations = {} | 1334 affiliations = {} |
1335 access_data = file_data['access'] | 1335 access_data = file_data['access'] |
1336 | 1336 |
1337 read_data = access_data.get(C.ACCESS_PERM_READ, {}) | 1337 read_data = access_data.get(C.ACCESS_PERM_READ, {}) |
1350 if owner: | 1350 if owner: |
1351 affiliations[owner] = 'owner' | 1351 affiliations[owner] = 'owner' |
1352 | 1352 |
1353 return affiliations | 1353 return affiliations |
1354 | 1354 |
1355 def _setFileAffiliationsUpdate( | 1355 def _set_file_affiliations_update( |
1356 self, | 1356 self, |
1357 access: dict, | 1357 access: dict, |
1358 file_data: dict, | 1358 file_data: dict, |
1359 affiliations: Dict[jid.JID, str] | 1359 affiliations: Dict[jid.JID, str] |
1360 ) -> None: | 1360 ) -> None: |
1399 elif affiliation == "owner": | 1399 elif affiliation == "owner": |
1400 raise NotImplementedError('"owner" affiliation can\'t be set') | 1400 raise NotImplementedError('"owner" affiliation can\'t be set') |
1401 else: | 1401 else: |
1402 raise ValueError(f"unknown affiliation: {affiliation!r}") | 1402 raise ValueError(f"unknown affiliation: {affiliation!r}") |
1403 | 1403 |
1404 async def setFileAffiliations( | 1404 async def set_file_affiliations( |
1405 self, | 1405 self, |
1406 client, | 1406 client, |
1407 file_data: dict, | 1407 file_data: dict, |
1408 affiliations: Dict[jid.JID, str] | 1408 affiliations: Dict[jid.JID, str] |
1409 ) -> None: | 1409 ) -> None: |
1415 - "publisher" gives read and write permissions | 1415 - "publisher" gives read and write permissions |
1416 - "member" gives read permission only | 1416 - "member" gives read permission only |
1417 - "none" removes both read and write permissions | 1417 - "none" removes both read and write permissions |
1418 """ | 1418 """ |
1419 file_id = file_data['id'] | 1419 file_id = file_data['id'] |
1420 await self.fileUpdate( | 1420 await self.file_update( |
1421 file_id, | 1421 file_id, |
1422 'access', | 1422 'access', |
1423 update_cb=partial( | 1423 update_cb=partial( |
1424 self._setFileAffiliationsUpdate, | 1424 self._set_file_affiliations_update, |
1425 file_data=file_data, | 1425 file_data=file_data, |
1426 affiliations=affiliations | 1426 affiliations=affiliations |
1427 ), | 1427 ), |
1428 ) | 1428 ) |
1429 | 1429 |
1430 def _setFileAccessModelUpdate( | 1430 def _set_file_access_model_update( |
1431 self, | 1431 self, |
1432 access: dict, | 1432 access: dict, |
1433 file_data: dict, | 1433 file_data: dict, |
1434 access_model: str | 1434 access_model: str |
1435 ) -> None: | 1435 ) -> None: |
1443 | 1443 |
1444 read_data['type'] = requested_type | 1444 read_data['type'] = requested_type |
1445 if requested_type == C.ACCESS_TYPE_WHITELIST and 'jids' not in read_data: | 1445 if requested_type == C.ACCESS_TYPE_WHITELIST and 'jids' not in read_data: |
1446 read_data['jids'] = [] | 1446 read_data['jids'] = [] |
1447 | 1447 |
1448 async def setFileAccessModel( | 1448 async def set_file_access_model( |
1449 self, | 1449 self, |
1450 client, | 1450 client, |
1451 file_data: dict, | 1451 file_data: dict, |
1452 access_model: str, | 1452 access_model: str, |
1453 ) -> None: | 1453 ) -> None: |
1456 Only 2 access models are supported so far: | 1456 Only 2 access models are supported so far: |
1457 - "open": set public access to file/dir | 1457 - "open": set public access to file/dir |
1458 - "whitelist": set whitelist to file/dir | 1458 - "whitelist": set whitelist to file/dir |
1459 """ | 1459 """ |
1460 file_id = file_data['id'] | 1460 file_id = file_data['id'] |
1461 await self.fileUpdate( | 1461 await self.file_update( |
1462 file_id, | 1462 file_id, |
1463 'access', | 1463 'access', |
1464 update_cb=partial( | 1464 update_cb=partial( |
1465 self._setFileAccessModelUpdate, | 1465 self._set_file_access_model_update, |
1466 file_data=file_data, | 1466 file_data=file_data, |
1467 access_model=access_model | 1467 access_model=access_model |
1468 ), | 1468 ), |
1469 ) | 1469 ) |
1470 | 1470 |
1471 def getFilesOwner( | 1471 def get_files_owner( |
1472 self, | 1472 self, |
1473 client, | 1473 client, |
1474 owner: Optional[jid.JID], | 1474 owner: Optional[jid.JID], |
1475 peer_jid: Optional[jid.JID], | 1475 peer_jid: Optional[jid.JID], |
1476 file_id: Optional[str] = None, | 1476 file_id: Optional[str] = None, |
1497 raise exceptions.InternalError( | 1497 raise exceptions.InternalError( |
1498 "Owner must be set for component if peer_jid is None" | 1498 "Owner must be set for component if peer_jid is None" |
1499 ) | 1499 ) |
1500 return peer_jid.userhostJID() | 1500 return peer_jid.userhostJID() |
1501 | 1501 |
1502 async def getFiles( | 1502 async def get_files( |
1503 self, client, peer_jid, file_id=None, version=None, parent=None, path=None, | 1503 self, client, peer_jid, file_id=None, version=None, parent=None, path=None, |
1504 type_=None, file_hash=None, hash_algo=None, name=None, namespace=None, | 1504 type_=None, file_hash=None, hash_algo=None, name=None, namespace=None, |
1505 mime_type=None, public_id=None, owner=None, access=None, projection=None, | 1505 mime_type=None, public_id=None, owner=None, access=None, projection=None, |
1506 unique=False, perms_to_check=(C.ACCESS_PERM_READ,)): | 1506 unique=False, perms_to_check=(C.ACCESS_PERM_READ,)): |
1507 """Retrieve files with with given filters | 1507 """Retrieve files with with given filters |
1524 @param name(unicode, None): name of the file to retrieve | 1524 @param name(unicode, None): name of the file to retrieve |
1525 @param namespace(unicode, None): namespace of the files to retrieve | 1525 @param namespace(unicode, None): namespace of the files to retrieve |
1526 @param mime_type(unicode, None): filter on this mime type | 1526 @param mime_type(unicode, None): filter on this mime type |
1527 @param public_id(unicode, None): filter on this public id | 1527 @param public_id(unicode, None): filter on this public id |
1528 @param owner(jid.JID, None): if not None, only get files from this owner | 1528 @param owner(jid.JID, None): if not None, only get files from this owner |
1529 @param access(dict, None): get file with given access (see [setFile]) | 1529 @param access(dict, None): get file with given access (see [set_file]) |
1530 @param projection(list[unicode], None): name of columns to retrieve | 1530 @param projection(list[unicode], None): name of columns to retrieve |
1531 None to retrieve all | 1531 None to retrieve all |
1532 @param unique(bool): if True will remove duplicates | 1532 @param unique(bool): if True will remove duplicates |
1533 @param perms_to_check(tuple[unicode],None): permission to check | 1533 @param perms_to_check(tuple[unicode],None): permission to check |
1534 must be a tuple of C.ACCESS_PERM_* or None | 1534 must be a tuple of C.ACCESS_PERM_* or None |
1535 if None, permission will no be checked (peer_jid must be None too in this | 1535 if None, permission will no be checked (peer_jid must be None too in this |
1536 case) | 1536 case) |
1537 other params are the same as for [setFile] | 1537 other params are the same as for [set_file] |
1538 @return (list[dict]): files corresponding to filters | 1538 @return (list[dict]): files corresponding to filters |
1539 @raise exceptions.NotFound: parent directory not found (when path is specified) | 1539 @raise exceptions.NotFound: parent directory not found (when path is specified) |
1540 @raise exceptions.PermissionError: peer_jid can't use perms_to_check for one of | 1540 @raise exceptions.PermissionError: peer_jid can't use perms_to_check for one of |
1541 the file | 1541 the file |
1542 on the path | 1542 on the path |
1544 if peer_jid is None and perms_to_check or perms_to_check is None and peer_jid: | 1544 if peer_jid is None and perms_to_check or perms_to_check is None and peer_jid: |
1545 raise exceptions.InternalError( | 1545 raise exceptions.InternalError( |
1546 "if you want to disable permission check, both peer_jid and " | 1546 "if you want to disable permission check, both peer_jid and " |
1547 "perms_to_check must be None" | 1547 "perms_to_check must be None" |
1548 ) | 1548 ) |
1549 owner = self.getFilesOwner(client, owner, peer_jid, file_id, parent) | 1549 owner = self.get_files_owner(client, owner, peer_jid, file_id, parent) |
1550 if path is not None: | 1550 if path is not None: |
1551 path = str(path) | 1551 path = str(path) |
1552 # permission are checked by _getParentDir | 1552 # permission are checked by _get_parent_dir |
1553 parent, remaining_path_elts = await self._getParentDir( | 1553 parent, remaining_path_elts = await self._get_parent_dir( |
1554 client, path, parent, namespace, owner, peer_jid, perms_to_check | 1554 client, path, parent, namespace, owner, peer_jid, perms_to_check |
1555 ) | 1555 ) |
1556 if remaining_path_elts: | 1556 if remaining_path_elts: |
1557 # if we have remaining path elements, | 1557 # if we have remaining path elements, |
1558 # the parent directory is not found | 1558 # the parent directory is not found |
1559 raise failure.Failure(exceptions.NotFound()) | 1559 raise failure.Failure(exceptions.NotFound()) |
1560 if parent and peer_jid: | 1560 if parent and peer_jid: |
1561 # if parent is given directly and permission check is requested, | 1561 # if parent is given directly and permission check is requested, |
1562 # we need to check all the parents | 1562 # we need to check all the parents |
1563 parent_data = await self.storage.getFiles(client, file_id=parent) | 1563 parent_data = await self.storage.get_files(client, file_id=parent) |
1564 try: | 1564 try: |
1565 parent_data = parent_data[0] | 1565 parent_data = parent_data[0] |
1566 except IndexError: | 1566 except IndexError: |
1567 raise exceptions.DataError("mising parent") | 1567 raise exceptions.DataError("mising parent") |
1568 await self.checkPermissionToRoot( | 1568 await self.check_permission_to_root( |
1569 client, parent_data, peer_jid, perms_to_check | 1569 client, parent_data, peer_jid, perms_to_check |
1570 ) | 1570 ) |
1571 | 1571 |
1572 files = await self.storage.getFiles( | 1572 files = await self.storage.get_files( |
1573 client, | 1573 client, |
1574 file_id=file_id, | 1574 file_id=file_id, |
1575 version=version, | 1575 version=version, |
1576 parent=parent, | 1576 parent=parent, |
1577 type_=type_, | 1577 type_=type_, |
1590 if peer_jid: | 1590 if peer_jid: |
1591 # if permission are checked, we must remove all file that user can't access | 1591 # if permission are checked, we must remove all file that user can't access |
1592 to_remove = [] | 1592 to_remove = [] |
1593 for file_data in files: | 1593 for file_data in files: |
1594 try: | 1594 try: |
1595 self.checkFilePermission( | 1595 self.check_file_permission( |
1596 file_data, peer_jid, perms_to_check, set_affiliation=True | 1596 file_data, peer_jid, perms_to_check, set_affiliation=True |
1597 ) | 1597 ) |
1598 except exceptions.PermissionError: | 1598 except exceptions.PermissionError: |
1599 to_remove.append(file_data) | 1599 to_remove.append(file_data) |
1600 for file_data in to_remove: | 1600 for file_data in to_remove: |
1601 files.remove(file_data) | 1601 files.remove(file_data) |
1602 return files | 1602 return files |
1603 | 1603 |
1604 async def setFile( | 1604 async def set_file( |
1605 self, client, name, file_id=None, version="", parent=None, path=None, | 1605 self, client, name, file_id=None, version="", parent=None, path=None, |
1606 type_=C.FILE_TYPE_FILE, file_hash=None, hash_algo=None, size=None, | 1606 type_=C.FILE_TYPE_FILE, file_hash=None, hash_algo=None, size=None, |
1607 namespace=None, mime_type=None, public_id=None, created=None, modified=None, | 1607 namespace=None, mime_type=None, public_id=None, created=None, modified=None, |
1608 owner=None, access=None, extra=None, peer_jid=None, | 1608 owner=None, access=None, extra=None, peer_jid=None, |
1609 perms_to_check=(C.ACCESS_PERM_WRITE,) | 1609 perms_to_check=(C.ACCESS_PERM_WRITE,) |
1676 if type_ == C.FILE_TYPE_DIRECTORY: | 1676 if type_ == C.FILE_TYPE_DIRECTORY: |
1677 if any((version, file_hash, size, mime_type)): | 1677 if any((version, file_hash, size, mime_type)): |
1678 raise ValueError( | 1678 raise ValueError( |
1679 "version, file_hash, size and mime_type can't be set for a directory" | 1679 "version, file_hash, size and mime_type can't be set for a directory" |
1680 ) | 1680 ) |
1681 owner = self.getFilesOwner(client, owner, peer_jid, file_id, parent) | 1681 owner = self.get_files_owner(client, owner, peer_jid, file_id, parent) |
1682 | 1682 |
1683 if path is not None: | 1683 if path is not None: |
1684 path = str(path) | 1684 path = str(path) |
1685 # _getParentDir will check permissions if peer_jid is set, so we use owner | 1685 # _get_parent_dir will check permissions if peer_jid is set, so we use owner |
1686 parent, remaining_path_elts = await self._getParentDir( | 1686 parent, remaining_path_elts = await self._get_parent_dir( |
1687 client, path, parent, namespace, owner, owner, perms_to_check | 1687 client, path, parent, namespace, owner, owner, perms_to_check |
1688 ) | 1688 ) |
1689 # if remaining directories don't exist, we have to create them | 1689 # if remaining directories don't exist, we have to create them |
1690 for new_dir in remaining_path_elts: | 1690 for new_dir in remaining_path_elts: |
1691 new_dir_id = shortuuid.uuid() | 1691 new_dir_id = shortuuid.uuid() |
1692 await self.storage.setFile( | 1692 await self.storage.set_file( |
1693 client, | 1693 client, |
1694 name=new_dir, | 1694 name=new_dir, |
1695 file_id=new_dir_id, | 1695 file_id=new_dir_id, |
1696 version="", | 1696 version="", |
1697 parent=parent, | 1697 parent=parent, |
1704 ) | 1704 ) |
1705 parent = new_dir_id | 1705 parent = new_dir_id |
1706 elif parent is None: | 1706 elif parent is None: |
1707 parent = "" | 1707 parent = "" |
1708 | 1708 |
1709 await self.storage.setFile( | 1709 await self.storage.set_file( |
1710 client, | 1710 client, |
1711 file_id=file_id, | 1711 file_id=file_id, |
1712 version=version, | 1712 version=version, |
1713 parent=parent, | 1713 parent=parent, |
1714 type_=type_, | 1714 type_=type_, |
1724 owner=owner, | 1724 owner=owner, |
1725 access=access, | 1725 access=access, |
1726 extra=extra, | 1726 extra=extra, |
1727 ) | 1727 ) |
1728 | 1728 |
1729 async def fileGetUsedSpace( | 1729 async def file_get_used_space( |
1730 self, | 1730 self, |
1731 client, | 1731 client, |
1732 peer_jid: jid.JID, | 1732 peer_jid: jid.JID, |
1733 owner: Optional[jid.JID] = None | 1733 owner: Optional[jid.JID] = None |
1734 ) -> int: | 1734 ) -> int: |
1735 """Get space taken by all files owned by an entity | 1735 """Get space taken by all files owned by an entity |
1736 | 1736 |
1737 @param peer_jid: entity requesting the size | 1737 @param peer_jid: entity requesting the size |
1738 @param owner: entity owning the file to check. If None, will be determined by | 1738 @param owner: entity owning the file to check. If None, will be determined by |
1739 getFilesOwner | 1739 get_files_owner |
1740 @return: size of total space used by files of this owner | 1740 @return: size of total space used by files of this owner |
1741 """ | 1741 """ |
1742 owner = self.getFilesOwner(client, owner, peer_jid) | 1742 owner = self.get_files_owner(client, owner, peer_jid) |
1743 if peer_jid.userhostJID() != owner and client.profile not in self.admins: | 1743 if peer_jid.userhostJID() != owner and client.profile not in self.admins: |
1744 raise exceptions.PermissionError("You are not allowed to check this size") | 1744 raise exceptions.PermissionError("You are not allowed to check this size") |
1745 return await self.storage.fileGetUsedSpace(client, owner) | 1745 return await self.storage.file_get_used_space(client, owner) |
1746 | 1746 |
1747 def fileUpdate(self, file_id, column, update_cb): | 1747 def file_update(self, file_id, column, update_cb): |
1748 """Update a file column taking care of race condition | 1748 """Update a file column taking care of race condition |
1749 | 1749 |
1750 access is NOT checked in this method, it must be checked beforehand | 1750 access is NOT checked in this method, it must be checked beforehand |
1751 @param file_id(unicode): id of the file to update | 1751 @param file_id(unicode): id of the file to update |
1752 @param column(unicode): one of "access" or "extra" | 1752 @param column(unicode): one of "access" or "extra" |
1753 @param update_cb(callable): method to update the value of the colum | 1753 @param update_cb(callable): method to update the value of the colum |
1754 the method will take older value as argument, and must update it in place | 1754 the method will take older value as argument, and must update it in place |
1755 Note that the callable must be thread-safe | 1755 Note that the callable must be thread-safe |
1756 """ | 1756 """ |
1757 return self.storage.fileUpdate(file_id, column, update_cb) | 1757 return self.storage.file_update(file_id, column, update_cb) |
1758 | 1758 |
1759 @defer.inlineCallbacks | 1759 @defer.inlineCallbacks |
1760 def _deleteFile( | 1760 def _delete_file( |
1761 self, | 1761 self, |
1762 client, | 1762 client, |
1763 peer_jid: jid.JID, | 1763 peer_jid: jid.JID, |
1764 recursive: bool, | 1764 recursive: bool, |
1765 files_path: Path, | 1765 files_path: Path, |
1776 if file_data['owner'] != peer_jid: | 1776 if file_data['owner'] != peer_jid: |
1777 raise exceptions.PermissionError( | 1777 raise exceptions.PermissionError( |
1778 "file {file_name} can't be deleted, {peer_jid} is not the owner" | 1778 "file {file_name} can't be deleted, {peer_jid} is not the owner" |
1779 .format(file_name=file_data['name'], peer_jid=peer_jid.full())) | 1779 .format(file_name=file_data['name'], peer_jid=peer_jid.full())) |
1780 if file_data['type'] == C.FILE_TYPE_DIRECTORY: | 1780 if file_data['type'] == C.FILE_TYPE_DIRECTORY: |
1781 sub_files = yield self.getFiles(client, peer_jid, parent=file_data['id']) | 1781 sub_files = yield self.get_files(client, peer_jid, parent=file_data['id']) |
1782 if sub_files and not recursive: | 1782 if sub_files and not recursive: |
1783 raise exceptions.DataError(_("Can't delete directory, it is not empty")) | 1783 raise exceptions.DataError(_("Can't delete directory, it is not empty")) |
1784 # we first delete the sub-files | 1784 # we first delete the sub-files |
1785 for sub_file_data in sub_files: | 1785 for sub_file_data in sub_files: |
1786 if sub_file_data['type'] == C.FILE_TYPE_DIRECTORY: | 1786 if sub_file_data['type'] == C.FILE_TYPE_DIRECTORY: |
1787 sub_file_path = files_path / sub_file_data['name'] | 1787 sub_file_path = files_path / sub_file_data['name'] |
1788 else: | 1788 else: |
1789 sub_file_path = files_path | 1789 sub_file_path = files_path |
1790 yield self._deleteFile( | 1790 yield self._delete_file( |
1791 client, peer_jid, recursive, sub_file_path, sub_file_data) | 1791 client, peer_jid, recursive, sub_file_path, sub_file_data) |
1792 # then the directory itself | 1792 # then the directory itself |
1793 yield self.storage.fileDelete(file_data['id']) | 1793 yield self.storage.file_delete(file_data['id']) |
1794 elif file_data['type'] == C.FILE_TYPE_FILE: | 1794 elif file_data['type'] == C.FILE_TYPE_FILE: |
1795 log.info(_("deleting file {name} with hash {file_hash}").format( | 1795 log.info(_("deleting file {name} with hash {file_hash}").format( |
1796 name=file_data['name'], file_hash=file_data['file_hash'])) | 1796 name=file_data['name'], file_hash=file_data['file_hash'])) |
1797 yield self.storage.fileDelete(file_data['id']) | 1797 yield self.storage.file_delete(file_data['id']) |
1798 references = yield self.getFiles( | 1798 references = yield self.get_files( |
1799 client, peer_jid, file_hash=file_data['file_hash']) | 1799 client, peer_jid, file_hash=file_data['file_hash']) |
1800 if references: | 1800 if references: |
1801 log.debug("there are still references to the file, we keep it") | 1801 log.debug("there are still references to the file, we keep it") |
1802 else: | 1802 else: |
1803 file_path = os.path.join(files_path, file_data['file_hash']) | 1803 file_path = os.path.join(files_path, file_data['file_hash']) |
1809 log.error(f"file at {file_path!r} doesn't exist but it was referenced in files database") | 1809 log.error(f"file at {file_path!r} doesn't exist but it was referenced in files database") |
1810 else: | 1810 else: |
1811 raise exceptions.InternalError('Unexpected file type: {file_type}' | 1811 raise exceptions.InternalError('Unexpected file type: {file_type}' |
1812 .format(file_type=file_data['type'])) | 1812 .format(file_type=file_data['type'])) |
1813 | 1813 |
1814 async def fileDelete(self, client, peer_jid, file_id, recursive=False): | 1814 async def file_delete(self, client, peer_jid, file_id, recursive=False): |
1815 """Delete a single file or a directory and all its sub-files | 1815 """Delete a single file or a directory and all its sub-files |
1816 | 1816 |
1817 @param file_id(unicode): id of the file to delete | 1817 @param file_id(unicode): id of the file to delete |
1818 @param peer_jid(jid.JID): entity requesting the deletion, | 1818 @param peer_jid(jid.JID): entity requesting the deletion, |
1819 must be owner of all files to delete | 1819 must be owner of all files to delete |
1820 @param recursive(boolean): must be True to delete a directory and all sub-files | 1820 @param recursive(boolean): must be True to delete a directory and all sub-files |
1821 """ | 1821 """ |
1822 # FIXME: we only allow owner of file to delete files for now, but WRITE access | 1822 # FIXME: we only allow owner of file to delete files for now, but WRITE access |
1823 # should be checked too | 1823 # should be checked too |
1824 files_data = await self.getFiles(client, peer_jid, file_id) | 1824 files_data = await self.get_files(client, peer_jid, file_id) |
1825 if not files_data: | 1825 if not files_data: |
1826 raise exceptions.NotFound("Can't find the file with id {file_id}".format( | 1826 raise exceptions.NotFound("Can't find the file with id {file_id}".format( |
1827 file_id=file_id)) | 1827 file_id=file_id)) |
1828 file_data = files_data[0] | 1828 file_data = files_data[0] |
1829 if file_data["type"] != C.FILE_TYPE_DIRECTORY and recursive: | 1829 if file_data["type"] != C.FILE_TYPE_DIRECTORY and recursive: |
1830 raise ValueError("recursive can only be set for directories") | 1830 raise ValueError("recursive can only be set for directories") |
1831 files_path = self.host.get_local_path(None, C.FILES_DIR) | 1831 files_path = self.host.get_local_path(None, C.FILES_DIR) |
1832 await self._deleteFile(client, peer_jid, recursive, files_path, file_data) | 1832 await self._delete_file(client, peer_jid, recursive, files_path, file_data) |
1833 | 1833 |
1834 ## Cache ## | 1834 ## Cache ## |
1835 | 1835 |
1836 def getCachePath(self, namespace: str, *args: str) -> Path: | 1836 def get_cache_path(self, namespace: str, *args: str) -> Path: |
1837 """Get path to use to get a common path for a namespace | 1837 """Get path to use to get a common path for a namespace |
1838 | 1838 |
1839 This can be used by plugins to manage permanent data. It's the responsability | 1839 This can be used by plugins to manage permanent data. It's the responsability |
1840 of plugins to clean this directory from unused data. | 1840 of plugins to clean this directory from unused data. |
1841 @param namespace: unique namespace to use | 1841 @param namespace: unique namespace to use |
1842 @param args: extra identifier which will be added to the path | 1842 @param args: extra identifier which will be added to the path |
1843 """ | 1843 """ |
1844 namespace = namespace.strip().lower() | 1844 namespace = namespace.strip().lower() |
1845 return Path( | 1845 return Path( |
1846 self._cache_path, | 1846 self._cache_path, |
1847 regex.pathEscape(namespace), | 1847 regex.path_escape(namespace), |
1848 *(regex.pathEscape(a) for a in args) | 1848 *(regex.path_escape(a) for a in args) |
1849 ) | 1849 ) |
1850 | 1850 |
1851 ## Misc ## | 1851 ## Misc ## |
1852 | 1852 |
1853 def isEntityAvailable(self, client, entity_jid): | 1853 def is_entity_available(self, client, entity_jid): |
1854 """Tell from the presence information if the given entity is available. | 1854 """Tell from the presence information if the given entity is available. |
1855 | 1855 |
1856 @param entity_jid (JID): the entity to check (if bare jid is used, all resources are tested) | 1856 @param entity_jid (JID): the entity to check (if bare jid is used, all resources are tested) |
1857 @return (bool): True if entity is available | 1857 @return (bool): True if entity is available |
1858 """ | 1858 """ |
1859 if not entity_jid.resource: | 1859 if not entity_jid.resource: |
1860 return bool( | 1860 return bool( |
1861 self.getAvailableResources(client, entity_jid) | 1861 self.get_available_resources(client, entity_jid) |
1862 ) # is any resource is available, entity is available | 1862 ) # is any resource is available, entity is available |
1863 try: | 1863 try: |
1864 presence_data = self.getEntityDatum(client, entity_jid, "presence") | 1864 presence_data = self.get_entity_datum(client, entity_jid, "presence") |
1865 except KeyError: | 1865 except KeyError: |
1866 log.debug("No presence information for {}".format(entity_jid)) | 1866 log.debug("No presence information for {}".format(entity_jid)) |
1867 return False | 1867 return False |
1868 return presence_data.show != C.PRESENCE_UNAVAILABLE | 1868 return presence_data.show != C.PRESENCE_UNAVAILABLE |
1869 | 1869 |
1870 def isAdmin(self, profile: str) -> bool: | 1870 def is_admin(self, profile: str) -> bool: |
1871 """Tell if given profile has administrator privileges""" | 1871 """Tell if given profile has administrator privileges""" |
1872 return profile in self.admins | 1872 return profile in self.admins |
1873 | 1873 |
1874 def isAdminJID(self, entity: jid.JID) -> bool: | 1874 def is_admin_jid(self, entity: jid.JID) -> bool: |
1875 """Tells if an entity jid correspond to an admin one | 1875 """Tells if an entity jid correspond to an admin one |
1876 | 1876 |
1877 It is sometime not possible to use the profile alone to check if an entity is an | 1877 It is sometime not possible to use the profile alone to check if an entity is an |
1878 admin (e.g. a request managed by a component). In this case we check if the JID | 1878 admin (e.g. a request managed by a component). In this case we check if the JID |
1879 correspond to an admin profile | 1879 correspond to an admin profile |