comparison sat_frontends/jp/cmd_invitation.py @ 3028:ab2696e34d29

Python 3 port: /!\ this is a huge commit /!\ starting from this commit, SàT is needs Python 3.6+ /!\ SàT maybe be instable or some feature may not work anymore, this will improve with time This patch port backend, bridge and frontends to Python 3. Roughly this has been done this way: - 2to3 tools has been applied (with python 3.7) - all references to python2 have been replaced with python3 (notably shebangs) - fixed files not handled by 2to3 (notably the shell script) - several manual fixes - fixed issues reported by Python 3 that where not handled in Python 2 - replaced "async" with "async_" when needed (it's a reserved word from Python 3.7) - replaced zope's "implements" with @implementer decorator - temporary hack to handle data pickled in database, as str or bytes may be returned, to be checked later - fixed hash comparison for password - removed some code which is not needed anymore with Python 3 - deactivated some code which needs to be checked (notably certificate validation) - tested with jp, fixed reported issues until some basic commands worked - ported Primitivus (after porting dependencies like urwid satext) - more manual fixes
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:08:41 +0200
parents 003b8b4b56a7
children fee60f17ebac
comparison
equal deleted inserted replaced
3027:ff5bcb12ae60 3028:ab2696e34d29
16 16
17 # You should have received a copy of the GNU Affero General Public License 17 # You should have received a copy of the GNU Affero General Public License
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 20
21 import base 21 from . import base
22 from sat.core.i18n import _ 22 from sat.core.i18n import _
23 from sat_frontends.jp.constants import Const as C 23 from sat_frontends.jp.constants import Const as C
24 from sat.tools.common.ansi import ANSI as A 24 from sat.tools.common.ansi import ANSI as A
25 from sat.tools.common import data_format 25 from sat.tools.common import data_format
26 from functools import partial 26 from functools import partial
34 self, 34 self,
35 host, 35 host,
36 "create", 36 "create",
37 use_profile=False, 37 use_profile=False,
38 use_output=C.OUTPUT_DICT, 38 use_output=C.OUTPUT_DICT,
39 help=_(u"create and send an invitation"), 39 help=_("create and send an invitation"),
40 ) 40 )
41 self.need_loop = True 41 self.need_loop = True
42 42
43 def add_parser_options(self): 43 def add_parser_options(self):
44 self.parser.add_argument( 44 self.parser.add_argument(
45 "-j", 45 "-j",
46 "--jid", 46 "--jid",
47 type=base.unicode_decoder,
48 default="", 47 default="",
49 help="jid of the invitee (default: generate one)", 48 help="jid of the invitee (default: generate one)",
50 ) 49 )
51 self.parser.add_argument( 50 self.parser.add_argument(
52 "-P", 51 "-P",
53 "--password", 52 "--password",
54 type=base.unicode_decoder,
55 default="", 53 default="",
56 help="password of the invitee profile/XMPP account (default: generate one)", 54 help="password of the invitee profile/XMPP account (default: generate one)",
57 ) 55 )
58 self.parser.add_argument( 56 self.parser.add_argument(
59 "-n", 57 "-n",
60 "--name", 58 "--name",
61 type=base.unicode_decoder,
62 default="", 59 default="",
63 help="name of the invitee", 60 help="name of the invitee",
64 ) 61 )
65 self.parser.add_argument( 62 self.parser.add_argument(
66 "-N", 63 "-N",
67 "--host-name", 64 "--host-name",
68 type=base.unicode_decoder,
69 default="", 65 default="",
70 help="name of the host", 66 help="name of the host",
71 ) 67 )
72 self.parser.add_argument( 68 self.parser.add_argument(
73 "-e", 69 "-e",
74 "--email", 70 "--email",
75 action="append", 71 action="append",
76 type=base.unicode_decoder,
77 default=[], 72 default=[],
78 help="email(s) to send the invitation to (if --no-email is set, email will just be saved)", 73 help="email(s) to send the invitation to (if --no-email is set, email will just be saved)",
79 ) 74 )
80 self.parser.add_argument( 75 self.parser.add_argument(
81 "--no-email", action="store_true", help="do NOT send invitation email" 76 "--no-email", action="store_true", help="do NOT send invitation email"
82 ) 77 )
83 self.parser.add_argument( 78 self.parser.add_argument(
84 "-l", 79 "-l",
85 "--lang", 80 "--lang",
86 type=base.unicode_decoder,
87 default="", 81 default="",
88 help="main language spoken by the invitee", 82 help="main language spoken by the invitee",
89 ) 83 )
90 self.parser.add_argument( 84 self.parser.add_argument(
91 "-u", 85 "-u",
92 "--url", 86 "--url",
93 type=base.unicode_decoder,
94 default="", 87 default="",
95 help="template to construct the URL", 88 help="template to construct the URL",
96 ) 89 )
97 self.parser.add_argument( 90 self.parser.add_argument(
98 "-s", 91 "-s",
99 "--subject", 92 "--subject",
100 type=base.unicode_decoder,
101 default="", 93 default="",
102 help="subject of the invitation email (default: generic subject)", 94 help="subject of the invitation email (default: generic subject)",
103 ) 95 )
104 self.parser.add_argument( 96 self.parser.add_argument(
105 "-b", 97 "-b",
106 "--body", 98 "--body",
107 type=base.unicode_decoder,
108 default="", 99 default="",
109 help="body of the invitation email (default: generic body)", 100 help="body of the invitation email (default: generic body)",
110 ) 101 )
111 self.parser.add_argument( 102 self.parser.add_argument(
112 "-x", 103 "-x",
113 "--extra", 104 "--extra",
114 metavar=("KEY", "VALUE"), 105 metavar=("KEY", "VALUE"),
115 type=base.unicode_decoder,
116 action="append", 106 action="append",
117 nargs=2, 107 nargs=2,
118 default=[], 108 default=[],
119 help="extra data to associate with invitation/invitee", 109 help="extra data to associate with invitation/invitee",
120 ) 110 )
121 self.parser.add_argument( 111 self.parser.add_argument(
122 "-p", 112 "-p",
123 "--profile", 113 "--profile",
124 type=base.unicode_decoder,
125 default="", 114 default="",
126 help="profile doing the invitation (default: don't associate profile)", 115 help="profile doing the invitation (default: don't associate profile)",
127 ) 116 )
128 117
129 def invitationCreateCb(self, invitation_data): 118 def invitationCreateCb(self, invitation_data):
130 self.output(invitation_data) 119 self.output(invitation_data)
131 self.host.quit(C.EXIT_OK) 120 self.host.quit(C.EXIT_OK)
132 121
133 def invitationCreateEb(self, failure_): 122 def invitationCreateEb(self, failure_):
134 self.disp( 123 self.disp(
135 u"can't create invitation: {reason}".format(reason=failure_), error=True 124 "can't create invitation: {reason}".format(reason=failure_), error=True
136 ) 125 )
137 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 126 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
138 127
139 def start(self): 128 def start(self):
140 extra = dict(self.args.extra) 129 extra = dict(self.args.extra)
141 email = self.args.email[0] if self.args.email else None 130 email = self.args.email[0] if self.args.email else None
142 emails_extra = self.args.email[1:] 131 emails_extra = self.args.email[1:]
143 if self.args.no_email: 132 if self.args.no_email:
144 if email: 133 if email:
145 extra["email"] = email 134 extra["email"] = email
146 data_format.iter2dict(u"emails_extra", emails_extra) 135 data_format.iter2dict("emails_extra", emails_extra)
147 else: 136 else:
148 if not email: 137 if not email:
149 self.parser.error( 138 self.parser.error(
150 _(u"you need to specify an email address to send email invitation") 139 _("you need to specify an email address to send email invitation")
151 ) 140 )
152 141
153 self.host.bridge.invitationCreate( 142 self.host.bridge.invitationCreate(
154 email, 143 email,
155 emails_extra, 144 emails_extra,
174 self, 163 self,
175 host, 164 host,
176 "get", 165 "get",
177 use_profile=False, 166 use_profile=False,
178 use_output=C.OUTPUT_DICT, 167 use_output=C.OUTPUT_DICT,
179 help=_(u"get invitation data"), 168 help=_("get invitation data"),
180 ) 169 )
181 self.need_loop = True 170 self.need_loop = True
182 171
183 def add_parser_options(self): 172 def add_parser_options(self):
184 self.parser.add_argument( 173 self.parser.add_argument(
185 "id", type=base.unicode_decoder, help=_(u"invitation UUID") 174 "id", help=_("invitation UUID")
186 ) 175 )
187 self.parser.add_argument( 176 self.parser.add_argument(
188 "-j", 177 "-j",
189 "--with-jid", 178 "--with-jid",
190 action="store_true", 179 action="store_true",
191 help=_(u"start profile session and retrieve jid"), 180 help=_("start profile session and retrieve jid"),
192 ) 181 )
193 182
194 def output_data(self, data, jid_=None): 183 def output_data(self, data, jid_=None):
195 if jid_ is not None: 184 if jid_ is not None:
196 data["jid"] = jid_ 185 data["jid"] = jid_
197 self.output(data) 186 self.output(data)
198 self.host.quit() 187 self.host.quit()
199 188
200 def invitationGetCb(self, invitation_data): 189 def invitationGetCb(self, invitation_data):
201 if self.args.with_jid: 190 if self.args.with_jid:
202 profile = invitation_data[u"guest_profile"] 191 profile = invitation_data["guest_profile"]
203 192
204 def session_started(__): 193 def session_started(__):
205 self.host.bridge.asyncGetParamA( 194 self.host.bridge.asyncGetParamA(
206 u"JabberID", 195 "JabberID",
207 u"Connection", 196 "Connection",
208 profile_key=profile, 197 profile_key=profile,
209 callback=lambda jid_: self.output_data(invitation_data, jid_), 198 callback=lambda jid_: self.output_data(invitation_data, jid_),
210 errback=partial( 199 errback=partial(
211 self.errback, 200 self.errback,
212 msg=_(u"can't retrieve jid: {}"), 201 msg=_("can't retrieve jid: {}"),
213 exit_code=C.EXIT_BRIDGE_ERRBACK, 202 exit_code=C.EXIT_BRIDGE_ERRBACK,
214 ), 203 ),
215 ) 204 )
216 205
217 self.host.bridge.profileStartSession( 206 self.host.bridge.profileStartSession(
218 invitation_data[u"password"], 207 invitation_data["password"],
219 profile, 208 profile,
220 callback=session_started, 209 callback=session_started,
221 errback=partial( 210 errback=partial(
222 self.errback, 211 self.errback,
223 msg=_(u"can't start session: {}"), 212 msg=_("can't start session: {}"),
224 exit_code=C.EXIT_BRIDGE_ERRBACK, 213 exit_code=C.EXIT_BRIDGE_ERRBACK,
225 ), 214 ),
226 ) 215 )
227 else: 216 else:
228 self.output_data(invitation_data) 217 self.output_data(invitation_data)
231 self.host.bridge.invitationGet( 220 self.host.bridge.invitationGet(
232 self.args.id, 221 self.args.id,
233 callback=self.invitationGetCb, 222 callback=self.invitationGetCb,
234 errback=partial( 223 errback=partial(
235 self.errback, 224 self.errback,
236 msg=_(u"can't get invitation data: {}"), 225 msg=_("can't get invitation data: {}"),
237 exit_code=C.EXIT_BRIDGE_ERRBACK, 226 exit_code=C.EXIT_BRIDGE_ERRBACK,
238 ), 227 ),
239 ) 228 )
240 229
241 230
242 class Modify(base.CommandBase): 231 class Modify(base.CommandBase):
243 def __init__(self, host): 232 def __init__(self, host):
244 base.CommandBase.__init__( 233 base.CommandBase.__init__(
245 self, host, "modify", use_profile=False, help=_(u"modify existing invitation") 234 self, host, "modify", use_profile=False, help=_("modify existing invitation")
246 ) 235 )
247 self.need_loop = True 236 self.need_loop = True
248 237
249 def add_parser_options(self): 238 def add_parser_options(self):
250 self.parser.add_argument( 239 self.parser.add_argument(
251 "--replace", action="store_true", help="replace the whole data" 240 "--replace", action="store_true", help="replace the whole data"
252 ) 241 )
253 self.parser.add_argument( 242 self.parser.add_argument(
254 "-n", 243 "-n",
255 "--name", 244 "--name",
256 type=base.unicode_decoder,
257 default="", 245 default="",
258 help="name of the invitee", 246 help="name of the invitee",
259 ) 247 )
260 self.parser.add_argument( 248 self.parser.add_argument(
261 "-N", 249 "-N",
262 "--host-name", 250 "--host-name",
263 type=base.unicode_decoder,
264 default="", 251 default="",
265 help="name of the host", 252 help="name of the host",
266 ) 253 )
267 self.parser.add_argument( 254 self.parser.add_argument(
268 "-e", 255 "-e",
269 "--email", 256 "--email",
270 type=base.unicode_decoder,
271 default="", 257 default="",
272 help="email to send the invitation to (if --no-email is set, email will just be saved)", 258 help="email to send the invitation to (if --no-email is set, email will just be saved)",
273 ) 259 )
274 self.parser.add_argument( 260 self.parser.add_argument(
275 "-l", 261 "-l",
276 "--lang", 262 "--lang",
277 dest="language", 263 dest="language",
278 type=base.unicode_decoder,
279 default="", 264 default="",
280 help="main language spoken by the invitee", 265 help="main language spoken by the invitee",
281 ) 266 )
282 self.parser.add_argument( 267 self.parser.add_argument(
283 "-x", 268 "-x",
284 "--extra", 269 "--extra",
285 metavar=("KEY", "VALUE"), 270 metavar=("KEY", "VALUE"),
286 type=base.unicode_decoder,
287 action="append", 271 action="append",
288 nargs=2, 272 nargs=2,
289 default=[], 273 default=[],
290 help="extra data to associate with invitation/invitee", 274 help="extra data to associate with invitation/invitee",
291 ) 275 )
292 self.parser.add_argument( 276 self.parser.add_argument(
293 "-p", 277 "-p",
294 "--profile", 278 "--profile",
295 type=base.unicode_decoder,
296 default="", 279 default="",
297 help="profile doing the invitation (default: don't associate profile", 280 help="profile doing the invitation (default: don't associate profile",
298 ) 281 )
299 self.parser.add_argument( 282 self.parser.add_argument(
300 "id", type=base.unicode_decoder, help=_(u"invitation UUID") 283 "id", help=_("invitation UUID")
301 ) 284 )
302 285
303 def invitationModifyCb(self): 286 def invitationModifyCb(self):
304 self.disp(_(u"invitations have been modified correctly")) 287 self.disp(_("invitations have been modified correctly"))
305 self.host.quit(C.EXIT_OK) 288 self.host.quit(C.EXIT_OK)
306 289
307 def invitationModifyEb(self, failure_): 290 def invitationModifyEb(self, failure_):
308 self.disp( 291 self.disp(
309 u"can't create invitation: {reason}".format(reason=failure_), error=True 292 "can't create invitation: {reason}".format(reason=failure_), error=True
310 ) 293 )
311 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 294 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
312 295
313 def start(self): 296 def start(self):
314 extra = dict(self.args.extra) 297 extra = dict(self.args.extra)
317 if not value: 300 if not value:
318 continue 301 continue
319 if arg_name in extra: 302 if arg_name in extra:
320 self.parser.error( 303 self.parser.error(
321 _( 304 _(
322 u"you can't set {arg_name} in both optional argument and extra" 305 "you can't set {arg_name} in both optional argument and extra"
323 ).format(arg_name=arg_name) 306 ).format(arg_name=arg_name)
324 ) 307 )
325 extra[arg_name] = value 308 extra[arg_name] = value
326 self.host.bridge.invitationModify( 309 self.host.bridge.invitationModify(
327 self.args.id, 310 self.args.id,
340 host, 323 host,
341 "list", 324 "list",
342 use_profile=False, 325 use_profile=False,
343 use_output=C.OUTPUT_COMPLEX, 326 use_output=C.OUTPUT_COMPLEX,
344 extra_outputs=extra_outputs, 327 extra_outputs=extra_outputs,
345 help=_(u"list invitations data"), 328 help=_("list invitations data"),
346 ) 329 )
347 self.need_loop = True 330 self.need_loop = True
348 331
349 def default_output(self, data): 332 def default_output(self, data):
350 for idx, datum in enumerate(data.iteritems()): 333 for idx, datum in enumerate(data.items()):
351 if idx: 334 if idx:
352 self.disp(u"\n") 335 self.disp("\n")
353 key, invitation_data = datum 336 key, invitation_data = datum
354 self.disp(A.color(C.A_HEADER, key)) 337 self.disp(A.color(C.A_HEADER, key))
355 indent = u" " 338 indent = " "
356 for k, v in invitation_data.iteritems(): 339 for k, v in invitation_data.items():
357 self.disp(indent + A.color(C.A_SUBHEADER, k + u":") + u" " + unicode(v)) 340 self.disp(indent + A.color(C.A_SUBHEADER, k + ":") + " " + str(v))
358 341
359 def add_parser_options(self): 342 def add_parser_options(self):
360 self.parser.add_argument( 343 self.parser.add_argument(
361 "-p", 344 "-p",
362 "--profile", 345 "--profile",
363 default=C.PROF_KEY_NONE, 346 default=C.PROF_KEY_NONE,
364 help=_(u"return only invitations linked to this profile"), 347 help=_("return only invitations linked to this profile"),
365 ) 348 )
366 349
367 def invitationListCb(self, data): 350 def invitationListCb(self, data):
368 self.output(data) 351 self.output(data)
369 self.host.quit() 352 self.host.quit()
372 self.host.bridge.invitationList( 355 self.host.bridge.invitationList(
373 self.args.profile, 356 self.args.profile,
374 callback=self.invitationListCb, 357 callback=self.invitationListCb,
375 errback=partial( 358 errback=partial(
376 self.errback, 359 self.errback,
377 msg=_(u"can't list invitations: {}"), 360 msg=_("can't list invitations: {}"),
378 exit_code=C.EXIT_BRIDGE_ERRBACK, 361 exit_code=C.EXIT_BRIDGE_ERRBACK,
379 ), 362 ),
380 ) 363 )
381 364
382 365
386 def __init__(self, host): 369 def __init__(self, host):
387 super(Invitation, self).__init__( 370 super(Invitation, self).__init__(
388 host, 371 host,
389 "invitation", 372 "invitation",
390 use_profile=False, 373 use_profile=False,
391 help=_(u"invitation of user(s) without XMPP account"), 374 help=_("invitation of user(s) without XMPP account"),
392 ) 375 )