comparison sat/plugins/plugin_misc_file.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 26edcf3a30eb
children 003b8b4b56a7
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 _, D_ 20 from sat.core.i18n import _, D_
21 from sat.core.constants import Const as C 21 from sat.core.constants import Const as C
22 from sat.core.log import getLogger 22 from sat.core.log import getLogger
23
23 log = getLogger(__name__) 24 log = getLogger(__name__)
24 from sat.core import exceptions 25 from sat.core import exceptions
25 from sat.tools import xml_tools 26 from sat.tools import xml_tools
26 from sat.tools import stream 27 from sat.tools import stream
27 from twisted.internet import defer 28 from twisted.internet import defer
35 C.PI_IMPORT_NAME: "FILE", 36 C.PI_IMPORT_NAME: "FILE",
36 C.PI_TYPE: C.PLUG_TYPE_MISC, 37 C.PI_TYPE: C.PLUG_TYPE_MISC,
37 C.PI_MODES: C.PLUG_MODE_BOTH, 38 C.PI_MODES: C.PLUG_MODE_BOTH,
38 C.PI_MAIN: "FilePlugin", 39 C.PI_MAIN: "FilePlugin",
39 C.PI_HANDLER: "no", 40 C.PI_HANDLER: "no",
40 C.PI_DESCRIPTION: _("""File Tansfer Management: 41 C.PI_DESCRIPTION: _(
41 This plugin manage the various ways of sending a file, and choose the best one.""") 42 """File Tansfer Management:
43 This plugin manage the various ways of sending a file, and choose the best one."""
44 ),
42 } 45 }
43 46
44 47
45 SENDING = D_(u'Please select a file to send to {peer}') 48 SENDING = D_(u"Please select a file to send to {peer}")
46 SENDING_TITLE = D_(u'File sending') 49 SENDING_TITLE = D_(u"File sending")
47 CONFIRM = D_(u'{peer} wants to send the file "{name}" to you:\n{desc}\n\nThe file has a size of {size_human}\n\nDo you accept ?') 50 CONFIRM = D_(
48 CONFIRM_TITLE = D_(u'Confirm file transfer') 51 u'{peer} wants to send the file "{name}" to you:\n{desc}\n\nThe file has a size of {size_human}\n\nDo you accept ?'
49 CONFIRM_OVERWRITE = D_(u'File {} already exists, are you sure you want to overwrite ?') 52 )
50 CONFIRM_OVERWRITE_TITLE = D_(u'File exists') 53 CONFIRM_TITLE = D_(u"Confirm file transfer")
54 CONFIRM_OVERWRITE = D_(u"File {} already exists, are you sure you want to overwrite ?")
55 CONFIRM_OVERWRITE_TITLE = D_(u"File exists")
51 SECURITY_LIMIT = 30 56 SECURITY_LIMIT = 30
52 57
53 PROGRESS_ID_KEY = 'progress_id' 58 PROGRESS_ID_KEY = "progress_id"
54 59
55 60
56 class FilePlugin(object): 61 class FilePlugin(object):
57 File=stream.SatFile 62 File = stream.SatFile
58 63
59 def __init__(self, host): 64 def __init__(self, host):
60 log.info(_("plugin File initialization")) 65 log.info(_("plugin File initialization"))
61 self.host = host 66 self.host = host
62 host.bridge.addMethod("fileSend", ".plugin", in_sign='ssssa{ss}s', out_sign='a{ss}', method=self._fileSend, async=True) 67 host.bridge.addMethod(
68 "fileSend",
69 ".plugin",
70 in_sign="ssssa{ss}s",
71 out_sign="a{ss}",
72 method=self._fileSend,
73 async=True,
74 )
63 self._file_callbacks = [] 75 self._file_callbacks = []
64 host.importMenu((D_("Action"), D_("send file")), self._fileSendMenu, security_limit=10, help_string=D_("Send a file"), type_=C.MENU_SINGLE) 76 host.importMenu(
65 77 (D_("Action"), D_("send file")),
66 def _fileSend(self, peer_jid_s, filepath, name="", file_desc="", extra=None, profile=C.PROF_KEY_NONE): 78 self._fileSendMenu,
79 security_limit=10,
80 help_string=D_("Send a file"),
81 type_=C.MENU_SINGLE,
82 )
83
84 def _fileSend(
85 self,
86 peer_jid_s,
87 filepath,
88 name="",
89 file_desc="",
90 extra=None,
91 profile=C.PROF_KEY_NONE,
92 ):
67 client = self.host.getClient(profile) 93 client = self.host.getClient(profile)
68 return self.fileSend(client, jid.JID(peer_jid_s), filepath, name or None, file_desc or None, extra) 94 return self.fileSend(
95 client, jid.JID(peer_jid_s), filepath, name or None, file_desc or None, extra
96 )
69 97
70 @defer.inlineCallbacks 98 @defer.inlineCallbacks
71 def fileSend(self, client, peer_jid, filepath, filename=None, file_desc=None, extra=None): 99 def fileSend(
100 self, client, peer_jid, filepath, filename=None, file_desc=None, extra=None
101 ):
72 """Send a file using best available method 102 """Send a file using best available method
73 103
74 @param peer_jid(jid.JID): jid of the destinee 104 @param peer_jid(jid.JID): jid of the destinee
75 @param filepath(str): absolute path to the file 105 @param filepath(str): absolute path to the file
76 @param filename(unicode, None): name to use, or None to find it from filepath 106 @param filename(unicode, None): name to use, or None to find it from filepath
79 @return (dict): action dictionary, with progress id in case of success, else xmlui message 109 @return (dict): action dictionary, with progress id in case of success, else xmlui message
80 """ 110 """
81 if not os.path.isfile(filepath): 111 if not os.path.isfile(filepath):
82 raise exceptions.DataError(u"The given path doesn't link to a file") 112 raise exceptions.DataError(u"The given path doesn't link to a file")
83 if not filename: 113 if not filename:
84 filename = os.path.basename(filepath) or '_' 114 filename = os.path.basename(filepath) or "_"
85 for namespace, callback, priority, method_name in self._file_callbacks: 115 for namespace, callback, priority, method_name in self._file_callbacks:
86 has_feature = yield self.host.hasFeature(client, namespace, peer_jid) 116 has_feature = yield self.host.hasFeature(client, namespace, peer_jid)
87 if has_feature: 117 if has_feature:
88 log.info(u"{name} method will be used to send the file".format(name=method_name)) 118 log.info(
89 progress_id = yield callback(client, peer_jid, filepath, filename, file_desc, extra) 119 u"{name} method will be used to send the file".format(
90 defer.returnValue({'progress': progress_id}) 120 name=method_name
121 )
122 )
123 progress_id = yield callback(
124 client, peer_jid, filepath, filename, file_desc, extra
125 )
126 defer.returnValue({"progress": progress_id})
91 msg = u"Can't find any method to send file to {jid}".format(jid=peer_jid.full()) 127 msg = u"Can't find any method to send file to {jid}".format(jid=peer_jid.full())
92 log.warning(msg) 128 log.warning(msg)
93 defer.returnValue({'xmlui': xml_tools.note(u"Can't transfer file", msg, C.XMLUI_DATA_LVL_WARNING).toXml()}) 129 defer.returnValue(
130 {
131 "xmlui": xml_tools.note(
132 u"Can't transfer file", msg, C.XMLUI_DATA_LVL_WARNING
133 ).toXml()
134 }
135 )
94 136
95 def _onFileChoosed(self, client, peer_jid, data): 137 def _onFileChoosed(self, client, peer_jid, data):
96 cancelled = C.bool(data.get("cancelled", C.BOOL_FALSE)) 138 cancelled = C.bool(data.get("cancelled", C.BOOL_FALSE))
97 if cancelled: 139 if cancelled:
98 return 140 return
99 path=data['path'] 141 path = data["path"]
100 return self.fileSend(client, peer_jid, path) 142 return self.fileSend(client, peer_jid, path)
101 143
102 def _fileSendMenu(self, data, profile): 144 def _fileSendMenu(self, data, profile):
103 """ XMLUI activated by menu: return file sending UI 145 """ XMLUI activated by menu: return file sending UI
104 146
105 @param profile: %(doc_profile)s 147 @param profile: %(doc_profile)s
106 """ 148 """
107 try: 149 try:
108 jid_ = jid.JID(data['jid']) 150 jid_ = jid.JID(data["jid"])
109 except RuntimeError: 151 except RuntimeError:
110 raise exceptions.DataError(_("Invalid JID")) 152 raise exceptions.DataError(_("Invalid JID"))
111 153
112 file_choosed_id = self.host.registerCallback(lambda data, profile: self._onFileChoosed(self.host.getClient(profile), jid_, data), with_data=True, one_shot=True) 154 file_choosed_id = self.host.registerCallback(
155 lambda data, profile: self._onFileChoosed(
156 self.host.getClient(profile), jid_, data
157 ),
158 with_data=True,
159 one_shot=True,
160 )
113 xml_ui = xml_tools.XMLUI( 161 xml_ui = xml_tools.XMLUI(
114 C.XMLUI_DIALOG, 162 C.XMLUI_DIALOG,
115 dialog_opt = { 163 dialog_opt={
116 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_FILE, 164 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_FILE,
117 C.XMLUI_DATA_MESS: _(SENDING).format(peer=jid_.full())}, 165 C.XMLUI_DATA_MESS: _(SENDING).format(peer=jid_.full()),
118 title = _(SENDING_TITLE), 166 },
119 submit_id = file_choosed_id) 167 title=_(SENDING_TITLE),
120 168 submit_id=file_choosed_id,
121 return {'xmlui': xml_ui.toXml()} 169 )
170
171 return {"xmlui": xml_ui.toXml()}
122 172
123 def register(self, namespace, callback, priority=0, method_name=None): 173 def register(self, namespace, callback, priority=0, method_name=None):
124 """Register a fileSending method 174 """Register a fileSending method
125 175
126 @param namespace(unicode): XEP namespace 176 @param namespace(unicode): XEP namespace
128 @param priority(int): pririoty of this method, the higher available will be used 178 @param priority(int): pririoty of this method, the higher available will be used
129 @param method_name(unicode): short name for the method, namespace will be used if None 179 @param method_name(unicode): short name for the method, namespace will be used if None
130 """ 180 """
131 for data in self._file_callbacks: 181 for data in self._file_callbacks:
132 if namespace == data[0]: 182 if namespace == data[0]:
133 raise exceptions.ConflictError(u'A method with this namespace is already registered') 183 raise exceptions.ConflictError(
134 self._file_callbacks.append((namespace, callback, priority, method_name or namespace)) 184 u"A method with this namespace is already registered"
185 )
186 self._file_callbacks.append(
187 (namespace, callback, priority, method_name or namespace)
188 )
135 self._file_callbacks.sort(key=lambda data: data[2], reverse=True) 189 self._file_callbacks.sort(key=lambda data: data[2], reverse=True)
136 190
137 def unregister(self, namespace): 191 def unregister(self, namespace):
138 for idx, data in enumerate(self._file_callbacks): 192 for idx, data in enumerate(self._file_callbacks):
139 if data[0] == namespace: 193 if data[0] == namespace:
146 200
147 def openFileWrite(self, client, file_path, transfer_data, file_data, stream_object): 201 def openFileWrite(self, client, file_path, transfer_data, file_data, stream_object):
148 """create SatFile or FileStremaObject for the requested file and fill suitable data 202 """create SatFile or FileStremaObject for the requested file and fill suitable data
149 """ 203 """
150 if stream_object: 204 if stream_object:
151 assert 'stream_object' not in transfer_data 205 assert "stream_object" not in transfer_data
152 transfer_data['stream_object'] = stream.FileStreamObject( 206 transfer_data["stream_object"] = stream.FileStreamObject(
153 self.host, 207 self.host,
154 client, 208 client,
155 file_path, 209 file_path,
156 mode='wb', 210 mode="wb",
157 uid=file_data[PROGRESS_ID_KEY], 211 uid=file_data[PROGRESS_ID_KEY],
158 size=file_data['size'], 212 size=file_data["size"],
159 data_cb = file_data.get('data_cb'), 213 data_cb=file_data.get("data_cb"),
160 ) 214 )
161 else: 215 else:
162 assert 'file_obj' not in transfer_data 216 assert "file_obj" not in transfer_data
163 transfer_data['file_obj'] = stream.SatFile( 217 transfer_data["file_obj"] = stream.SatFile(
164 self.host, 218 self.host,
165 client, 219 client,
166 file_path, 220 file_path,
167 mode='wb', 221 mode="wb",
168 uid=file_data[PROGRESS_ID_KEY], 222 uid=file_data[PROGRESS_ID_KEY],
169 size=file_data['size'], 223 size=file_data["size"],
170 data_cb = file_data.get('data_cb'), 224 data_cb=file_data.get("data_cb"),
171 ) 225 )
172 226
173 def _gotConfirmation(self, data, client, peer_jid, transfer_data, file_data, stream_object): 227 def _gotConfirmation(
228 self, data, client, peer_jid, transfer_data, file_data, stream_object
229 ):
174 """Called when the permission and dest path have been received 230 """Called when the permission and dest path have been received
175 231
176 @param peer_jid(jid.JID): jid of the file sender 232 @param peer_jid(jid.JID): jid of the file sender
177 @param transfer_data(dict): same as for [self.getDestDir] 233 @param transfer_data(dict): same as for [self.getDestDir]
178 @param file_data(dict): same as for [self.getDestDir] 234 @param file_data(dict): same as for [self.getDestDir]
179 @param stream_object(bool): same as for [self.getDestDir] 235 @param stream_object(bool): same as for [self.getDestDir]
180 return (bool): True if copy is wanted and OK 236 return (bool): True if copy is wanted and OK
181 False if user wants to cancel 237 False if user wants to cancel
182 if file exists ask confirmation and call again self._getDestDir if needed 238 if file exists ask confirmation and call again self._getDestDir if needed
183 """ 239 """
184 if data.get('cancelled', False): 240 if data.get("cancelled", False):
185 return False 241 return False
186 path = data['path'] 242 path = data["path"]
187 file_data['file_path'] = file_path = os.path.join(path, file_data['name']) 243 file_data["file_path"] = file_path = os.path.join(path, file_data["name"])
188 log.debug(u'destination file path set to {}'.format(file_path)) 244 log.debug(u"destination file path set to {}".format(file_path))
189 245
190 # we manage case where file already exists 246 # we manage case where file already exists
191 if os.path.exists(file_path): 247 if os.path.exists(file_path):
248
192 def check_overwrite(overwrite): 249 def check_overwrite(overwrite):
193 if overwrite: 250 if overwrite:
194 self.openFileWrite(client, file_path, transfer_data, file_data, stream_object) 251 self.openFileWrite(
252 client, file_path, transfer_data, file_data, stream_object
253 )
195 return True 254 return True
196 else: 255 else:
197 return self.getDestDir(client, peer_jid, transfer_data, file_data) 256 return self.getDestDir(client, peer_jid, transfer_data, file_data)
198 257
199 exists_d = xml_tools.deferConfirm( 258 exists_d = xml_tools.deferConfirm(
200 self.host, 259 self.host,
201 _(CONFIRM_OVERWRITE).format(file_path), 260 _(CONFIRM_OVERWRITE).format(file_path),
202 _(CONFIRM_OVERWRITE_TITLE), 261 _(CONFIRM_OVERWRITE_TITLE),
203 action_extra={'meta_from_jid': peer_jid.full(), 262 action_extra={
204 'meta_type': C.META_TYPE_OVERWRITE, 263 "meta_from_jid": peer_jid.full(),
205 'meta_progress_id': file_data[PROGRESS_ID_KEY] 264 "meta_type": C.META_TYPE_OVERWRITE,
206 }, 265 "meta_progress_id": file_data[PROGRESS_ID_KEY],
266 },
207 security_limit=SECURITY_LIMIT, 267 security_limit=SECURITY_LIMIT,
208 profile=client.profile) 268 profile=client.profile,
269 )
209 exists_d.addCallback(check_overwrite) 270 exists_d.addCallback(check_overwrite)
210 return exists_d 271 return exists_d
211 272
212 self.openFileWrite(client, file_path, transfer_data, file_data, stream_object) 273 self.openFileWrite(client, file_path, transfer_data, file_data, stream_object)
213 return True 274 return True
237 "size_human" will also be added with human readable file size 298 "size_human" will also be added with human readable file size
238 @param stream_object(bool): if True, a stream_object will be used instead of file_obj 299 @param stream_object(bool): if True, a stream_object will be used instead of file_obj
239 a stream.FileStreamObject will be used 300 a stream.FileStreamObject will be used
240 return (defer.Deferred): True if transfer is accepted 301 return (defer.Deferred): True if transfer is accepted
241 """ 302 """
242 cont,ret_value = self.host.trigger.returnPoint("FILE_getDestDir", client, peer_jid, transfer_data, file_data, stream_object) 303 cont, ret_value = self.host.trigger.returnPoint(
304 "FILE_getDestDir", client, peer_jid, transfer_data, file_data, stream_object
305 )
243 if not cont: 306 if not cont:
244 return ret_value 307 return ret_value
245 filename = file_data['name'] 308 filename = file_data["name"]
246 assert filename and not '/' in filename 309 assert filename and not "/" in filename
247 assert PROGRESS_ID_KEY in file_data 310 assert PROGRESS_ID_KEY in file_data
248 # human readable size 311 # human readable size
249 file_data['size_human'] = u'{:.6n} Mio'.format(float(file_data['size'])/(1024**2)) 312 file_data["size_human"] = u"{:.6n} Mio".format(
250 d = xml_tools.deferDialog(self.host, 313 float(file_data["size"]) / (1024 ** 2)
314 )
315 d = xml_tools.deferDialog(
316 self.host,
251 _(CONFIRM).format(peer=peer_jid.full(), **file_data), 317 _(CONFIRM).format(peer=peer_jid.full(), **file_data),
252 _(CONFIRM_TITLE), 318 _(CONFIRM_TITLE),
253 type_=C.XMLUI_DIALOG_FILE, 319 type_=C.XMLUI_DIALOG_FILE,
254 options={C.XMLUI_DATA_FILETYPE: C.XMLUI_DATA_FILETYPE_DIR}, 320 options={C.XMLUI_DATA_FILETYPE: C.XMLUI_DATA_FILETYPE_DIR},
255 action_extra={'meta_from_jid': peer_jid.full(), 321 action_extra={
256 'meta_type': C.META_TYPE_FILE, 322 "meta_from_jid": peer_jid.full(),
257 'meta_progress_id': file_data[PROGRESS_ID_KEY] 323 "meta_type": C.META_TYPE_FILE,
258 }, 324 "meta_progress_id": file_data[PROGRESS_ID_KEY],
325 },
259 security_limit=SECURITY_LIMIT, 326 security_limit=SECURITY_LIMIT,
260 profile=client.profile) 327 profile=client.profile,
261 d.addCallback(self._gotConfirmation, client, peer_jid, transfer_data, file_data, stream_object) 328 )
329 d.addCallback(
330 self._gotConfirmation,
331 client,
332 peer_jid,
333 transfer_data,
334 file_data,
335 stream_object,
336 )
262 return d 337 return d