Mercurial > libervia-backend
comparison sat/memory/memory.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 9446f1ea9eac |
children | 5060cbeec01e |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _ | 20 from sat.core.i18n import _ |
21 | 21 |
22 from sat.core.log import getLogger | 22 from sat.core.log import getLogger |
23 | |
23 log = getLogger(__name__) | 24 log = getLogger(__name__) |
24 | 25 |
25 import os.path | 26 import os.path |
26 import copy | 27 import copy |
27 from collections import namedtuple | 28 from collections import namedtuple |
42 import shortuuid | 43 import shortuuid |
43 import mimetypes | 44 import mimetypes |
44 import time | 45 import time |
45 | 46 |
46 | 47 |
47 PresenceTuple = namedtuple("PresenceTuple", ('show', 'priority', 'statuses')) | 48 PresenceTuple = namedtuple("PresenceTuple", ("show", "priority", "statuses")) |
48 MSG_NO_SESSION = "Session id doesn't exist or is finished" | 49 MSG_NO_SESSION = "Session id doesn't exist or is finished" |
50 | |
49 | 51 |
50 class Sessions(object): | 52 class Sessions(object): |
51 """Sessions are data associated to key used for a temporary moment, with optional profile checking.""" | 53 """Sessions are data associated to key used for a temporary moment, with optional profile checking.""" |
54 | |
52 DEFAULT_TIMEOUT = 600 | 55 DEFAULT_TIMEOUT = 600 |
53 | 56 |
54 def __init__(self, timeout=None, resettable_timeout=True): | 57 def __init__(self, timeout=None, resettable_timeout=True): |
55 """ | 58 """ |
56 @param timeout (int): nb of seconds before session destruction | 59 @param timeout (int): nb of seconds before session destruction |
70 @return: session_id, session_data | 73 @return: session_id, session_data |
71 """ | 74 """ |
72 if session_id is None: | 75 if session_id is None: |
73 session_id = str(uuid4()) | 76 session_id = str(uuid4()) |
74 elif session_id in self._sessions: | 77 elif session_id in self._sessions: |
75 raise exceptions.ConflictError(u"Session id {} is already used".format(session_id)) | 78 raise exceptions.ConflictError( |
79 u"Session id {} is already used".format(session_id) | |
80 ) | |
76 timer = reactor.callLater(self.timeout, self._purgeSession, session_id) | 81 timer = reactor.callLater(self.timeout, self._purgeSession, session_id) |
77 if session_data is None: | 82 if session_data is None: |
78 session_data = {} | 83 session_data = {} |
79 self._sessions[session_id] = (timer, session_data) if profile is None else (timer, session_data, profile) | 84 self._sessions[session_id] = ( |
85 (timer, session_data) if profile is None else (timer, session_data, profile) | |
86 ) | |
80 return session_id, session_data | 87 return session_id, session_data |
81 | 88 |
82 def _purgeSession(self, session_id): | 89 def _purgeSession(self, session_id): |
83 try: | 90 try: |
84 timer, session_data, profile = self._sessions[session_id] | 91 timer, session_data, profile = self._sessions[session_id] |
89 timer.cancel() | 96 timer.cancel() |
90 except error.AlreadyCalled: | 97 except error.AlreadyCalled: |
91 # if the session is time-outed, the timer has been called | 98 # if the session is time-outed, the timer has been called |
92 pass | 99 pass |
93 del self._sessions[session_id] | 100 del self._sessions[session_id] |
94 log.debug(u"Session {} purged{}".format(session_id, u' (profile {})'.format(profile) if profile is not None else u'')) | 101 log.debug( |
102 u"Session {} purged{}".format( | |
103 session_id, | |
104 u" (profile {})".format(profile) if profile is not None else u"", | |
105 ) | |
106 ) | |
95 | 107 |
96 def __len__(self): | 108 def __len__(self): |
97 return len(self._sessions) | 109 return len(self._sessions) |
98 | 110 |
99 def __contains__(self, session_id): | 111 def __contains__(self, session_id): |
101 | 113 |
102 def profileGet(self, session_id, profile): | 114 def profileGet(self, session_id, profile): |
103 try: | 115 try: |
104 timer, session_data, profile_set = self._sessions[session_id] | 116 timer, session_data, profile_set = self._sessions[session_id] |
105 except ValueError: | 117 except ValueError: |
106 raise exceptions.InternalError("You need to use __getitem__ when profile is not set") | 118 raise exceptions.InternalError( |
119 "You need to use __getitem__ when profile is not set" | |
120 ) | |
107 except KeyError: | 121 except KeyError: |
108 raise failure.Failure(KeyError(MSG_NO_SESSION)) | 122 raise failure.Failure(KeyError(MSG_NO_SESSION)) |
109 if profile_set != profile: | 123 if profile_set != profile: |
110 raise exceptions.InternalError("current profile differ from set profile !") | 124 raise exceptions.InternalError("current profile differ from set profile !") |
111 if self.resettable_timeout: | 125 if self.resettable_timeout: |
114 | 128 |
115 def __getitem__(self, session_id): | 129 def __getitem__(self, session_id): |
116 try: | 130 try: |
117 timer, session_data = self._sessions[session_id] | 131 timer, session_data = self._sessions[session_id] |
118 except ValueError: | 132 except ValueError: |
119 raise exceptions.InternalError("You need to use profileGet instead of __getitem__ when profile is set") | 133 raise exceptions.InternalError( |
134 "You need to use profileGet instead of __getitem__ when profile is set" | |
135 ) | |
120 except KeyError: | 136 except KeyError: |
121 raise failure.Failure(KeyError(MSG_NO_SESSION)) | 137 raise failure.Failure(KeyError(MSG_NO_SESSION)) |
122 if self.resettable_timeout: | 138 if self.resettable_timeout: |
123 timer.reset(self.timeout) | 139 timer.reset(self.timeout) |
124 return session_data | 140 return session_data |
167 - None if no session is associated to the profile | 183 - None if no session is associated to the profile |
168 - raise an error if more than one session are found | 184 - raise an error if more than one session are found |
169 """ | 185 """ |
170 ids = self._profileGetAllIds(profile) | 186 ids = self._profileGetAllIds(profile) |
171 if len(ids) > 1: | 187 if len(ids) > 1: |
172 raise exceptions.InternalError('profileGetUnique has been used but more than one session has been found!') | 188 raise exceptions.InternalError( |
173 return self.profileGet(ids[0], profile) if len(ids) == 1 else None # XXX: timeout might be reset | 189 "profileGetUnique has been used but more than one session has been found!" |
190 ) | |
191 return ( | |
192 self.profileGet(ids[0], profile) if len(ids) == 1 else None | |
193 ) # XXX: timeout might be reset | |
174 | 194 |
175 def profileDelUnique(self, profile): | 195 def profileDelUnique(self, profile): |
176 """Delete the unique session that is associated to the given profile. | 196 """Delete the unique session that is associated to the given profile. |
177 | 197 |
178 @param profile: %(doc_profile)s | 198 @param profile: %(doc_profile)s |
179 @return: None, but raise an error if more than one session are found | 199 @return: None, but raise an error if more than one session are found |
180 """ | 200 """ |
181 ids = self._profileGetAllIds(profile) | 201 ids = self._profileGetAllIds(profile) |
182 if len(ids) > 1: | 202 if len(ids) > 1: |
183 raise exceptions.InternalError('profileDelUnique has been used but more than one session has been found!') | 203 raise exceptions.InternalError( |
204 "profileDelUnique has been used but more than one session has been found!" | |
205 ) | |
184 if len(ids) == 1: | 206 if len(ids) == 1: |
185 del self._sessions[ids[0]] | 207 del self._sessions[ids[0]] |
186 | 208 |
187 | 209 |
188 class PasswordSessions(ProfileSessions): | 210 class PasswordSessions(ProfileSessions): |
192 # profile password should be asked again in order to decrypt it. | 214 # profile password should be asked again in order to decrypt it. |
193 def __init__(self, timeout=None): | 215 def __init__(self, timeout=None): |
194 ProfileSessions.__init__(self, timeout, resettable_timeout=False) | 216 ProfileSessions.__init__(self, timeout, resettable_timeout=False) |
195 | 217 |
196 def _purgeSession(self, session_id): | 218 def _purgeSession(self, session_id): |
197 log.debug("FIXME: PasswordSessions should ask for the profile password after the session expired") | 219 log.debug( |
220 "FIXME: PasswordSessions should ask for the profile password after the session expired" | |
221 ) | |
198 | 222 |
199 | 223 |
200 # XXX: tmp update code, will be removed in the future | 224 # XXX: tmp update code, will be removed in the future |
201 # When you remove this, please add the default value for | 225 # When you remove this, please add the default value for |
202 # 'local_dir' in sat.core.constants.Const.DEFAULT_CONFIG | 226 # 'local_dir' in sat.core.constants.Const.DEFAULT_CONFIG |
209 try: | 233 try: |
210 user_config.read(C.CONFIG_FILES) | 234 user_config.read(C.CONFIG_FILES) |
211 except: | 235 except: |
212 pass # file is readable but its structure if wrong | 236 pass # file is readable but its structure if wrong |
213 try: | 237 try: |
214 current_value = user_config.get('DEFAULT', 'local_dir') | 238 current_value = user_config.get("DEFAULT", "local_dir") |
215 except (NoOptionError, NoSectionError): | 239 except (NoOptionError, NoSectionError): |
216 current_value = '' | 240 current_value = "" |
217 if current_value: | 241 if current_value: |
218 return # nothing to do | 242 return # nothing to do |
219 old_default = '~/.sat' | 243 old_default = "~/.sat" |
220 if os.path.isfile(os.path.expanduser(old_default) + '/' + C.SAVEFILE_DATABASE): | 244 if os.path.isfile(os.path.expanduser(old_default) + "/" + C.SAVEFILE_DATABASE): |
221 if not silent: | 245 if not silent: |
222 log.warning(_(u"A database has been found in the default local_dir for previous versions (< 0.5)")) | 246 log.warning( |
223 tools_config.fixConfigOption('', 'local_dir', old_default, silent) | 247 _( |
248 u"A database has been found in the default local_dir for previous versions (< 0.5)" | |
249 ) | |
250 ) | |
251 tools_config.fixConfigOption("", "local_dir", old_default, silent) | |
224 | 252 |
225 | 253 |
226 class Memory(object): | 254 class Memory(object): |
227 """This class manage all the persistent information""" | 255 """This class manage all the persistent information""" |
228 | 256 |
229 def __init__(self, host): | 257 def __init__(self, host): |
230 log.info(_("Memory manager init")) | 258 log.info(_("Memory manager init")) |
231 self.initialized = defer.Deferred() | 259 self.initialized = defer.Deferred() |
232 self.host = host | 260 self.host = host |
233 self._entities_cache = {} # XXX: keep presence/last resource/other data in cache | 261 self._entities_cache = {} # XXX: keep presence/last resource/other data in cache |
234 # /!\ an entity is not necessarily in roster | 262 # /!\ an entity is not necessarily in roster |
235 # main key is bare jid, value is a dict | 263 # main key is bare jid, value is a dict |
236 # where main key is resource, or None for bare jid | 264 # where main key is resource, or None for bare jid |
237 self._key_signals = set() # key which need a signal to frontends when updated | 265 self._key_signals = set() # key which need a signal to frontends when updated |
238 self.subscriptions = {} | 266 self.subscriptions = {} |
239 self.auth_sessions = PasswordSessions() # remember the authenticated profiles | 267 self.auth_sessions = PasswordSessions() # remember the authenticated profiles |
240 self.disco = Discovery(host) | 268 self.disco = Discovery(host) |
241 fixLocalDir(False) # XXX: tmp update code, will be removed in the future | 269 fixLocalDir(False) # XXX: tmp update code, will be removed in the future |
242 self.config = tools_config.parseMainConf() | 270 self.config = tools_config.parseMainConf() |
243 database_file = os.path.expanduser(os.path.join(self.getConfig('', 'local_dir'), C.SAVEFILE_DATABASE)) | 271 database_file = os.path.expanduser( |
272 os.path.join(self.getConfig("", "local_dir"), C.SAVEFILE_DATABASE) | |
273 ) | |
244 self.storage = SqliteStorage(database_file, host.version) | 274 self.storage = SqliteStorage(database_file, host.version) |
245 PersistentDict.storage = self.storage | 275 PersistentDict.storage = self.storage |
246 self.params = Params(host, self.storage) | 276 self.params = Params(host, self.storage) |
247 log.info(_("Loading default params template")) | 277 log.info(_("Loading default params template")) |
248 self.params.load_default_params() | 278 self.params.load_default_params() |
288 @param filename (str): output file | 318 @param filename (str): output file |
289 @return: bool: True in case of success | 319 @return: bool: True in case of success |
290 """ | 320 """ |
291 if not filename: | 321 if not filename: |
292 return False | 322 return False |
293 #TODO: need to encrypt files (at least passwords !) and set permissions | 323 # TODO: need to encrypt files (at least passwords !) and set permissions |
294 filename = os.path.expanduser(filename) | 324 filename = os.path.expanduser(filename) |
295 try: | 325 try: |
296 self.params.save_xml(filename) | 326 self.params.save_xml(filename) |
297 log.debug(_(u"Parameters saved to file: %s") % filename) | 327 log.debug(_(u"Parameters saved to file: %s") % filename) |
298 return True | 328 return True |
300 log.error(_(u"Can't save parameters to file: %s") % e) | 330 log.error(_(u"Can't save parameters to file: %s") % e) |
301 return False | 331 return False |
302 | 332 |
303 def load(self): | 333 def load(self): |
304 """Load parameters and all memory things from db""" | 334 """Load parameters and all memory things from db""" |
305 #parameters data | 335 # parameters data |
306 return self.params.loadGenParams() | 336 return self.params.loadGenParams() |
307 | 337 |
308 def loadIndividualParams(self, profile): | 338 def loadIndividualParams(self, profile): |
309 """Load individual parameters for a profile | 339 """Load individual parameters for a profile |
310 @param profile: %(doc_profile)s""" | 340 @param profile: %(doc_profile)s""" |
338 # if there is a value at this point in self._entities_cache, | 368 # if there is a value at this point in self._entities_cache, |
339 # it is the loadIndividualParams Deferred, the session is starting | 369 # it is the loadIndividualParams Deferred, the session is starting |
340 session_d = self._entities_cache[profile] | 370 session_d = self._entities_cache[profile] |
341 except KeyError: | 371 except KeyError: |
342 # else we do request the params | 372 # else we do request the params |
343 session_d = self._entities_cache[profile] = self.loadIndividualParams(profile) | 373 session_d = self._entities_cache[profile] = self.loadIndividualParams( |
374 profile | |
375 ) | |
344 session_d.addCallback(createSession) | 376 session_d.addCallback(createSession) |
345 finally: | 377 finally: |
346 return session_d | 378 return session_d |
347 | 379 |
348 auth_d = self.profileAuthenticate(password, profile) | 380 auth_d = self.profileAuthenticate(password, profile) |
394 # submitting a form with empty passwords is restricted to local frontends. | 426 # submitting a form with empty passwords is restricted to local frontends. |
395 return defer.succeed(None) | 427 return defer.succeed(None) |
396 | 428 |
397 def check_result(result): | 429 def check_result(result): |
398 if not result: | 430 if not result: |
399 log.warning(u'Authentication failure of profile {}'.format(profile)) | 431 log.warning(u"Authentication failure of profile {}".format(profile)) |
400 raise failure.Failure(exceptions.PasswordError(u"The provided profile password doesn't match.")) | 432 raise failure.Failure( |
401 if not session_data: # avoid to create two profile sessions when password if specified | 433 exceptions.PasswordError( |
434 u"The provided profile password doesn't match." | |
435 ) | |
436 ) | |
437 if ( | |
438 not session_data | |
439 ): # avoid to create two profile sessions when password if specified | |
402 return self.newAuthSession(password, profile) | 440 return self.newAuthSession(password, profile) |
403 | 441 |
404 d = self.asyncGetParamA(C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile) | 442 d = self.asyncGetParamA( |
443 C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile | |
444 ) | |
405 d.addCallback(lambda sat_cipher: PasswordHasher.verify(password, sat_cipher)) | 445 d.addCallback(lambda sat_cipher: PasswordHasher.verify(password, sat_cipher)) |
406 return d.addCallback(check_result) | 446 return d.addCallback(check_result) |
407 | 447 |
408 def newAuthSession(self, key, profile): | 448 def newAuthSession(self, key, profile): |
409 """Start a new session for the authenticated profile. | 449 """Start a new session for the authenticated profile. |
412 | 452 |
413 @param key: the key to decrypt the personal key | 453 @param key: the key to decrypt the personal key |
414 @param profile: %(doc_profile)s | 454 @param profile: %(doc_profile)s |
415 @return: a deferred None value | 455 @return: a deferred None value |
416 """ | 456 """ |
457 | |
417 def gotPersonalKey(personal_key): | 458 def gotPersonalKey(personal_key): |
418 """Create the session for this profile and store the personal key""" | 459 """Create the session for this profile and store the personal key""" |
419 self.auth_sessions.newSession({C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile) | 460 self.auth_sessions.newSession( |
420 log.debug(u'auth session created for profile %s' % profile) | 461 {C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile |
462 ) | |
463 log.debug(u"auth session created for profile %s" % profile) | |
421 | 464 |
422 d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() | 465 d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() |
423 d.addCallback(lambda data: BlockCipher.decrypt(key, data[C.MEMORY_CRYPTO_KEY])) | 466 d.addCallback(lambda data: BlockCipher.decrypt(key, data[C.MEMORY_CRYPTO_KEY])) |
424 return d.addCallback(gotPersonalKey) | 467 return d.addCallback(gotPersonalKey) |
425 | 468 |
429 log.info(_("[%s] Profile session purge" % profile)) | 472 log.info(_("[%s] Profile session purge" % profile)) |
430 self.params.purgeProfile(profile) | 473 self.params.purgeProfile(profile) |
431 try: | 474 try: |
432 del self._entities_cache[profile] | 475 del self._entities_cache[profile] |
433 except KeyError: | 476 except KeyError: |
434 log.error(_(u"Trying to purge roster status cache for a profile not in memory: [%s]") % profile) | 477 log.error( |
478 _( | |
479 u"Trying to purge roster status cache for a profile not in memory: [%s]" | |
480 ) | |
481 % profile | |
482 ) | |
435 | 483 |
436 def getProfilesList(self, clients=True, components=False): | 484 def getProfilesList(self, clients=True, components=False): |
437 """retrieve profiles list | 485 """retrieve profiles list |
438 | 486 |
439 @param clients(bool): if True return clients profiles | 487 @param clients(bool): if True return clients profiles |
470 @param profile: %(doc_profile)s | 518 @param profile: %(doc_profile)s |
471 """ | 519 """ |
472 # we want to be sure that the profile exists | 520 # we want to be sure that the profile exists |
473 profile = self.getProfileName(profile) | 521 profile = self.getProfileName(profile) |
474 | 522 |
475 self.memory_data['Profile_default'] = profile | 523 self.memory_data["Profile_default"] = profile |
476 | 524 |
477 def createProfile(self, name, password, component=None): | 525 def createProfile(self, name, password, component=None): |
478 """Create a new profile | 526 """Create a new profile |
479 | 527 |
480 @param name(unicode): profile name | 528 @param name(unicode): profile name |
484 @return: Deferred | 532 @return: Deferred |
485 @raise exceptions.NotFound: component is not a known plugin import name | 533 @raise exceptions.NotFound: component is not a known plugin import name |
486 """ | 534 """ |
487 if not name: | 535 if not name: |
488 raise ValueError(u"Empty profile name") | 536 raise ValueError(u"Empty profile name") |
489 if name[0] == '@': | 537 if name[0] == "@": |
490 raise ValueError(u"A profile name can't start with a '@'") | 538 raise ValueError(u"A profile name can't start with a '@'") |
491 if '\n' in name: | 539 if "\n" in name: |
492 raise ValueError(u"A profile name can't contain line feed ('\\n')") | 540 raise ValueError(u"A profile name can't contain line feed ('\\n')") |
493 | 541 |
494 if name in self._entities_cache: | 542 if name in self._entities_cache: |
495 raise exceptions.ConflictError(u"A session for this profile exists") | 543 raise exceptions.ConflictError(u"A session for this profile exists") |
496 | 544 |
497 if component: | 545 if component: |
498 if not component in self.host.plugins: | 546 if not component in self.host.plugins: |
499 raise exceptions.NotFound(_(u"Can't find component {component} entry point".format( | 547 raise exceptions.NotFound( |
500 component = component))) | 548 _( |
549 u"Can't find component {component} entry point".format( | |
550 component=component | |
551 ) | |
552 ) | |
553 ) | |
501 # FIXME: PLUGIN_INFO is not currently accessible after import, but type shoul be tested here | 554 # FIXME: PLUGIN_INFO is not currently accessible after import, but type shoul be tested here |
502 # if self.host.plugins[component].PLUGIN_INFO[u"type"] != C.PLUG_TYPE_ENTRY_POINT: | 555 # if self.host.plugins[component].PLUGIN_INFO[u"type"] != C.PLUG_TYPE_ENTRY_POINT: |
503 # raise ValueError(_(u"Plugin {component} is not an entry point !".format( | 556 # raise ValueError(_(u"Plugin {component} is not an entry point !".format( |
504 # component = component))) | 557 # component = component))) |
505 | 558 |
506 d = self.params.createProfile(name, component) | 559 d = self.params.createProfile(name, component) |
507 | 560 |
508 def initPersonalKey(dummy): | 561 def initPersonalKey(dummy): |
509 # be sure to call this after checking that the profile doesn't exist yet | 562 # be sure to call this after checking that the profile doesn't exist yet |
510 personal_key = BlockCipher.getRandomKey(base64=True) # generated once for all and saved in a PersistentDict | 563 personal_key = BlockCipher.getRandomKey( |
511 self.auth_sessions.newSession({C.MEMORY_CRYPTO_KEY: personal_key}, profile=name) # will be encrypted by setParam | 564 base64=True |
565 ) # generated once for all and saved in a PersistentDict | |
566 self.auth_sessions.newSession( | |
567 {C.MEMORY_CRYPTO_KEY: personal_key}, profile=name | |
568 ) # will be encrypted by setParam | |
512 | 569 |
513 def startFakeSession(dummy): | 570 def startFakeSession(dummy): |
514 # avoid ProfileNotConnected exception in setParam | 571 # avoid ProfileNotConnected exception in setParam |
515 self._entities_cache[name] = None | 572 self._entities_cache[name] = None |
516 self.params.loadIndParams(name) | 573 self.params.loadIndParams(name) |
519 del self._entities_cache[name] | 576 del self._entities_cache[name] |
520 self.params.purgeProfile(name) | 577 self.params.purgeProfile(name) |
521 | 578 |
522 d.addCallback(initPersonalKey) | 579 d.addCallback(initPersonalKey) |
523 d.addCallback(startFakeSession) | 580 d.addCallback(startFakeSession) |
524 d.addCallback(lambda dummy: self.setParam(C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=name)) | 581 d.addCallback( |
582 lambda dummy: self.setParam( | |
583 C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=name | |
584 ) | |
585 ) | |
525 d.addCallback(stopFakeSession) | 586 d.addCallback(stopFakeSession) |
526 d.addCallback(lambda dummy: self.auth_sessions.profileDelUnique(name)) | 587 d.addCallback(lambda dummy: self.auth_sessions.profileDelUnique(name)) |
527 return d | 588 return d |
528 | 589 |
529 def asyncDeleteProfile(self, name, force=False): | 590 def asyncDeleteProfile(self, name, force=False): |
532 @param name: Name of the profile | 593 @param name: Name of the profile |
533 @param force: force the deletion even if the profile is connected. | 594 @param force: force the deletion even if the profile is connected. |
534 To be used for direct calls only (not through the bridge). | 595 To be used for direct calls only (not through the bridge). |
535 @return: a Deferred instance | 596 @return: a Deferred instance |
536 """ | 597 """ |
598 | |
537 def cleanMemory(dummy): | 599 def cleanMemory(dummy): |
538 self.auth_sessions.profileDelUnique(name) | 600 self.auth_sessions.profileDelUnique(name) |
539 try: | 601 try: |
540 del self._entities_cache[name] | 602 del self._entities_cache[name] |
541 except KeyError: | 603 except KeyError: |
542 pass | 604 pass |
605 | |
543 d = self.params.asyncDeleteProfile(name, force) | 606 d = self.params.asyncDeleteProfile(name, force) |
544 d.addCallback(cleanMemory) | 607 d.addCallback(cleanMemory) |
545 return d | 608 return d |
546 | 609 |
547 def isComponent(self, profile_name): | 610 def isComponent(self, profile_name): |
565 ## History ## | 628 ## History ## |
566 | 629 |
567 def addToHistory(self, client, data): | 630 def addToHistory(self, client, data): |
568 return self.storage.addToHistory(data, client.profile) | 631 return self.storage.addToHistory(data, client.profile) |
569 | 632 |
570 def _historyGet(self, from_jid_s, to_jid_s, limit=C.HISTORY_LIMIT_NONE, between=True, filters=None, profile=C.PROF_KEY_NONE): | 633 def _historyGet( |
571 return self.historyGet(jid.JID(from_jid_s), jid.JID(to_jid_s), limit, between, filters, profile) | 634 self, |
572 | 635 from_jid_s, |
573 def historyGet(self, from_jid, to_jid, limit=C.HISTORY_LIMIT_NONE, between=True, filters=None, profile=C.PROF_KEY_NONE): | 636 to_jid_s, |
637 limit=C.HISTORY_LIMIT_NONE, | |
638 between=True, | |
639 filters=None, | |
640 profile=C.PROF_KEY_NONE, | |
641 ): | |
642 return self.historyGet( | |
643 jid.JID(from_jid_s), jid.JID(to_jid_s), limit, between, filters, profile | |
644 ) | |
645 | |
646 def historyGet( | |
647 self, | |
648 from_jid, | |
649 to_jid, | |
650 limit=C.HISTORY_LIMIT_NONE, | |
651 between=True, | |
652 filters=None, | |
653 profile=C.PROF_KEY_NONE, | |
654 ): | |
574 """Retrieve messages in history | 655 """Retrieve messages in history |
575 | 656 |
576 @param from_jid (JID): source JID (full, or bare for catchall) | 657 @param from_jid (JID): source JID (full, or bare for catchall) |
577 @param to_jid (JID): dest JID (full, or bare for catchall) | 658 @param to_jid (JID): dest JID (full, or bare for catchall) |
578 @param limit (int): maximum number of messages to get: | 659 @param limit (int): maximum number of messages to get: |
584 @param profile (str): %(doc_profile)s | 665 @param profile (str): %(doc_profile)s |
585 @return (D(list)): list of message data as in [messageNew] | 666 @return (D(list)): list of message data as in [messageNew] |
586 """ | 667 """ |
587 assert profile != C.PROF_KEY_NONE | 668 assert profile != C.PROF_KEY_NONE |
588 if limit == C.HISTORY_LIMIT_DEFAULT: | 669 if limit == C.HISTORY_LIMIT_DEFAULT: |
589 limit = int(self.getParamA(C.HISTORY_LIMIT, 'General', profile_key=profile)) | 670 limit = int(self.getParamA(C.HISTORY_LIMIT, "General", profile_key=profile)) |
590 elif limit == C.HISTORY_LIMIT_NONE: | 671 elif limit == C.HISTORY_LIMIT_NONE: |
591 limit = None | 672 limit = None |
592 if limit == 0: | 673 if limit == 0: |
593 return defer.succeed([]) | 674 return defer.succeed([]) |
594 return self.storage.historyGet(from_jid, to_jid, limit, between, filters, profile) | 675 return self.storage.historyGet(from_jid, to_jid, limit, between, filters, profile) |
595 | 676 |
596 ## Statuses ## | 677 ## Statuses ## |
597 | 678 |
598 def _getPresenceStatuses(self, profile_key): | 679 def _getPresenceStatuses(self, profile_key): |
599 ret = self.getPresenceStatuses(profile_key) | 680 ret = self.getPresenceStatuses(profile_key) |
600 return {entity.full():data for entity, data in ret.iteritems()} | 681 return {entity.full(): data for entity, data in ret.iteritems()} |
601 | 682 |
602 def getPresenceStatuses(self, profile_key): | 683 def getPresenceStatuses(self, profile_key): |
603 """Get all the presence statuses of a profile | 684 """Get all the presence statuses of a profile |
604 | 685 |
605 @param profile_key: %(doc_profile_key)s | 686 @param profile_key: %(doc_profile_key)s |
615 full_jid.resource = resource | 696 full_jid.resource = resource |
616 try: | 697 try: |
617 presence_data = self.getEntityDatum(full_jid, "presence", profile_key) | 698 presence_data = self.getEntityDatum(full_jid, "presence", profile_key) |
618 except KeyError: | 699 except KeyError: |
619 continue | 700 continue |
620 entities_presence.setdefault(entity_jid, {})[resource or ''] = presence_data | 701 entities_presence.setdefault(entity_jid, {})[ |
702 resource or "" | |
703 ] = presence_data | |
621 | 704 |
622 return entities_presence | 705 return entities_presence |
623 | 706 |
624 def setPresenceStatus(self, entity_jid, show, priority, statuses, profile_key): | 707 def setPresenceStatus(self, entity_jid, show, priority, statuses, profile_key): |
625 """Change the presence status of an entity | 708 """Change the presence status of an entity |
629 @param priority: priority | 712 @param priority: priority |
630 @param statuses: dictionary of statuses | 713 @param statuses: dictionary of statuses |
631 @param profile_key: %(doc_profile_key)s | 714 @param profile_key: %(doc_profile_key)s |
632 """ | 715 """ |
633 presence_data = PresenceTuple(show, priority, statuses) | 716 presence_data = PresenceTuple(show, priority, statuses) |
634 self.updateEntityData(entity_jid, "presence", presence_data, profile_key=profile_key) | 717 self.updateEntityData( |
718 entity_jid, "presence", presence_data, profile_key=profile_key | |
719 ) | |
635 if entity_jid.resource and show != C.PRESENCE_UNAVAILABLE: | 720 if entity_jid.resource and show != C.PRESENCE_UNAVAILABLE: |
636 # If a resource is available, bare jid should not have presence information | 721 # If a resource is available, bare jid should not have presence information |
637 try: | 722 try: |
638 self.delEntityDatum(entity_jid.userhostJID(), "presence", profile_key) | 723 self.delEntityDatum(entity_jid.userhostJID(), "presence", profile_key) |
639 except (KeyError, exceptions.UnknownEntityError): | 724 except (KeyError, exceptions.UnknownEntityError): |
655 @raise exceptions.UnknownEntityError: if entity is not in cache | 740 @raise exceptions.UnknownEntityError: if entity is not in cache |
656 @raise ValueError: entity_jid has a resource | 741 @raise ValueError: entity_jid has a resource |
657 """ | 742 """ |
658 # FIXME: is there a need to keep cache data for resources which are not connected anymore? | 743 # FIXME: is there a need to keep cache data for resources which are not connected anymore? |
659 if entity_jid.resource: | 744 if entity_jid.resource: |
660 raise ValueError("getAllResources must be used with a bare jid (got {})".format(entity_jid)) | 745 raise ValueError( |
746 "getAllResources must be used with a bare jid (got {})".format(entity_jid) | |
747 ) | |
661 profile_cache = self._getProfileCache(client) | 748 profile_cache = self._getProfileCache(client) |
662 try: | 749 try: |
663 entity_data = profile_cache[entity_jid.userhostJID()] | 750 entity_data = profile_cache[entity_jid.userhostJID()] |
664 except KeyError: | 751 except KeyError: |
665 raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(entity_jid)) | 752 raise exceptions.UnknownEntityError( |
666 resources= set(entity_data.keys()) | 753 u"Entity {} not in cache".format(entity_jid) |
754 ) | |
755 resources = set(entity_data.keys()) | |
667 resources.discard(None) | 756 resources.discard(None) |
668 return resources | 757 return resources |
669 | 758 |
670 def getAvailableResources(self, client, entity_jid): | 759 def getAvailableResources(self, client, entity_jid): |
671 """Return available resource for entity_jid | 760 """Return available resource for entity_jid |
699 | 788 |
700 @param entity_jid: bare entity jid | 789 @param entity_jid: bare entity jid |
701 @return (unicode): main resource or None | 790 @return (unicode): main resource or None |
702 """ | 791 """ |
703 if entity_jid.resource: | 792 if entity_jid.resource: |
704 raise ValueError("getMainResource must be used with a bare jid (got {})".format(entity_jid)) | 793 raise ValueError( |
794 "getMainResource must be used with a bare jid (got {})".format(entity_jid) | |
795 ) | |
705 try: | 796 try: |
706 if self.host.plugins["XEP-0045"].isJoinedRoom(client, entity_jid): | 797 if self.host.plugins["XEP-0045"].isJoinedRoom(client, entity_jid): |
707 return None # MUC rooms have no main resource | 798 return None # MUC rooms have no main resource |
708 except KeyError: # plugin not found | 799 except KeyError: # plugin not found |
709 pass | 800 pass |
764 continue | 855 continue |
765 full_jid = copy.copy(bare_jid) | 856 full_jid = copy.copy(bare_jid) |
766 full_jid.resource = resource | 857 full_jid.resource = resource |
767 yield full_jid | 858 yield full_jid |
768 | 859 |
769 def updateEntityData(self, entity_jid, key, value, silent=False, profile_key=C.PROF_KEY_NONE): | 860 def updateEntityData( |
861 self, entity_jid, key, value, silent=False, profile_key=C.PROF_KEY_NONE | |
862 ): | |
770 """Set a misc data for an entity | 863 """Set a misc data for an entity |
771 | 864 |
772 If key was registered with setSignalOnUpdate, a signal will be sent to frontends | 865 If key was registered with setSignalOnUpdate, a signal will be sent to frontends |
773 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of all entities, | 866 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of all entities, |
774 C.ENTITY_ALL for all entities (all resources + bare jids) | 867 C.ENTITY_ALL for all entities (all resources + bare jids) |
778 @param profile_key: %(doc_profile_key)s | 871 @param profile_key: %(doc_profile_key)s |
779 """ | 872 """ |
780 client = self.host.getClient(profile_key) | 873 client = self.host.getClient(profile_key) |
781 profile_cache = self._getProfileCache(client) | 874 profile_cache = self._getProfileCache(client) |
782 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): | 875 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): |
783 entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL) | 876 entities = self.getAllEntitiesIter(client, entity_jid == C.ENTITY_ALL) |
784 else: | 877 else: |
785 entities = (entity_jid,) | 878 entities = (entity_jid,) |
786 | 879 |
787 for jid_ in entities: | 880 for jid_ in entities: |
788 entity_data = profile_cache.setdefault(jid_.userhostJID(),{}).setdefault(jid_.resource, {}) | 881 entity_data = profile_cache.setdefault(jid_.userhostJID(), {}).setdefault( |
882 jid_.resource, {} | |
883 ) | |
789 | 884 |
790 entity_data[key] = value | 885 entity_data[key] = value |
791 if key in self._key_signals and not silent: | 886 if key in self._key_signals and not silent: |
792 if not isinstance(value, basestring): | 887 if not isinstance(value, basestring): |
793 log.error(u"Setting a non string value ({}) for a key ({}) which has a signal flag".format(value, key)) | 888 log.error( |
889 u"Setting a non string value ({}) for a key ({}) which has a signal flag".format( | |
890 value, key | |
891 ) | |
892 ) | |
794 else: | 893 else: |
795 self.host.bridge.entityDataUpdated(jid_.full(), key, value, self.getProfileName(profile_key)) | 894 self.host.bridge.entityDataUpdated( |
895 jid_.full(), key, value, self.getProfileName(profile_key) | |
896 ) | |
796 | 897 |
797 def delEntityDatum(self, entity_jid, key, profile_key): | 898 def delEntityDatum(self, entity_jid, key, profile_key): |
798 """Delete a data for an entity | 899 """Delete a data for an entity |
799 | 900 |
800 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of all entities, | 901 @param entity_jid: JID of the entity, C.ENTITY_ALL_RESOURCES for all resources of all entities, |
806 @raise KeyError: key is not in cache | 907 @raise KeyError: key is not in cache |
807 """ | 908 """ |
808 client = self.host.getClient(profile_key) | 909 client = self.host.getClient(profile_key) |
809 profile_cache = self._getProfileCache(client) | 910 profile_cache = self._getProfileCache(client) |
810 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): | 911 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): |
811 entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL) | 912 entities = self.getAllEntitiesIter(client, entity_jid == C.ENTITY_ALL) |
812 else: | 913 else: |
813 entities = (entity_jid,) | 914 entities = (entity_jid,) |
814 | 915 |
815 for jid_ in entities: | 916 for jid_ in entities: |
816 try: | 917 try: |
817 entity_data = profile_cache[jid_.userhostJID()][jid_.resource] | 918 entity_data = profile_cache[jid_.userhostJID()][jid_.resource] |
818 except KeyError: | 919 except KeyError: |
819 raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(jid_)) | 920 raise exceptions.UnknownEntityError( |
921 u"Entity {} not in cache".format(jid_) | |
922 ) | |
820 try: | 923 try: |
821 del entity_data[key] | 924 del entity_data[key] |
822 except KeyError as e: | 925 except KeyError as e: |
823 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): | 926 if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): |
824 continue # we ignore KeyError when deleting keys from several entities | 927 continue # we ignore KeyError when deleting keys from several entities |
825 else: | 928 else: |
826 raise e | 929 raise e |
827 | 930 |
828 def _getEntitiesData(self, entities_jids, keys_list, profile_key): | 931 def _getEntitiesData(self, entities_jids, keys_list, profile_key): |
829 ret = self.getEntitiesData([jid.JID(jid_) for jid_ in entities_jids], keys_list, profile_key) | 932 ret = self.getEntitiesData( |
933 [jid.JID(jid_) for jid_ in entities_jids], keys_list, profile_key | |
934 ) | |
830 return {jid_.full(): data for jid_, data in ret.iteritems()} | 935 return {jid_.full(): data for jid_, data in ret.iteritems()} |
831 | 936 |
832 def getEntitiesData(self, entities_jids, keys_list=None, profile_key=C.PROF_KEY_NONE): | 937 def getEntitiesData(self, entities_jids, keys_list=None, profile_key=C.PROF_KEY_NONE): |
833 """Get a list of cached values for several entities at once | 938 """Get a list of cached values for several entities at once |
834 | 939 |
841 if an entity doesn't exist in cache, it will not appear | 946 if an entity doesn't exist in cache, it will not appear |
842 in resulting dict | 947 in resulting dict |
843 | 948 |
844 @raise exceptions.UnknownEntityError: if entity is not in cache | 949 @raise exceptions.UnknownEntityError: if entity is not in cache |
845 """ | 950 """ |
951 | |
846 def fillEntityData(entity_cache_data): | 952 def fillEntityData(entity_cache_data): |
847 entity_data = {} | 953 entity_data = {} |
848 if keys_list is None: | 954 if keys_list is None: |
849 entity_data = entity_cache_data | 955 entity_data = entity_cache_data |
850 else: | 956 else: |
859 profile_cache = self._getProfileCache(client) | 965 profile_cache = self._getProfileCache(client) |
860 ret_data = {} | 966 ret_data = {} |
861 if entities_jids: | 967 if entities_jids: |
862 for entity in entities_jids: | 968 for entity in entities_jids: |
863 try: | 969 try: |
864 entity_cache_data = profile_cache[entity.userhostJID()][entity.resource] | 970 entity_cache_data = profile_cache[entity.userhostJID()][ |
971 entity.resource | |
972 ] | |
865 except KeyError: | 973 except KeyError: |
866 continue | 974 continue |
867 ret_data[entity.full()] = fillEntityData(entity_cache_data, keys_list) | 975 ret_data[entity.full()] = fillEntityData(entity_cache_data, keys_list) |
868 else: | 976 else: |
869 for bare_jid, data in profile_cache.iteritems(): | 977 for bare_jid, data in profile_cache.iteritems(): |
889 client = self.host.getClient(profile_key) | 997 client = self.host.getClient(profile_key) |
890 profile_cache = self._getProfileCache(client) | 998 profile_cache = self._getProfileCache(client) |
891 try: | 999 try: |
892 entity_data = profile_cache[entity_jid.userhostJID()][entity_jid.resource] | 1000 entity_data = profile_cache[entity_jid.userhostJID()][entity_jid.resource] |
893 except KeyError: | 1001 except KeyError: |
894 raise exceptions.UnknownEntityError(u"Entity {} not in cache (was requesting {})".format(entity_jid, keys_list)) | 1002 raise exceptions.UnknownEntityError( |
1003 u"Entity {} not in cache (was requesting {})".format( | |
1004 entity_jid, keys_list | |
1005 ) | |
1006 ) | |
895 if keys_list is None: | 1007 if keys_list is None: |
896 return entity_data | 1008 return entity_data |
897 | 1009 |
898 return {key: entity_data[key] for key in keys_list if key in entity_data} | 1010 return {key: entity_data[key] for key in keys_list if key in entity_data} |
899 | 1011 |
908 @raise exceptions.UnknownEntityError: if entity is not in cache | 1020 @raise exceptions.UnknownEntityError: if entity is not in cache |
909 @raise KeyError: if there is no value for this key and this entity | 1021 @raise KeyError: if there is no value for this key and this entity |
910 """ | 1022 """ |
911 return self.getEntityData(entity_jid, (key,), profile_key)[key] | 1023 return self.getEntityData(entity_jid, (key,), profile_key)[key] |
912 | 1024 |
913 def delEntityCache(self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE): | 1025 def delEntityCache( |
1026 self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE | |
1027 ): | |
914 """Remove all cached data for entity | 1028 """Remove all cached data for entity |
915 | 1029 |
916 @param entity_jid: JID of the entity to delete | 1030 @param entity_jid: JID of the entity to delete |
917 @param delete_all_resources: if True also delete all known resources from cache (a bare jid must be given in this case) | 1031 @param delete_all_resources: if True also delete all known resources from cache (a bare jid must be given in this case) |
918 @param profile_key: %(doc_profile_key)s | 1032 @param profile_key: %(doc_profile_key)s |
926 if entity_jid.resource: | 1040 if entity_jid.resource: |
927 raise ValueError(_("Need a bare jid to delete all resources")) | 1041 raise ValueError(_("Need a bare jid to delete all resources")) |
928 try: | 1042 try: |
929 del profile_cache[entity_jid] | 1043 del profile_cache[entity_jid] |
930 except KeyError: | 1044 except KeyError: |
931 raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(entity_jid)) | 1045 raise exceptions.UnknownEntityError( |
1046 u"Entity {} not in cache".format(entity_jid) | |
1047 ) | |
932 else: | 1048 else: |
933 try: | 1049 try: |
934 del profile_cache[entity_jid.userhostJID()][entity_jid.resource] | 1050 del profile_cache[entity_jid.userhostJID()][entity_jid.resource] |
935 except KeyError: | 1051 except KeyError: |
936 raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(entity_jid)) | 1052 raise exceptions.UnknownEntityError( |
1053 u"Entity {} not in cache".format(entity_jid) | |
1054 ) | |
937 | 1055 |
938 ## Encryption ## | 1056 ## Encryption ## |
939 | 1057 |
940 def encryptValue(self, value, profile): | 1058 def encryptValue(self, value, profile): |
941 """Encrypt a value for the given profile. The personal key must be loaded | 1059 """Encrypt a value for the given profile. The personal key must be loaded |
945 @param value (str): the value to encrypt | 1063 @param value (str): the value to encrypt |
946 @param profile (str): %(doc_profile)s | 1064 @param profile (str): %(doc_profile)s |
947 @return: the deferred encrypted value | 1065 @return: the deferred encrypted value |
948 """ | 1066 """ |
949 try: | 1067 try: |
950 personal_key = self.auth_sessions.profileGetUnique(profile)[C.MEMORY_CRYPTO_KEY] | 1068 personal_key = self.auth_sessions.profileGetUnique(profile)[ |
1069 C.MEMORY_CRYPTO_KEY | |
1070 ] | |
951 except TypeError: | 1071 except TypeError: |
952 raise exceptions.InternalError(_('Trying to encrypt a value for %s while the personal key is undefined!') % profile) | 1072 raise exceptions.InternalError( |
1073 _("Trying to encrypt a value for %s while the personal key is undefined!") | |
1074 % profile | |
1075 ) | |
953 return BlockCipher.encrypt(personal_key, value) | 1076 return BlockCipher.encrypt(personal_key, value) |
954 | 1077 |
955 def decryptValue(self, value, profile): | 1078 def decryptValue(self, value, profile): |
956 """Decrypt a value for the given profile. The personal key must be loaded | 1079 """Decrypt a value for the given profile. The personal key must be loaded |
957 already in the profile session, that should be the case if the profile is | 1080 already in the profile session, that should be the case if the profile is |
960 @param value (str): the value to decrypt | 1083 @param value (str): the value to decrypt |
961 @param profile (str): %(doc_profile)s | 1084 @param profile (str): %(doc_profile)s |
962 @return: the deferred decrypted value | 1085 @return: the deferred decrypted value |
963 """ | 1086 """ |
964 try: | 1087 try: |
965 personal_key = self.auth_sessions.profileGetUnique(profile)[C.MEMORY_CRYPTO_KEY] | 1088 personal_key = self.auth_sessions.profileGetUnique(profile)[ |
1089 C.MEMORY_CRYPTO_KEY | |
1090 ] | |
966 except TypeError: | 1091 except TypeError: |
967 raise exceptions.InternalError(_('Trying to decrypt a value for %s while the personal key is undefined!') % profile) | 1092 raise exceptions.InternalError( |
1093 _("Trying to decrypt a value for %s while the personal key is undefined!") | |
1094 % profile | |
1095 ) | |
968 return BlockCipher.decrypt(personal_key, value) | 1096 return BlockCipher.decrypt(personal_key, value) |
969 | 1097 |
970 def encryptPersonalData(self, data_key, data_value, crypto_key, profile): | 1098 def encryptPersonalData(self, data_key, data_value, crypto_key, profile): |
971 """Re-encrypt a personal data (saved to a PersistentDict). | 1099 """Re-encrypt a personal data (saved to a PersistentDict). |
972 | 1100 |
985 return data.force(data_key) | 1113 return data.force(data_key) |
986 | 1114 |
987 return d.addCallback(cb) | 1115 return d.addCallback(cb) |
988 | 1116 |
989 def done(dummy): | 1117 def done(dummy): |
990 log.debug(_(u'Personal data (%(ns)s, %(key)s) has been successfuly encrypted') % | 1118 log.debug( |
991 {'ns': C.MEMORY_CRYPTO_NAMESPACE, 'key': data_key}) | 1119 _(u"Personal data (%(ns)s, %(key)s) has been successfuly encrypted") |
1120 % {"ns": C.MEMORY_CRYPTO_NAMESPACE, "key": data_key} | |
1121 ) | |
992 | 1122 |
993 d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() | 1123 d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() |
994 return d.addCallback(gotIndMemory).addCallback(done) | 1124 return d.addCallback(gotIndMemory).addCallback(done) |
995 | 1125 |
996 ## Subscription requests ## | 1126 ## Subscription requests ## |
1012 | 1142 |
1013 def getWaitingSub(self, profile_key): | 1143 def getWaitingSub(self, profile_key): |
1014 """Called to get a list of currently waiting subscription requests""" | 1144 """Called to get a list of currently waiting subscription requests""" |
1015 profile = self.getProfileName(profile_key) | 1145 profile = self.getProfileName(profile_key) |
1016 if not profile: | 1146 if not profile: |
1017 log.error(_('Asking waiting subscriptions for a non-existant profile')) | 1147 log.error(_("Asking waiting subscriptions for a non-existant profile")) |
1018 return {} | 1148 return {} |
1019 if profile not in self.subscriptions: | 1149 if profile not in self.subscriptions: |
1020 return {} | 1150 return {} |
1021 | 1151 |
1022 return self.subscriptions[profile] | 1152 return self.subscriptions[profile] |
1027 return self.params.getStringParamA(name, category, attr, profile_key) | 1157 return self.params.getStringParamA(name, category, attr, profile_key) |
1028 | 1158 |
1029 def getParamA(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): | 1159 def getParamA(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): |
1030 return self.params.getParamA(name, category, attr, profile_key=profile_key) | 1160 return self.params.getParamA(name, category, attr, profile_key=profile_key) |
1031 | 1161 |
1032 def asyncGetParamA(self, name, category, attr="value", security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): | 1162 def asyncGetParamA( |
1033 return self.params.asyncGetParamA(name, category, attr, security_limit, profile_key) | 1163 self, |
1034 | 1164 name, |
1035 def asyncGetParamsValuesFromCategory(self, category, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): | 1165 category, |
1036 return self.params.asyncGetParamsValuesFromCategory(category, security_limit, profile_key) | 1166 attr="value", |
1037 | 1167 security_limit=C.NO_SECURITY_LIMIT, |
1038 def asyncGetStringParamA(self, name, category, attr="value", security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): | 1168 profile_key=C.PROF_KEY_NONE, |
1039 return self.params.asyncGetStringParamA(name, category, attr, security_limit, profile_key) | 1169 ): |
1040 | 1170 return self.params.asyncGetParamA( |
1041 def getParamsUI(self, security_limit=C.NO_SECURITY_LIMIT, app='', profile_key=C.PROF_KEY_NONE): | 1171 name, category, attr, security_limit, profile_key |
1172 ) | |
1173 | |
1174 def asyncGetParamsValuesFromCategory( | |
1175 self, category, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE | |
1176 ): | |
1177 return self.params.asyncGetParamsValuesFromCategory( | |
1178 category, security_limit, profile_key | |
1179 ) | |
1180 | |
1181 def asyncGetStringParamA( | |
1182 self, | |
1183 name, | |
1184 category, | |
1185 attr="value", | |
1186 security_limit=C.NO_SECURITY_LIMIT, | |
1187 profile_key=C.PROF_KEY_NONE, | |
1188 ): | |
1189 return self.params.asyncGetStringParamA( | |
1190 name, category, attr, security_limit, profile_key | |
1191 ) | |
1192 | |
1193 def getParamsUI( | |
1194 self, security_limit=C.NO_SECURITY_LIMIT, app="", profile_key=C.PROF_KEY_NONE | |
1195 ): | |
1042 return self.params.getParamsUI(security_limit, app, profile_key) | 1196 return self.params.getParamsUI(security_limit, app, profile_key) |
1043 | 1197 |
1044 def getParamsCategories(self): | 1198 def getParamsCategories(self): |
1045 return self.params.getParamsCategories() | 1199 return self.params.getParamsCategories() |
1046 | 1200 |
1047 def setParam(self, name, value, category, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): | 1201 def setParam( |
1202 self, | |
1203 name, | |
1204 value, | |
1205 category, | |
1206 security_limit=C.NO_SECURITY_LIMIT, | |
1207 profile_key=C.PROF_KEY_NONE, | |
1208 ): | |
1048 return self.params.setParam(name, value, category, security_limit, profile_key) | 1209 return self.params.setParam(name, value, category, security_limit, profile_key) |
1049 | 1210 |
1050 def updateParams(self, xml): | 1211 def updateParams(self, xml): |
1051 return self.params.updateParams(xml) | 1212 return self.params.updateParams(xml) |
1052 | 1213 |
1053 def paramsRegisterApp(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=''): | 1214 def paramsRegisterApp(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=""): |
1054 return self.params.paramsRegisterApp(xml, security_limit, app) | 1215 return self.params.paramsRegisterApp(xml, security_limit, app) |
1055 | 1216 |
1056 def setDefault(self, name, category, callback, errback=None): | 1217 def setDefault(self, name, category, callback, errback=None): |
1057 return self.params.setDefault(name, category, callback, errback) | 1218 return self.params.setDefault(name, category, callback, errback) |
1058 | 1219 |
1071 @raise exceptions.InternalError: perms_to_check is invalid | 1232 @raise exceptions.InternalError: perms_to_check is invalid |
1072 """ | 1233 """ |
1073 if peer_jid is None and perms_to_check is None: | 1234 if peer_jid is None and perms_to_check is None: |
1074 return | 1235 return |
1075 peer_jid = peer_jid.userhostJID() | 1236 peer_jid = peer_jid.userhostJID() |
1076 if peer_jid == file_data['owner']: | 1237 if peer_jid == file_data["owner"]: |
1077 # the owner has all rights | 1238 # the owner has all rights |
1078 return | 1239 return |
1079 if not C.ACCESS_PERMS.issuperset(perms_to_check): | 1240 if not C.ACCESS_PERMS.issuperset(perms_to_check): |
1080 raise exceptions.InternalError(_(u'invalid permission')) | 1241 raise exceptions.InternalError(_(u"invalid permission")) |
1081 | 1242 |
1082 for perm in perms_to_check: | 1243 for perm in perms_to_check: |
1083 # we check each perm and raise PermissionError as soon as one condition is not valid | 1244 # we check each perm and raise PermissionError as soon as one condition is not valid |
1084 # we must never return here, we only return after the loop if nothing was blocking the access | 1245 # we must never return here, we only return after the loop if nothing was blocking the access |
1085 try: | 1246 try: |
1086 perm_data = file_data[u'access'][perm] | 1247 perm_data = file_data[u"access"][perm] |
1087 perm_type = perm_data[u'type'] | 1248 perm_type = perm_data[u"type"] |
1088 except KeyError: | 1249 except KeyError: |
1089 raise failure.Failure(exceptions.PermissionError()) | 1250 raise failure.Failure(exceptions.PermissionError()) |
1090 if perm_type == C.ACCESS_TYPE_PUBLIC: | 1251 if perm_type == C.ACCESS_TYPE_PUBLIC: |
1091 continue | 1252 continue |
1092 elif perm_type == C.ACCESS_TYPE_WHITELIST: | 1253 elif perm_type == C.ACCESS_TYPE_WHITELIST: |
1093 try: | 1254 try: |
1094 jids = perm_data[u'jids'] | 1255 jids = perm_data[u"jids"] |
1095 except KeyError: | 1256 except KeyError: |
1096 raise failure.Failure(exceptions.PermissionError()) | 1257 raise failure.Failure(exceptions.PermissionError()) |
1097 if peer_jid.full() in jids: | 1258 if peer_jid.full() in jids: |
1098 continue | 1259 continue |
1099 else: | 1260 else: |
1100 raise failure.Failure(exceptions.PermissionError()) | 1261 raise failure.Failure(exceptions.PermissionError()) |
1101 else: | 1262 else: |
1102 raise exceptions.InternalError(_(u'unknown access type: {type}').format(type=perm_type)) | 1263 raise exceptions.InternalError( |
1264 _(u"unknown access type: {type}").format(type=perm_type) | |
1265 ) | |
1103 | 1266 |
1104 @defer.inlineCallbacks | 1267 @defer.inlineCallbacks |
1105 def checkPermissionToRoot(self, client, file_data, peer_jid, perms_to_check): | 1268 def checkPermissionToRoot(self, client, file_data, peer_jid, perms_to_check): |
1106 """do checkFilePermission on file_data and all its parents until root""" | 1269 """do checkFilePermission on file_data and all its parents until root""" |
1107 current = file_data | 1270 current = file_data |
1108 while True: | 1271 while True: |
1109 self.checkFilePermission(current, peer_jid, perms_to_check) | 1272 self.checkFilePermission(current, peer_jid, perms_to_check) |
1110 parent = current[u'parent'] | 1273 parent = current[u"parent"] |
1111 if not parent: | 1274 if not parent: |
1112 break | 1275 break |
1113 files_data = yield self.getFile(self, client, peer_jid=None, file_id=parent, perms_to_check=None) | 1276 files_data = yield self.getFile( |
1277 self, client, peer_jid=None, file_id=parent, perms_to_check=None | |
1278 ) | |
1114 try: | 1279 try: |
1115 current = files_data[0] | 1280 current = files_data[0] |
1116 except IndexError: | 1281 except IndexError: |
1117 raise exceptions.DataError(u'Missing parent') | 1282 raise exceptions.DataError(u"Missing parent") |
1118 | 1283 |
1119 @defer.inlineCallbacks | 1284 @defer.inlineCallbacks |
1120 def _getParentDir(self, client, path, parent, namespace, owner, peer_jid, perms_to_check): | 1285 def _getParentDir( |
1286 self, client, path, parent, namespace, owner, peer_jid, perms_to_check | |
1287 ): | |
1121 """Retrieve parent node from a path, or last existing directory | 1288 """Retrieve parent node from a path, or last existing directory |
1122 | 1289 |
1123 each directory of the path will be retrieved, until the last existing one | 1290 each directory of the path will be retrieved, until the last existing one |
1124 @return (tuple[unicode, list[unicode])): parent, remaining path elements: | 1291 @return (tuple[unicode, list[unicode])): parent, remaining path elements: |
1125 - parent is the id of the last retrieved directory (or u'' for root) | 1292 - parent is the id of the last retrieved directory (or u'' for root) |
1126 - remaining path elements are the directories which have not been retrieved | 1293 - remaining path elements are the directories which have not been retrieved |
1127 (i.e. which don't exist) | 1294 (i.e. which don't exist) |
1128 """ | 1295 """ |
1129 # if path is set, we have to retrieve parent directory of the file(s) from it | 1296 # if path is set, we have to retrieve parent directory of the file(s) from it |
1130 if parent is not None: | 1297 if parent is not None: |
1131 raise exceptions.ConflictError(_(u"You can't use path and parent at the same time")) | 1298 raise exceptions.ConflictError( |
1132 path_elts = filter(None, path.split(u'/')) | 1299 _(u"You can't use path and parent at the same time") |
1133 if {u'..', u'.'}.intersection(path_elts): | 1300 ) |
1301 path_elts = filter(None, path.split(u"/")) | |
1302 if {u"..", u"."}.intersection(path_elts): | |
1134 raise ValueError(_(u'".." or "." can\'t be used in path')) | 1303 raise ValueError(_(u'".." or "." can\'t be used in path')) |
1135 | 1304 |
1136 # we retrieve all directories from path until we get the parent container | 1305 # we retrieve all directories from path until we get the parent container |
1137 # non existing directories will be created | 1306 # non existing directories will be created |
1138 parent = u'' | 1307 parent = u"" |
1139 for idx, path_elt in enumerate(path_elts): | 1308 for idx, path_elt in enumerate(path_elts): |
1140 directories = yield self.storage.getFiles(client, parent=parent, type_=C.FILE_TYPE_DIRECTORY, | 1309 directories = yield self.storage.getFiles( |
1141 name=path_elt, namespace=namespace, owner=owner) | 1310 client, |
1311 parent=parent, | |
1312 type_=C.FILE_TYPE_DIRECTORY, | |
1313 name=path_elt, | |
1314 namespace=namespace, | |
1315 owner=owner, | |
1316 ) | |
1142 if not directories: | 1317 if not directories: |
1143 defer.returnValue((parent, path_elts[idx:])) | 1318 defer.returnValue((parent, path_elts[idx:])) |
1144 # from this point, directories don't exist anymore, we have to create them | 1319 # from this point, directories don't exist anymore, we have to create them |
1145 elif len(directories) > 1: | 1320 elif len(directories) > 1: |
1146 raise exceptions.InternalError(_(u"Several directories found, this should not happen")) | 1321 raise exceptions.InternalError( |
1322 _(u"Several directories found, this should not happen") | |
1323 ) | |
1147 else: | 1324 else: |
1148 directory = directories[0] | 1325 directory = directories[0] |
1149 self.checkFilePermission(directory, peer_jid, perms_to_check) | 1326 self.checkFilePermission(directory, peer_jid, perms_to_check) |
1150 parent = directory[u'id'] | 1327 parent = directory[u"id"] |
1151 defer.returnValue((parent, [])) | 1328 defer.returnValue((parent, [])) |
1152 | 1329 |
1153 @defer.inlineCallbacks | 1330 @defer.inlineCallbacks |
1154 def getFiles(self, client, peer_jid, file_id=None, version=None, parent=None, path=None, type_=None, | 1331 def getFiles( |
1155 file_hash=None, hash_algo=None, name=None, namespace=None, mime_type=None, | 1332 self, |
1156 owner=None, access=None, projection=None, unique=False, perms_to_check=(C.ACCESS_PERM_READ,)): | 1333 client, |
1334 peer_jid, | |
1335 file_id=None, | |
1336 version=None, | |
1337 parent=None, | |
1338 path=None, | |
1339 type_=None, | |
1340 file_hash=None, | |
1341 hash_algo=None, | |
1342 name=None, | |
1343 namespace=None, | |
1344 mime_type=None, | |
1345 owner=None, | |
1346 access=None, | |
1347 projection=None, | |
1348 unique=False, | |
1349 perms_to_check=(C.ACCESS_PERM_READ,), | |
1350 ): | |
1157 """retrieve files with with given filters | 1351 """retrieve files with with given filters |
1158 | 1352 |
1159 @param peer_jid(jid.JID, None): jid trying to access the file | 1353 @param peer_jid(jid.JID, None): jid trying to access the file |
1160 needed to check permission. | 1354 needed to check permission. |
1161 Use None to ignore permission (perms_to_check must be None too) | 1355 Use None to ignore permission (perms_to_check must be None too) |
1178 @raise exceptions.NotFound: parent directory not found (when path is specified) | 1372 @raise exceptions.NotFound: parent directory not found (when path is specified) |
1179 @raise exceptions.PermissionError: peer_jid can't use perms_to_check for one of the file | 1373 @raise exceptions.PermissionError: peer_jid can't use perms_to_check for one of the file |
1180 on the path | 1374 on the path |
1181 """ | 1375 """ |
1182 if peer_jid is None and perms_to_check or perms_to_check is None and peer_jid: | 1376 if peer_jid is None and perms_to_check or perms_to_check is None and peer_jid: |
1183 raise exceptions.InternalError('if you want to disable permission check, both peer_jid and perms_to_check must be None') | 1377 raise exceptions.InternalError( |
1378 "if you want to disable permission check, both peer_jid and perms_to_check must be None" | |
1379 ) | |
1184 if owner is not None: | 1380 if owner is not None: |
1185 owner = owner.userhostJID() | 1381 owner = owner.userhostJID() |
1186 if path is not None: | 1382 if path is not None: |
1187 # permission are checked by _getParentDir | 1383 # permission are checked by _getParentDir |
1188 parent, remaining_path_elts = yield self._getParentDir(client, path, parent, namespace, owner, peer_jid, perms_to_check) | 1384 parent, remaining_path_elts = yield self._getParentDir( |
1385 client, path, parent, namespace, owner, peer_jid, perms_to_check | |
1386 ) | |
1189 if remaining_path_elts: | 1387 if remaining_path_elts: |
1190 # if we have remaining path elements, | 1388 # if we have remaining path elements, |
1191 # the parent directory is not found | 1389 # the parent directory is not found |
1192 raise failure.Failure(exceptions.NotFound()) | 1390 raise failure.Failure(exceptions.NotFound()) |
1193 if parent and peer_jid: | 1391 if parent and peer_jid: |
1195 # we need to check all the parents | 1393 # we need to check all the parents |
1196 parent_data = yield self.storage.getFiles(client, file_id=parent) | 1394 parent_data = yield self.storage.getFiles(client, file_id=parent) |
1197 try: | 1395 try: |
1198 parent_data = parent_data[0] | 1396 parent_data = parent_data[0] |
1199 except IndexError: | 1397 except IndexError: |
1200 raise exceptions.DataError(u'mising parent') | 1398 raise exceptions.DataError(u"mising parent") |
1201 yield self.checkPermissionToRoot(client, parent_data, peer_jid, perms_to_check) | 1399 yield self.checkPermissionToRoot( |
1202 | 1400 client, parent_data, peer_jid, perms_to_check |
1203 files = yield self.storage.getFiles(client, file_id=file_id, version=version, parent=parent, type_=type_, | 1401 ) |
1204 file_hash=file_hash, hash_algo=hash_algo, name=name, namespace=namespace, | 1402 |
1205 mime_type=mime_type, owner=owner, access=access, | 1403 files = yield self.storage.getFiles( |
1206 projection=projection, unique=unique) | 1404 client, |
1405 file_id=file_id, | |
1406 version=version, | |
1407 parent=parent, | |
1408 type_=type_, | |
1409 file_hash=file_hash, | |
1410 hash_algo=hash_algo, | |
1411 name=name, | |
1412 namespace=namespace, | |
1413 mime_type=mime_type, | |
1414 owner=owner, | |
1415 access=access, | |
1416 projection=projection, | |
1417 unique=unique, | |
1418 ) | |
1207 | 1419 |
1208 if peer_jid: | 1420 if peer_jid: |
1209 # if permission are checked, we must remove all file tha use can't access | 1421 # if permission are checked, we must remove all file tha use can't access |
1210 to_remove = [] | 1422 to_remove = [] |
1211 for file_data in files: | 1423 for file_data in files: |
1212 try: | 1424 try: |
1213 self.checkFilePermission(file_data, peer_jid, perms_to_check) | 1425 self.checkFilePermission(file_data, peer_jid, perms_to_check) |
1214 except exceptions.PermissionError: | 1426 except exceptions.PermissionError: |
1216 for file_data in to_remove: | 1428 for file_data in to_remove: |
1217 files.remove(file_data) | 1429 files.remove(file_data) |
1218 defer.returnValue(files) | 1430 defer.returnValue(files) |
1219 | 1431 |
1220 @defer.inlineCallbacks | 1432 @defer.inlineCallbacks |
1221 def setFile(self, client, name, file_id=None, version=u'', parent=None, path=None, | 1433 def setFile( |
1222 type_=C.FILE_TYPE_FILE, file_hash=None, hash_algo=None, size=None, namespace=None, | 1434 self, |
1223 mime_type=None, created=None, modified=None, owner=None, access=None, extra=None, | 1435 client, |
1224 peer_jid = None, perms_to_check=(C.ACCESS_PERM_WRITE,)): | 1436 name, |
1437 file_id=None, | |
1438 version=u"", | |
1439 parent=None, | |
1440 path=None, | |
1441 type_=C.FILE_TYPE_FILE, | |
1442 file_hash=None, | |
1443 hash_algo=None, | |
1444 size=None, | |
1445 namespace=None, | |
1446 mime_type=None, | |
1447 created=None, | |
1448 modified=None, | |
1449 owner=None, | |
1450 access=None, | |
1451 extra=None, | |
1452 peer_jid=None, | |
1453 perms_to_check=(C.ACCESS_PERM_WRITE,), | |
1454 ): | |
1225 """set a file metadata | 1455 """set a file metadata |
1226 | 1456 |
1227 @param name(unicode): basename of the file | 1457 @param name(unicode): basename of the file |
1228 @param file_id(unicode): unique id of the file | 1458 @param file_id(unicode): unique id of the file |
1229 @param version(unicode): version of this file | 1459 @param version(unicode): version of this file |
1256 @param perms_to_check(tuple[unicode],None): permission to check | 1486 @param perms_to_check(tuple[unicode],None): permission to check |
1257 must be a tuple of C.ACCESS_PERM_* or None | 1487 must be a tuple of C.ACCESS_PERM_* or None |
1258 if None, permission will no be checked (peer_jid must be None too in this case) | 1488 if None, permission will no be checked (peer_jid must be None too in this case) |
1259 @param profile(unicode): profile owning the file | 1489 @param profile(unicode): profile owning the file |
1260 """ | 1490 """ |
1261 if '/' in name: | 1491 if "/" in name: |
1262 raise ValueError('name must not contain a slash ("/")') | 1492 raise ValueError('name must not contain a slash ("/")') |
1263 if file_id is None: | 1493 if file_id is None: |
1264 file_id = shortuuid.uuid() | 1494 file_id = shortuuid.uuid() |
1265 if file_hash is not None and hash_algo is None or hash_algo is not None and file_hash is None: | 1495 if ( |
1266 raise ValueError('file_hash and hash_algo must be set at the same time') | 1496 file_hash is not None |
1497 and hash_algo is None | |
1498 or hash_algo is not None | |
1499 and file_hash is None | |
1500 ): | |
1501 raise ValueError("file_hash and hash_algo must be set at the same time") | |
1267 if mime_type is None: | 1502 if mime_type is None: |
1268 mime_type, file_encoding = mimetypes.guess_type(name) | 1503 mime_type, file_encoding = mimetypes.guess_type(name) |
1269 if created is None: | 1504 if created is None: |
1270 created = time.time() | 1505 created = time.time() |
1271 if namespace is not None: | 1506 if namespace is not None: |
1272 namespace = namespace.strip() or None | 1507 namespace = namespace.strip() or None |
1273 if type_ == C.FILE_TYPE_DIRECTORY: | 1508 if type_ == C.FILE_TYPE_DIRECTORY: |
1274 if any(version, file_hash, size, mime_type): | 1509 if any(version, file_hash, size, mime_type): |
1275 raise ValueError(u"version, file_hash, size and mime_type can't be set for a directory") | 1510 raise ValueError( |
1511 u"version, file_hash, size and mime_type can't be set for a directory" | |
1512 ) | |
1276 if owner is not None: | 1513 if owner is not None: |
1277 owner = owner.userhostJID() | 1514 owner = owner.userhostJID() |
1278 | 1515 |
1279 if path is not None: | 1516 if path is not None: |
1280 # _getParentDir will check permissions if peer_jid is set, so we use owner | 1517 # _getParentDir will check permissions if peer_jid is set, so we use owner |
1281 parent, remaining_path_elts = yield self._getParentDir(client, path, parent, namespace, owner, owner, perms_to_check) | 1518 parent, remaining_path_elts = yield self._getParentDir( |
1519 client, path, parent, namespace, owner, owner, perms_to_check | |
1520 ) | |
1282 # if remaining directories don't exist, we have to create them | 1521 # if remaining directories don't exist, we have to create them |
1283 for new_dir in remaining_path_elts: | 1522 for new_dir in remaining_path_elts: |
1284 new_dir_id = shortuuid.uuid() | 1523 new_dir_id = shortuuid.uuid() |
1285 yield self.storage.setFile(client, name=new_dir, file_id=new_dir_id, version=u'', parent=parent, | 1524 yield self.storage.setFile( |
1286 type_=C.FILE_TYPE_DIRECTORY, namespace=namespace, | 1525 client, |
1287 created=time.time(), | 1526 name=new_dir, |
1288 owner=owner, | 1527 file_id=new_dir_id, |
1289 access=access, extra={}) | 1528 version=u"", |
1529 parent=parent, | |
1530 type_=C.FILE_TYPE_DIRECTORY, | |
1531 namespace=namespace, | |
1532 created=time.time(), | |
1533 owner=owner, | |
1534 access=access, | |
1535 extra={}, | |
1536 ) | |
1290 parent = new_dir_id | 1537 parent = new_dir_id |
1291 elif parent is None: | 1538 elif parent is None: |
1292 parent = u'' | 1539 parent = u"" |
1293 | 1540 |
1294 yield self.storage.setFile(client, file_id=file_id, version=version, parent=parent, type_=type_, | 1541 yield self.storage.setFile( |
1295 file_hash=file_hash, hash_algo=hash_algo, name=name, size=size, | 1542 client, |
1296 namespace=namespace, mime_type=mime_type, created=created, modified=modified, | 1543 file_id=file_id, |
1297 owner=owner, | 1544 version=version, |
1298 access=access, extra=extra) | 1545 parent=parent, |
1546 type_=type_, | |
1547 file_hash=file_hash, | |
1548 hash_algo=hash_algo, | |
1549 name=name, | |
1550 size=size, | |
1551 namespace=namespace, | |
1552 mime_type=mime_type, | |
1553 created=created, | |
1554 modified=modified, | |
1555 owner=owner, | |
1556 access=access, | |
1557 extra=extra, | |
1558 ) | |
1299 | 1559 |
1300 def fileUpdate(self, file_id, column, update_cb): | 1560 def fileUpdate(self, file_id, column, update_cb): |
1301 """update a file column taking care of race condition | 1561 """update a file column taking care of race condition |
1302 | 1562 |
1303 access is NOT checked in this method, it must be checked beforehand | 1563 access is NOT checked in this method, it must be checked beforehand |
1316 | 1576 |
1317 @param entity_jid (JID): the entity to check (if bare jid is used, all resources are tested) | 1577 @param entity_jid (JID): the entity to check (if bare jid is used, all resources are tested) |
1318 @return (bool): True if entity is available | 1578 @return (bool): True if entity is available |
1319 """ | 1579 """ |
1320 if not entity_jid.resource: | 1580 if not entity_jid.resource: |
1321 return bool(self.getAvailableResources(client, entity_jid)) # is any resource is available, entity is available | 1581 return bool( |
1582 self.getAvailableResources(client, entity_jid) | |
1583 ) # is any resource is available, entity is available | |
1322 try: | 1584 try: |
1323 presence_data = self.getEntityDatum(entity_jid, "presence", client.profile) | 1585 presence_data = self.getEntityDatum(entity_jid, "presence", client.profile) |
1324 except KeyError: | 1586 except KeyError: |
1325 log.debug(u"No presence information for {}".format(entity_jid)) | 1587 log.debug(u"No presence information for {}".format(entity_jid)) |
1326 return False | 1588 return False |