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
This commit is contained in:
parent
d21a6a660f
commit
fbfe96c505
1 changed files with 6336 additions and 6398 deletions
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SAT plugin for file tansfer
|
||||
|
|
@ -41,23 +41,23 @@ PLUGIN_INFO = {
|
|||
C.PI_RECOMMENDATIONS: ["IDENTITY"],
|
||||
C.PI_MAIN: "InvitationsPlugin",
|
||||
C.PI_HANDLER: "no",
|
||||
C.PI_DESCRIPTION: _(u"""invitation of people without XMPP account""")
|
||||
C.PI_DESCRIPTION: _("""invitation of people without XMPP account""")
|
||||
}
|
||||
|
||||
|
||||
SUFFIX_MAX = 5
|
||||
INVITEE_PROFILE_TPL = u"guest@@{uuid}"
|
||||
KEY_ID = u'id'
|
||||
KEY_JID = u'jid'
|
||||
KEY_CREATED = u'created'
|
||||
KEY_LAST_CONNECTION = u'last_connection'
|
||||
KEY_GUEST_PROFILE = u'guest_profile'
|
||||
KEY_PASSWORD = u'password'
|
||||
KEY_EMAILS_EXTRA = u'emails_extra'
|
||||
EXTRA_RESERVED = {KEY_ID, KEY_JID, KEY_CREATED, u'jid_', u'jid', KEY_LAST_CONNECTION,
|
||||
INVITEE_PROFILE_TPL = "guest@@{uuid}"
|
||||
KEY_ID = 'id'
|
||||
KEY_JID = 'jid'
|
||||
KEY_CREATED = 'created'
|
||||
KEY_LAST_CONNECTION = 'last_connection'
|
||||
KEY_GUEST_PROFILE = 'guest_profile'
|
||||
KEY_PASSWORD = 'password'
|
||||
KEY_EMAILS_EXTRA = 'emails_extra'
|
||||
EXTRA_RESERVED = {KEY_ID, KEY_JID, KEY_CREATED, 'jid_', 'jid', KEY_LAST_CONNECTION,
|
||||
KEY_GUEST_PROFILE, KEY_PASSWORD, KEY_EMAILS_EXTRA}
|
||||
DEFAULT_SUBJECT = D_(u"You have been invited by {host_name} to {app_name}")
|
||||
DEFAULT_BODY = D_(u"""Hello {name}!
|
||||
DEFAULT_SUBJECT = D_("You have been invited by {host_name} to {app_name}")
|
||||
DEFAULT_BODY = D_("""Hello {name}!
|
||||
|
||||
You have received an invitation from {host_name} to participate to "{app_name}".
|
||||
To join, you just have to click on the following URL:
|
||||
|
|
@ -73,34 +73,34 @@ Welcome!
|
|||
class InvitationsPlugin(object):
|
||||
|
||||
def __init__(self, host):
|
||||
log.info(_(u"plugin Invitations initialization"))
|
||||
log.info(_("plugin Invitations initialization"))
|
||||
self.host = host
|
||||
self.invitations = persistent.LazyPersistentBinaryDict(u'invitations')
|
||||
self.invitations = persistent.LazyPersistentBinaryDict('invitations')
|
||||
host.bridge.addMethod("invitationCreate", ".plugin", in_sign='sasssssssssa{ss}s',
|
||||
out_sign='a{ss}',
|
||||
method=self._create,
|
||||
async=True)
|
||||
async_=True)
|
||||
host.bridge.addMethod("invitationGet", ".plugin", in_sign='s', out_sign='a{ss}',
|
||||
method=self.get,
|
||||
async=True)
|
||||
async_=True)
|
||||
host.bridge.addMethod("invitationModify", ".plugin", in_sign='sa{ss}b',
|
||||
out_sign='',
|
||||
method=self._modify,
|
||||
async=True)
|
||||
async_=True)
|
||||
host.bridge.addMethod("invitationList", ".plugin", in_sign='s',
|
||||
out_sign='a{sa{ss}}',
|
||||
method=self._list,
|
||||
async=True)
|
||||
async_=True)
|
||||
|
||||
def checkExtra(self, extra):
|
||||
if EXTRA_RESERVED.intersection(extra):
|
||||
raise ValueError(
|
||||
_(u"You can't use following key(s) in extra, they are reserved: {}")
|
||||
.format(u', '.join(EXTRA_RESERVED.intersection(extra))))
|
||||
_("You can't use following key(s) in extra, they are reserved: {}")
|
||||
.format(', '.join(EXTRA_RESERVED.intersection(extra))))
|
||||
|
||||
def _create(self, email=u'', emails_extra=None, jid_=u'', password=u'', name=u'',
|
||||
host_name=u'', language=u'', url_template=u'', message_subject=u'',
|
||||
message_body=u'', extra=None, profile=u''):
|
||||
def _create(self, email='', emails_extra=None, jid_='', password='', name='',
|
||||
host_name='', language='', url_template='', message_subject='',
|
||||
message_body='', extra=None, profile=''):
|
||||
# XXX: we don't use **kwargs here to keep arguments name for introspection with
|
||||
# D-Bus bridge
|
||||
if emails_extra is None:
|
||||
|
|
@ -109,10 +109,10 @@ class InvitationsPlugin(object):
|
|||
if extra is None:
|
||||
extra = {}
|
||||
else:
|
||||
extra = {unicode(k): unicode(v) for k,v in extra.iteritems()}
|
||||
extra = {str(k): str(v) for k,v in extra.items()}
|
||||
|
||||
kwargs = {"extra": extra,
|
||||
KEY_EMAILS_EXTRA: [unicode(e) for e in emails_extra]
|
||||
KEY_EMAILS_EXTRA: [str(e) for e in emails_extra]
|
||||
}
|
||||
|
||||
# we need to be sure that values are unicode, else they won't be pickled correctly
|
||||
|
|
@ -121,7 +121,7 @@ class InvitationsPlugin(object):
|
|||
"url_template", "message_subject", "message_body", "profile"):
|
||||
value = locals()[key]
|
||||
if value:
|
||||
kwargs[key] = unicode(value)
|
||||
kwargs[key] = str(value)
|
||||
d = self.create(**kwargs)
|
||||
def serialize(data):
|
||||
data[KEY_JID] = data[KEY_JID].full()
|
||||
|
|
@ -131,7 +131,7 @@ class InvitationsPlugin(object):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def create(self, **kwargs):
|
||||
ur"""Create an invitation
|
||||
r"""Create an invitation
|
||||
|
||||
This will create an XMPP account and a profile, and use a UUID to retrieve them.
|
||||
The profile is automatically generated in the form guest@@[UUID], this way they
|
||||
|
|
@ -194,29 +194,29 @@ class InvitationsPlugin(object):
|
|||
extra = kwargs.pop('extra', {})
|
||||
if set(kwargs).intersection(extra):
|
||||
raise ValueError(
|
||||
_(u"You can't use following key(s) in both args and extra: {}").format(
|
||||
u', '.join(set(kwargs).intersection(extra))))
|
||||
_("You can't use following key(s) in both args and extra: {}").format(
|
||||
', '.join(set(kwargs).intersection(extra))))
|
||||
|
||||
self.checkExtra(extra)
|
||||
|
||||
email = kwargs.pop(u'email', None)
|
||||
emails_extra = kwargs.pop(u'emails_extra', [])
|
||||
email = kwargs.pop('email', None)
|
||||
emails_extra = kwargs.pop('emails_extra', [])
|
||||
if not email and emails_extra:
|
||||
raise ValueError(
|
||||
_(u'You need to provide a main email address before using emails_extra'))
|
||||
_('You need to provide a main email address before using emails_extra'))
|
||||
|
||||
if (email is not None
|
||||
and not 'url_template' in kwargs
|
||||
and not 'message_body' in kwargs):
|
||||
raise ValueError(
|
||||
_(u"You need to provide url_template if you use default message body"))
|
||||
_("You need to provide url_template if you use default message body"))
|
||||
|
||||
## uuid
|
||||
log.info(_(u"creating an invitation"))
|
||||
id_ = unicode(shortuuid.uuid())
|
||||
log.info(_("creating an invitation"))
|
||||
id_ = str(shortuuid.uuid())
|
||||
|
||||
## XMPP account creation
|
||||
password = kwargs.pop(u'password', None)
|
||||
password = kwargs.pop('password', None)
|
||||
if password is None:
|
||||
password = utils.generatePassword()
|
||||
assert password
|
||||
|
|
@ -228,13 +228,13 @@ class InvitationsPlugin(object):
|
|||
# saved and could be used to encrypt profile password.
|
||||
extra[KEY_PASSWORD] = password
|
||||
|
||||
jid_ = kwargs.pop(u'jid_', None)
|
||||
jid_ = kwargs.pop('jid_', None)
|
||||
if not jid_:
|
||||
domain = self.host.memory.getConfig(None, 'xmpp_domain')
|
||||
if not domain:
|
||||
# TODO: fallback to profile's domain
|
||||
raise ValueError(_(u"You need to specify xmpp_domain in sat.conf"))
|
||||
jid_ = u"invitation-{uuid}@{domain}".format(uuid=shortuuid.uuid(),
|
||||
raise ValueError(_("You need to specify xmpp_domain in sat.conf"))
|
||||
jid_ = "invitation-{uuid}@{domain}".format(uuid=shortuuid.uuid(),
|
||||
domain=domain)
|
||||
jid_ = jid.JID(jid_)
|
||||
if jid_.user:
|
||||
|
|
@ -245,11 +245,11 @@ class InvitationsPlugin(object):
|
|||
except error.StanzaError as e:
|
||||
prefix = jid_.user
|
||||
idx = 0
|
||||
while e.condition == u'conflict':
|
||||
while e.condition == 'conflict':
|
||||
if idx >= SUFFIX_MAX:
|
||||
raise exceptions.ConflictError(_(u"Can't create XMPP account"))
|
||||
jid_.user = prefix + '_' + unicode(idx)
|
||||
log.info(_(u"requested jid already exists, trying with {}".format(
|
||||
raise exceptions.ConflictError(_("Can't create XMPP account"))
|
||||
jid_.user = prefix + '_' + str(idx)
|
||||
log.info(_("requested jid already exists, trying with {}".format(
|
||||
jid_.full())))
|
||||
try:
|
||||
yield self.host.plugins['XEP-0077'].registerNewAccount(jid_,
|
||||
|
|
@ -258,10 +258,10 @@ class InvitationsPlugin(object):
|
|||
idx += 1
|
||||
else:
|
||||
break
|
||||
if e.condition != u'conflict':
|
||||
if e.condition != 'conflict':
|
||||
raise e
|
||||
|
||||
log.info(_(u"account {jid_} created").format(jid_=jid_.full()))
|
||||
log.info(_("account {jid_} created").format(jid_=jid_.full()))
|
||||
|
||||
## profile creation
|
||||
|
||||
|
|
@ -273,66 +273,66 @@ class InvitationsPlugin(object):
|
|||
profile_key=guest_profile)
|
||||
yield self.host.memory.setParam("Password", password, "Connection",
|
||||
profile_key=guest_profile)
|
||||
name = kwargs.pop(u'name', None)
|
||||
name = kwargs.pop('name', None)
|
||||
if name is not None:
|
||||
extra[u'name'] = name
|
||||
extra['name'] = name
|
||||
try:
|
||||
id_plugin = self.host.plugins[u'IDENTITY']
|
||||
id_plugin = self.host.plugins['IDENTITY']
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
yield self.host.connect(guest_profile, password)
|
||||
guest_client = self.host.getClient(guest_profile)
|
||||
yield id_plugin.setIdentity(guest_client, {u'nick': name})
|
||||
yield id_plugin.setIdentity(guest_client, {'nick': name})
|
||||
yield self.host.disconnect(guest_profile)
|
||||
|
||||
## email
|
||||
language = kwargs.pop(u'language', None)
|
||||
language = kwargs.pop('language', None)
|
||||
if language is not None:
|
||||
extra[u'language'] = language.strip()
|
||||
extra['language'] = language.strip()
|
||||
|
||||
if email is not None:
|
||||
extra[u'email'] = email
|
||||
extra['email'] = email
|
||||
data_format.iter2dict(KEY_EMAILS_EXTRA, extra)
|
||||
url_template = kwargs.pop(u'url_template', '')
|
||||
url_template = kwargs.pop('url_template', '')
|
||||
format_args = {
|
||||
u'uuid': id_,
|
||||
u'app_name': C.APP_NAME,
|
||||
u'app_url': C.APP_URL}
|
||||
'uuid': id_,
|
||||
'app_name': C.APP_NAME,
|
||||
'app_url': C.APP_URL}
|
||||
|
||||
if name is None:
|
||||
format_args[u'name'] = email
|
||||
format_args['name'] = email
|
||||
else:
|
||||
format_args[u'name'] = name
|
||||
format_args['name'] = name
|
||||
|
||||
profile = kwargs.pop(u'profile', None)
|
||||
profile = kwargs.pop('profile', None)
|
||||
if profile is None:
|
||||
format_args[u'profile'] = u''
|
||||
format_args['profile'] = ''
|
||||
else:
|
||||
format_args[u'profile'] = extra[u'profile'] = profile
|
||||
format_args['profile'] = extra['profile'] = profile
|
||||
|
||||
host_name = kwargs.pop(u'host_name', None)
|
||||
host_name = kwargs.pop('host_name', None)
|
||||
if host_name is None:
|
||||
format_args[u'host_name'] = profile or _(u"somebody")
|
||||
format_args['host_name'] = profile or _("somebody")
|
||||
else:
|
||||
format_args[u'host_name'] = extra[u'host_name'] = host_name
|
||||
format_args['host_name'] = extra['host_name'] = host_name
|
||||
|
||||
invite_url = url_template.format(**format_args)
|
||||
format_args[u'url'] = invite_url
|
||||
format_args['url'] = invite_url
|
||||
|
||||
yield sat_email.sendEmail(
|
||||
self.host,
|
||||
[email] + emails_extra,
|
||||
(kwargs.pop(u'message_subject', None) or DEFAULT_SUBJECT).format(
|
||||
(kwargs.pop('message_subject', None) or DEFAULT_SUBJECT).format(
|
||||
**format_args),
|
||||
(kwargs.pop(u'message_body', None) or DEFAULT_BODY).format(**format_args),
|
||||
(kwargs.pop('message_body', None) or DEFAULT_BODY).format(**format_args),
|
||||
)
|
||||
|
||||
## extra data saving
|
||||
self.invitations[id_] = extra
|
||||
|
||||
if kwargs:
|
||||
log.warning(_(u"Not all arguments have been consumed: {}").format(kwargs))
|
||||
log.warning(_("Not all arguments have been consumed: {}").format(kwargs))
|
||||
|
||||
extra[KEY_ID] = id_
|
||||
extra[KEY_JID] = jid_
|
||||
|
|
@ -348,7 +348,7 @@ class InvitationsPlugin(object):
|
|||
return self.invitations[id_]
|
||||
|
||||
def _modify(self, id_, new_extra, replace):
|
||||
return self.modify(id_, {unicode(k): unicode(v) for k,v in new_extra.iteritems()},
|
||||
return self.modify(id_, {str(k): str(v) for k,v in new_extra.items()},
|
||||
replace)
|
||||
|
||||
def modify(self, id_, new_extra, replace=False):
|
||||
|
|
@ -372,9 +372,9 @@ class InvitationsPlugin(object):
|
|||
continue
|
||||
else:
|
||||
new_data = current_data
|
||||
for k,v in new_extra.iteritems():
|
||||
for k,v in new_extra.items():
|
||||
if k in EXTRA_RESERVED:
|
||||
log.warning(_(u"Skipping reserved key {key}".format(k)))
|
||||
log.warning(_("Skipping reserved key {key}".format(k)))
|
||||
continue
|
||||
if v:
|
||||
new_data[k] = v
|
||||
|
|
@ -401,9 +401,9 @@ class InvitationsPlugin(object):
|
|||
C.PROF_KEY_NONE: don't filter invitations
|
||||
@return list(unicode): invitations uids
|
||||
"""
|
||||
invitations = yield self.invitations.items()
|
||||
invitations = yield list(self.invitations.items())
|
||||
if profile != C.PROF_KEY_NONE:
|
||||
invitations = {id_:data for id_, data in invitations.iteritems()
|
||||
if data.get(u'profile') == profile}
|
||||
invitations = {id_:data for id_, data in invitations.items()
|
||||
if data.get('profile') == profile}
|
||||
|
||||
defer.returnValue(invitations)
|
||||
|
|
|
|||
Loading…
Reference in a new issue