comparison src/plugins/plugin_comp_file_sharing.py @ 2528:65e278997715

component file sharing: comments metadata: new <comments> element is added to file metadata, it contains the URL to the comments virtual node and the count of comments (this way client knows if it make sense to request comments or not). Fixed triggers in plugin XEP-0264 (return value was missing). New trigger in plugin XEP-0329 to allow component to add metadata (used here for comments url).
author Goffi <goffi@goffi.org>
date Fri, 16 Mar 2018 18:43:11 +0100
parents a201194fc461
children cbbf2ff2ef3f
comparison
equal deleted inserted replaced
2527:a201194fc461 2528:65e278997715
21 from sat.core.constants import Const as C 21 from sat.core.constants import Const as C
22 from sat.core import exceptions 22 from sat.core import exceptions
23 from sat.core.log import getLogger 23 from sat.core.log import getLogger
24 log = getLogger(__name__) 24 log = getLogger(__name__)
25 from sat.tools.common import regex 25 from sat.tools.common import regex
26 from sat.tools.common import uri
26 from sat.tools import stream 27 from sat.tools import stream
27 from twisted.internet import defer 28 from twisted.internet import defer
28 from twisted.words.protocols.jabber import error 29 from twisted.words.protocols.jabber import error
29 from wokkel import pubsub 30 from wokkel import pubsub
30 from wokkel import generic 31 from wokkel import generic
46 C.PI_HANDLER: C.BOOL_TRUE, 47 C.PI_HANDLER: C.BOOL_TRUE,
47 C.PI_DESCRIPTION: _(u"""Component hosting and sharing files""") 48 C.PI_DESCRIPTION: _(u"""Component hosting and sharing files""")
48 } 49 }
49 50
50 HASH_ALGO = u'sha-256' 51 HASH_ALGO = u'sha-256'
52 NS_COMMENTS = 'org.salut-a-toi.comments'
51 COMMENT_NODE_PREFIX = 'org.salut-a-toi.file_comments/' 53 COMMENT_NODE_PREFIX = 'org.salut-a-toi.file_comments/'
52 54
53 55
54 class FileSharing(object): 56 class FileSharing(object):
55 57
60 self._jf = host.plugins['XEP-0234'] 62 self._jf = host.plugins['XEP-0234']
61 self._h = host.plugins['XEP-0300'] 63 self._h = host.plugins['XEP-0300']
62 self._t = host.plugins['XEP-0264'] 64 self._t = host.plugins['XEP-0264']
63 host.trigger.add("FILE_getDestDir", self._getDestDirTrigger) 65 host.trigger.add("FILE_getDestDir", self._getDestDirTrigger)
64 host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger, priority=1000) 66 host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger, priority=1000)
67 host.trigger.add("XEP-0234_buildFileElement", self._addFileComments)
68 host.trigger.add("XEP-0234_parseFileElement", self._getFileComments)
69 host.trigger.add("XEP-0329_compGetFilesFromNode", self._addCommentsData)
65 self.files_path = host.getLocalPath(None, C.FILES_DIR, profile=False) 70 self.files_path = host.getLocalPath(None, C.FILES_DIR, profile=False)
66 71
67 def getHandler(self, client): 72 def getHandler(self, client):
68 return Comments_handler(self) 73 return Comments_handler(self)
69 74
75 if not os.path.exists(path): 80 if not os.path.exists(path):
76 os.makedirs(path) 81 os.makedirs(path)
77 82
78 @defer.inlineCallbacks 83 @defer.inlineCallbacks
79 def _fileTransferedCb(self, dummy, client, peer_jid, file_data, file_path): 84 def _fileTransferedCb(self, dummy, client, peer_jid, file_data, file_path):
85 """post file reception tasks
86
87 on file is received, this method create hash/thumbnails if necessary
88 move the file to the right location, and create metadata entry in database
89 """
80 name = file_data[u'name'] 90 name = file_data[u'name']
81 extra = {} 91 extra = {}
82 92
83 if file_data[u'hash_algo'] == HASH_ALGO: 93 if file_data[u'hash_algo'] == HASH_ALGO:
84 log.debug(_(u"Reusing already generated hash")) 94 log.debug(_(u"Reusing already generated hash"))
124 mime_type=mime_type, 134 mime_type=mime_type,
125 owner=peer_jid, 135 owner=peer_jid,
126 extra=extra) 136 extra=extra)
127 137
128 def _getDestDirTrigger(self, client, peer_jid, transfer_data, file_data, stream_object): 138 def _getDestDirTrigger(self, client, peer_jid, transfer_data, file_data, stream_object):
139 """This trigger accept file sending request, and store file locally"""
129 if not client.is_component: 140 if not client.is_component:
130 return True, None 141 return True, None
131 assert stream_object 142 assert stream_object
132 assert 'stream_object' not in transfer_data 143 assert 'stream_object' not in transfer_data
133 assert C.KEY_PROGRESS_ID in file_data 144 assert C.KEY_PROGRESS_ID in file_data
141 self._f.openFileWrite(client, file_tmp_path, transfer_data, file_data, stream_object) 152 self._f.openFileWrite(client, file_tmp_path, transfer_data, file_data, stream_object)
142 return False, defer.succeed(True) 153 return False, defer.succeed(True)
143 154
144 @defer.inlineCallbacks 155 @defer.inlineCallbacks
145 def _retrieveFiles(self, client, session, content_data, content_name, file_data, file_elt): 156 def _retrieveFiles(self, client, session, content_data, content_name, file_data, file_elt):
157 """This method retrieve a file on request, and send if after checking permissions"""
146 peer_jid = session[u'peer_jid'] 158 peer_jid = session[u'peer_jid']
147 try: 159 try:
148 found_files = yield self.host.memory.getFiles(client, 160 found_files = yield self.host.memory.getFiles(client,
149 peer_jid=peer_jid, 161 peer_jid=peer_jid,
150 name=file_data.get(u'name'), 162 name=file_data.get(u'name'),
190 if not client.is_component: 202 if not client.is_component:
191 return True, None 203 return True, None
192 else: 204 else:
193 return False, self._retrieveFiles(client, session, content_data, content_name, file_data, file_elt) 205 return False, self._retrieveFiles(client, session, content_data, content_name, file_data, file_elt)
194 206
207 ## comments triggers ##
208
209 def _addFileComments(self, file_elt, extra_args):
210 try:
211 comments_url = extra_args.pop('comments_url')
212 except KeyError:
213 return
214
215 comment_elt = file_elt.addElement((NS_COMMENTS, 'comments'), content=comments_url)
216
217 try:
218 count = len(extra_args[u'extra'][u'comments'])
219 except KeyError:
220 count = 0
221
222 comment_elt['count'] = unicode(count)
223 return True
224
225 def _getFileComments(self, file_elt, file_data):
226 try:
227 comments_elt = next(file_elt.elements(NS_COMMENTS, 'comments'))
228 except StopIteration:
229 return
230 file_data['comments_url'] = unicode(comments_elt)
231 file_data['comments_count'] = comments_elt['count']
232 return True
233
234 def _addCommentsData(self, client, iq_elt, owner, node_path, files_data):
235 for file_data in files_data:
236 file_data['comments_url'] = uri.buildXMPPUri('pubsub',
237 path=client.jid.full(),
238 node=COMMENT_NODE_PREFIX + file_data['id'])
239 return True
240
195 241
196 class Comments_handler(pubsub.PubSubService): 242 class Comments_handler(pubsub.PubSubService):
243 """This class is a minimal Pubsub service handling virtual nodes for comments"""
197 244
198 def __init__(self, plugin_parent): 245 def __init__(self, plugin_parent):
199 super(Comments_handler, self).__init__() # PubsubVirtualResource()) 246 super(Comments_handler, self).__init__() # PubsubVirtualResource())
200 self.host = plugin_parent.host 247 self.host = plugin_parent.host
201 self.plugin_parent = plugin_parent 248 self.plugin_parent = plugin_parent