diff sat/plugins/plugin_misc_invitations.py @ 2909:90146552cde5

core (memory), plugin XEP-0329, plugin invitation: minor style improvments
author Goffi <goffi@goffi.org>
date Sun, 14 Apr 2019 08:21:51 +0200
parents 003b8b4b56a7
children
line wrap: on
line diff
--- a/sat/plugins/plugin_misc_invitations.py	Sun Apr 14 08:21:51 2019 +0200
+++ b/sat/plugins/plugin_misc_invitations.py	Sun Apr 14 08:21:51 2019 +0200
@@ -17,20 +17,21 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import shortuuid
+from twisted.internet import defer
+from twisted.words.protocols.jabber import jid
+from twisted.words.protocols.jabber import error
 from sat.core.i18n import _, D_
 from sat.core.constants import Const as C
 from sat.core import exceptions
 from sat.core.log import getLogger
-log = getLogger(__name__)
-import shortuuid
 from sat.tools import utils
 from sat.tools.common import data_format
-from twisted.internet import defer
-from twisted.words.protocols.jabber import jid
-from twisted.words.protocols.jabber import error
 from sat.memory import persistent
 from sat.tools import email as sat_email
 
+log = getLogger(__name__)
+
 
 PLUGIN_INFO = {
     C.PI_NAME: "Invitations",
@@ -53,7 +54,8 @@
 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, KEY_GUEST_PROFILE, KEY_PASSWORD, KEY_EMAILS_EXTRA}
+EXTRA_RESERVED = {KEY_ID, KEY_JID, KEY_CREATED, u'jid_', u'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}!
 
@@ -74,26 +76,33 @@
         log.info(_(u"plugin Invitations initialization"))
         self.host = host
         self.invitations = persistent.LazyPersistentBinaryDict(u'invitations')
-        host.bridge.addMethod("invitationCreate", ".plugin", in_sign='sasssssssssa{ss}s', out_sign='a{ss}',
+        host.bridge.addMethod("invitationCreate", ".plugin", in_sign='sasssssssssa{ss}s',
+                              out_sign='a{ss}',
                               method=self._create,
                               async=True)
         host.bridge.addMethod("invitationGet", ".plugin", in_sign='s', out_sign='a{ss}',
                               method=self.get,
                               async=True)
-        host.bridge.addMethod("invitationModify", ".plugin", in_sign='sa{ss}b', out_sign='',
+        host.bridge.addMethod("invitationModify", ".plugin", in_sign='sa{ss}b',
+                              out_sign='',
                               method=self._modify,
                               async=True)
-        host.bridge.addMethod("invitationList", ".plugin", in_sign='s', out_sign='a{sa{ss}}',
+        host.bridge.addMethod("invitationList", ".plugin", in_sign='s',
+                              out_sign='a{sa{ss}}',
                               method=self._list,
                               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))))
+            raise ValueError(
+                _(u"You can't use following key(s) in extra, they are reserved: {}")
+                .format(u', '.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''):
-        # XXX: we don't use **kwargs here to keep arguments name for introspection with D-Bus bridge
+    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''):
+        # XXX: we don't use **kwargs here to keep arguments name for introspection with
+        #      D-Bus bridge
         if emails_extra is None:
             emails_extra = []
 
@@ -106,8 +115,10 @@
                   KEY_EMAILS_EXTRA: [unicode(e) for e in emails_extra]
                   }
 
-        # we need to be sure that values are unicode, else they won't be pickled correctly with D-Bus
-        for key in ("jid_", "password", "name", "host_name", "email", "language", "url_template", "message_subject", "message_body", "profile"):
+        # we need to be sure that values are unicode, else they won't be pickled correctly
+        # with D-Bus
+        for key in ("jid_", "password", "name", "host_name", "email", "language",
+                    "url_template", "message_subject", "message_body", "profile"):
             value = locals()[key]
             if value:
                 kwargs[key] = unicode(value)
@@ -120,32 +131,45 @@
 
     @defer.inlineCallbacks
     def create(self, **kwargs):
-        ur"""create an invitation
+        ur"""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 can be retrieved easily
-        **kwargs: keywords arguments which can have the following keys, unset values are equivalent to None:
-            jid_(jid.JID, None): jid to use for invitation, the jid will be created using XEP-0077
-                if the jid has no user part, an anonymous account will be used (no XMPP account created in this case)
-                if None, automatically generate an account name (in the form "invitation-[random UUID]@domain.tld") (note that this UUID is not the
-                    same as the invitation one, as jid can be used publicly (leaking the UUID), and invitation UUID give access to account.
-                in case of conflict, a suffix number is added to the account until a free one if found (with a failure if SUFFIX_MAX is reached)
-            password(unicode, None): password to use (will be used for XMPP account and profile)
+        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
+            can be retrieved easily
+        **kwargs: keywords arguments which can have the following keys, unset values are
+                  equivalent to None:
+            jid_(jid.JID, None): jid to use for invitation, the jid will be created using
+                                 XEP-0077
+                if the jid has no user part, an anonymous account will be used (no XMPP
+                    account created in this case)
+                if None, automatically generate an account name (in the form
+                    "invitation-[random UUID]@domain.tld") (note that this UUID is not the
+                    same as the invitation one, as jid can be used publicly (leaking the
+                    UUID), and invitation UUID give access to account.
+                in case of conflict, a suffix number is added to the account until a free
+                    one if found (with a failure if SUFFIX_MAX is reached)
+            password(unicode, None): password to use (will be used for XMPP account and
+                                     profile)
                 None to automatically generate one
             name(unicode, None): name of the invitee
                 will be set as profile identity if present
             host_name(unicode, None): name of the host
             email(unicode, None): email to send the invitation to
-                if None, no invitation email is sent, you can still associate email using extra
+                if None, no invitation email is sent, you can still associate email using
+                    extra
                 if email is used, extra can't have "email" key
-            language(unicode): language of the invitee (used notabily to translate the invitation)
+            language(unicode): language of the invitee (used notabily to translate the
+                               invitation)
                 TODO: not used yet
             url_template(unicode, None): template to use to construct the invitation URL
                 use {uuid} as a placeholder for identifier
-                use None if you don't want to include URL (or if it is already specified in custom message)
+                use None if you don't want to include URL (or if it is already specified
+                    in custom message)
                 /!\ you must put full URL, don't forget https://
-                /!\ the URL will give access to the invitee account, you should warn in message to not publish it publicly
-            message_subject(unicode, None): customised message body for the invitation email
+                /!\ the URL will give access to the invitee account, you should warn in
+                    message to not publish it publicly
+            message_subject(unicode, None): customised message body for the invitation
+                                            email
                 None to use default subject
                 uses the same substitution as for message_body
             message_body(unicode, None): customised message body for the invitation email
@@ -169,7 +193,8 @@
         ## initial checks
         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(
+            raise ValueError(
+                _(u"You can't use following key(s) in both args and extra: {}").format(
                 u', '.join(set(kwargs).intersection(extra))))
 
         self.checkExtra(extra)
@@ -177,10 +202,14 @@
         email = kwargs.pop(u'email', None)
         emails_extra = kwargs.pop(u'emails_extra', [])
         if not email and emails_extra:
-            raise ValueError(_(u'You need to provide a main email address before using emails_extra'))
+            raise ValueError(
+                _(u'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"))
+        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"))
 
         ## uuid
         log.info(_(u"creating an invitation"))
@@ -195,8 +224,8 @@
         #      it is needed for invitation as the same password is used for profile
         #      and SàT need to be able to automatically open the profile with the uuid
         # FIXME: we could add an extra encryption key which would be used with the uuid
-        #        when the invitee is connecting (e.g. with URL). This key would not be saved
-        #        and could be used to encrypt profile password.
+        #        when the invitee is connecting (e.g. with URL). This key would not be
+        #        saved and could be used to encrypt profile password.
         extra[KEY_PASSWORD] = password
 
         jid_ = kwargs.pop(u'jid_', None)
@@ -205,10 +234,12 @@
             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(), domain=domain)
+            jid_ = u"invitation-{uuid}@{domain}".format(uuid=shortuuid.uuid(),
+                                                        domain=domain)
         jid_ = jid.JID(jid_)
         if jid_.user:
-            # we don't register account if there is no user as anonymous login is then used
+            # we don't register account if there is no user as anonymous login is then
+            # used
             try:
                 yield self.host.plugins['XEP-0077'].registerNewAccount(jid_, password)
             except error.StanzaError as e:
@@ -218,9 +249,11 @@
                     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(jid_.full())))
+                    log.info(_(u"requested jid already exists, trying with {}".format(
+                        jid_.full())))
                     try:
-                        yield self.host.plugins['XEP-0077'].registerNewAccount(jid_, password)
+                        yield self.host.plugins['XEP-0077'].registerNewAccount(jid_,
+                                                                               password)
                     except error.StanzaError as e:
                         idx += 1
                     else:
@@ -236,8 +269,10 @@
         # profile creation should not fail as we generate unique name ourselves
         yield self.host.memory.createProfile(guest_profile, password)
         yield self.host.memory.startSession(password, guest_profile)
-        yield self.host.memory.setParam("JabberID", jid_.full(), "Connection", profile_key=guest_profile)
-        yield self.host.memory.setParam("Password", password, "Connection", profile_key=guest_profile)
+        yield self.host.memory.setParam("JabberID", jid_.full(), "Connection",
+                                        profile_key=guest_profile)
+        yield self.host.memory.setParam("Password", password, "Connection",
+                                        profile_key=guest_profile)
         name = kwargs.pop(u'name', None)
         if name is not None:
             extra[u'name'] = name
@@ -288,7 +323,8 @@
             yield sat_email.sendEmail(
                 self.host,
                 [email] + emails_extra,
-                (kwargs.pop(u'message_subject', None) or DEFAULT_SUBJECT).format(**format_args),
+                (kwargs.pop(u'message_subject', None) or DEFAULT_SUBJECT).format(
+                    **format_args),
                 (kwargs.pop(u'message_body', None) or DEFAULT_BODY).format(**format_args),
             )
 
@@ -312,7 +348,8 @@
         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()}, replace)
+        return self.modify(id_, {unicode(k): unicode(v) for k,v in new_extra.iteritems()},
+                           replace)
 
     def modify(self, id_, new_extra, replace=False):
         """Modify invitation data
@@ -366,6 +403,7 @@
         """
         invitations = yield 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.iteritems()
+                           if data.get(u'profile') == profile}
 
         defer.returnValue(invitations)