Mercurial > libervia-backend
comparison sat/plugins/plugin_comp_file_sharing.py @ 3314:5887fb414758
component file sharing: add/parse affiliation when possible
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 17 Jul 2020 13:00:10 +0200 |
parents | 9d1c0feba048 |
children | 15612c0fb421 |
comparison
equal
deleted
inserted
replaced
3313:624c60293deb | 3314:5887fb414758 |
---|---|
21 import mimetypes | 21 import mimetypes |
22 from functools import partial | 22 from functools import partial |
23 import shortuuid | 23 import shortuuid |
24 import unicodedata | 24 import unicodedata |
25 from urllib.parse import urljoin, urlparse, quote, unquote | 25 from urllib.parse import urljoin, urlparse, quote, unquote |
26 from dataclasses import dataclass | |
27 from pathlib import Path | 26 from pathlib import Path |
28 from sat.core.i18n import _ | 27 from sat.core.i18n import _ |
29 from sat.core.constants import Const as C | 28 from sat.core.constants import Const as C |
30 from sat.core import exceptions | 29 from sat.core import exceptions |
31 from sat.core.log import getLogger | 30 from sat.core.log import getLogger |
67 C.PI_DESCRIPTION: _("""Component hosting and sharing files"""), | 66 C.PI_DESCRIPTION: _("""Component hosting and sharing files"""), |
68 } | 67 } |
69 | 68 |
70 HASH_ALGO = "sha-256" | 69 HASH_ALGO = "sha-256" |
71 NS_COMMENTS = "org.salut-a-toi.comments" | 70 NS_COMMENTS = "org.salut-a-toi.comments" |
71 NS_FS_AFFILIATION = "org.salut-a-toi.file-sharing-affiliation" | |
72 COMMENT_NODE_PREFIX = "org.salut-a-toi.file_comments/" | 72 COMMENT_NODE_PREFIX = "org.salut-a-toi.file_comments/" |
73 # Directory used to buffer request body (i.e. file in case of PUT) we use more than one @ | 73 # Directory used to buffer request body (i.e. file in case of PUT) we use more than one @ |
74 # there, to be sure than it's not conflicting with a JID | 74 # there, to be sure than it's not conflicting with a JID |
75 TMP_BUFFER_DIR = "@@tmp@@" | 75 TMP_BUFFER_DIR = "@@tmp@@" |
76 | 76 |
268 # for PUT we check early if upload_id is fine, to avoid buffering a file we'll refuse | 268 # for PUT we check early if upload_id is fine, to avoid buffering a file we'll refuse |
269 # we buffer the file in component's TMP_BUFFER_DIR, so we just have to rename it at the end | 269 # we buffer the file in component's TMP_BUFFER_DIR, so we just have to rename it at the end |
270 try: | 270 try: |
271 upload_id, filename = self.upload_data | 271 upload_id, filename = self.upload_data |
272 except exceptions.DataError as e: | 272 except exceptions.DataError as e: |
273 log.warning("Invalid PUT request, we stop here: {e}") | 273 log.warning(f"Invalid PUT request, we stop here: {e}") |
274 return self.refuseRequest() | 274 return self.refuseRequest() |
275 try: | 275 try: |
276 client, upload_request, timer = self.file_sharing.expected_uploads.pop(upload_id) | 276 client, upload_request, timer = self.file_sharing.expected_uploads.pop(upload_id) |
277 except KeyError: | 277 except KeyError: |
278 log.warning(f"unknown (expired?) upload ID received for a PUT: {upload_id!r}") | 278 log.warning(f"unknown (expired?) upload ID received for a PUT: {upload_id!r}") |
341 self.host.plugins["XEP-0363"].registerHandler(self._onHTTPUpload) | 341 self.host.plugins["XEP-0363"].registerHandler(self._onHTTPUpload) |
342 self.host.trigger.add("FILE_getDestDir", self._getDestDirTrigger) | 342 self.host.trigger.add("FILE_getDestDir", self._getDestDirTrigger) |
343 self.host.trigger.add( | 343 self.host.trigger.add( |
344 "XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger, priority=1000 | 344 "XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger, priority=1000 |
345 ) | 345 ) |
346 self.host.trigger.add("XEP-0234_buildFileElement", self._addFileComments) | 346 self.host.trigger.add("XEP-0234_buildFileElement", self._addFileMetadataElts) |
347 self.host.trigger.add("XEP-0234_parseFileElement", self._getFileComments) | 347 self.host.trigger.add("XEP-0234_parseFileElement", self._getFileMetadataElts) |
348 self.host.trigger.add("XEP-0329_compGetFilesFromNode", self._addCommentsData) | 348 self.host.trigger.add("XEP-0329_compGetFilesFromNode", self._addFileMetadata) |
349 self.host.trigger.add( | |
350 "XEP-0329_compGetFilesFromNode_build_directory", | |
351 self._addDirectoryMetadataElts) | |
352 self.host.trigger.add( | |
353 "XEP-0329_parseResult_directory", | |
354 self._getDirectoryMetadataElts) | |
349 self.files_path = self.host.getLocalPath(None, C.FILES_DIR, profile=False) | 355 self.files_path = self.host.getLocalPath(None, C.FILES_DIR, profile=False) |
350 self.http_port = self.host.memory.getConfig( | 356 self.http_port = self.host.memory.getConfig( |
351 'component file_sharing', 'http_upload_port', 8888) | 357 'component file_sharing', 'http_upload_port', 8888) |
352 connection_type = self.host.memory.getConfig( | 358 connection_type = self.host.memory.getConfig( |
353 'component file_sharing', 'http_upload_connection_type', 'https') | 359 'component file_sharing', 'http_upload_connection_type', 'https') |
354 if connection_type not in ('http', 'https'): | 360 if connection_type not in ('http', 'https'): |
355 raise exceptions.ConfigError( | 361 raise exceptions.ConfigError( |
356 f'bad http_upload_connection_type, you must use one of "http" or "https"' | 362 'bad http_upload_connection_type, you must use one of "http" or "https"' |
357 ) | 363 ) |
358 self.server = FileSharingSite(self) | 364 self.server = FileSharingSite(self) |
359 self.expected_uploads = {} | 365 self.expected_uploads = {} |
360 if connection_type == 'http': | 366 if connection_type == 'http': |
361 reactor.listenTCP(self.http_port, self.server) | 367 reactor.listenTCP(self.http_port, self.server) |
362 else: | 368 else: |
363 options = tls.getOptionsFromConfig(self.host.memory.config, "component file_sharing") | 369 options = tls.getOptionsFromConfig( |
370 self.host.memory.config, "component file_sharing") | |
364 tls.TLSOptionsCheck(options) | 371 tls.TLSOptionsCheck(options) |
365 context_factory = tls.getTLSContextFactory(options) | 372 context_factory = tls.getTLSContextFactory(options) |
366 reactor.listenSSL(self.http_port, self.server, context_factory) | 373 reactor.listenSSL(self.http_port, self.server, context_factory) |
367 | |
368 | 374 |
369 def getHandler(self, client): | 375 def getHandler(self, client): |
370 return Comments_handler(self) | 376 return Comments_handler(self) |
371 | 377 |
372 def profileConnecting(self, client): | 378 def profileConnecting(self, client): |
579 get=url, | 585 get=url, |
580 headers=[], | 586 headers=[], |
581 ) | 587 ) |
582 return slot | 588 return slot |
583 | 589 |
584 ## comments triggers ## | 590 ## metadata triggers ## |
585 | 591 |
586 def _addFileComments(self, file_elt, extra_args): | 592 def _addFileMetadataElts(self, client, file_elt, extra_args): |
593 # affiliation | |
594 affiliation = extra_args.get('affiliation') | |
595 if affiliation is not None: | |
596 file_elt.addElement((NS_FS_AFFILIATION, "affiliation"), content=affiliation) | |
597 | |
598 # comments | |
587 try: | 599 try: |
588 comments_url = extra_args.pop("comments_url") | 600 comments_url = extra_args.pop("comments_url") |
589 except KeyError: | 601 except KeyError: |
590 return | 602 return |
591 | 603 |
597 count = 0 | 609 count = 0 |
598 | 610 |
599 comment_elt["count"] = str(count) | 611 comment_elt["count"] = str(count) |
600 return True | 612 return True |
601 | 613 |
602 def _getFileComments(self, file_elt, file_data): | 614 def _getFileMetadataElts(self, client, file_elt, file_data): |
615 # affiliation | |
616 try: | |
617 affiliation_elt = next(file_elt.elements(NS_FS_AFFILIATION, "affiliation")) | |
618 except StopIteration: | |
619 pass | |
620 else: | |
621 file_data["affiliation"] = str(affiliation_elt) | |
622 | |
623 # comments | |
603 try: | 624 try: |
604 comments_elt = next(file_elt.elements(NS_COMMENTS, "comments")) | 625 comments_elt = next(file_elt.elements(NS_COMMENTS, "comments")) |
605 except StopIteration: | 626 except StopIteration: |
606 return | 627 pass |
607 file_data["comments_url"] = str(comments_elt) | 628 else: |
608 file_data["comments_count"] = comments_elt["count"] | 629 file_data["comments_url"] = str(comments_elt) |
630 file_data["comments_count"] = comments_elt["count"] | |
609 return True | 631 return True |
610 | 632 |
611 def _addCommentsData(self, client, iq_elt, owner, node_path, files_data): | 633 def _addFileMetadata( |
634 self, client, iq_elt, iq_result_elt, owner, node_path, files_data): | |
612 for file_data in files_data: | 635 for file_data in files_data: |
613 file_data["comments_url"] = uri.buildXMPPUri( | 636 file_data["comments_url"] = uri.buildXMPPUri( |
614 "pubsub", | 637 "pubsub", |
615 path=client.jid.full(), | 638 path=client.jid.full(), |
616 node=COMMENT_NODE_PREFIX + file_data["id"], | 639 node=COMMENT_NODE_PREFIX + file_data["id"], |
617 ) | 640 ) |
618 return True | 641 return True |
619 | 642 |
643 def _addDirectoryMetadataElts( | |
644 self, client, file_data, directory_elt, owner, node_path): | |
645 affiliation = file_data.get('affiliation') | |
646 if affiliation is not None: | |
647 directory_elt.addElement( | |
648 (NS_FS_AFFILIATION, "affiliation"), | |
649 content=affiliation | |
650 ) | |
651 | |
652 def _getDirectoryMetadataElts( | |
653 self, client, elt, file_data): | |
654 try: | |
655 affiliation_elt = next(elt.elements((NS_FS_AFFILIATION, "affiliation"))) | |
656 except StopIteration: | |
657 pass | |
658 else: | |
659 file_data['affiliation'] = str(affiliation_elt) | |
660 | |
620 | 661 |
621 class Comments_handler(pubsub.PubSubService): | 662 class Comments_handler(pubsub.PubSubService): |
622 """This class is a minimal Pubsub service handling virtual nodes for comments""" | 663 """This class is a minimal Pubsub service handling virtual nodes for comments""" |
623 | 664 |
624 def __init__(self, plugin_parent): | 665 def __init__(self, plugin_parent): |
625 super(Comments_handler, self).__init__() # PubsubVirtualResource()) | 666 super(Comments_handler, self).__init__() |
626 self.host = plugin_parent.host | 667 self.host = plugin_parent.host |
627 self.plugin_parent = plugin_parent | 668 self.plugin_parent = plugin_parent |
628 self.discoIdentity = { | 669 self.discoIdentity = { |
629 "category": "pubsub", | 670 "category": "pubsub", |
630 "type": "virtual", # FIXME: non standard, here to avoid this service being considered as main pubsub one | 671 "type": "virtual", # FIXME: non standard, here to avoid this service being considered as main pubsub one |