Exemplo n.º 1
0
    def validate(self, data):
        errors = ()
        invitations_nr = (data.get('users') and len(data.get('users')) or 0) +\
            (data.get('addresses') and len(data.get('addresses')) or 0)

        if invitations_nr == 0:
            # at least one invitation required
            registry = getUtility(IRegistry)
            config = registry.forInterface(IParticipationRegistry)
            if config.allow_invite_email and config.allow_invite_users:
                errors += (Invalid(_(u'Select at least one user or enter at '
                                     'least one e-mail address')),)
            elif config.allow_invite_email:
                errors += (Invalid(_(u'Enter at least one e-mail address.')),)
            elif config.allow_invite_users:
                errors += (Invalid(_(u'Select at least one user.')),)

        if IParticipationQuotaSupport.providedBy(self.context):
            # check maximum participants when quota enabled
            quota_support = IParticipationQuotaHelper(self.context)
            allowed = quota_support.allowed_number_of_invitations()
            if invitations_nr > allowed:
                if allowed <= 0:
                    msg = _(u'error_participation_quota_reached',
                            default=u'The participation quota is reached, '
                            'you cannot add any further participants.')
                else:
                    msg = _('error_too_many_participants',
                            default=u'You cannot invite so many participants '
                            'any more. Can only add ${num} more participants.',
                            mapping={'num': allowed})
                raise Invalid(msg)

        return errors
Exemplo n.º 2
0
    def prepare_comment(self, activity, obj):
        action = activity.attrs['action']
        actor_info = activity.get_actor_info()
        actor_fullname = actor_info.get('fullname').decode('utf-8')

        if action == 'participation:invitation_created':
            actor_email = activity.attrs['invitation:email'].decode('utf-8')
            roles = translate_and_join_roles(
                activity.attrs['invitation:roles'], obj, self.request)

            return _(u'activity_invitation_created_body',
                     default=u'${inviter} has invited ${mail} as ${roles}.',
                     mapping={'inviter': actor_fullname,
                              'mail': actor_email,
                              'roles': roles})

        if action == 'participation:invitation_retracted':
            actor_email = activity.attrs['invitation:email'].decode('utf-8')
            roles = translate_and_join_roles(
                activity.attrs['invitation:roles'], obj, self.request)

            return _(u'activity_invitation_retracted_body',
                     default=u'${actor} has retracted the invitation'
                     u' for ${mail}.',
                     mapping={'actor': actor_fullname,
                              'mail': actor_email})

        if action == 'participation:role_changed':
            subject_fullname = self.get_fullname_of(
                activity.attrs['roles:userid'])
            removed_roles = translate_and_join_roles(
                activity.attrs['roles:removed'], obj, self.request)
            added_roles = translate_and_join_roles(
                activity.attrs['roles:added'], obj, self.request)

            return _(u'activity_role_changed_body',
                     default=u'${actor} has changed the role of ${subject}'
                     u' from ${removed_roles} to ${added_roles}.',
                     mapping={'actor': actor_fullname,
                              'subject': subject_fullname,
                              'removed_roles': removed_roles,
                              'added_roles': added_roles})

        if action == 'participation:role_removed':
            subject_fullname = self.get_fullname_of(
                activity.attrs['roles:userid'])

            return _(u'activity_participant_removed_body',
                     default=u'${actor} has removed the'
                     u' participant ${subject}.',
                     mapping={'actor': actor_fullname,
                              'subject': subject_fullname})

        return None
Exemplo n.º 3
0
    def validate(self, roles):
        registry = getUtility(IRegistry)
        config = registry.forInterface(IParticipationRegistry)

        if not config.allow_multiple_roles and not roles:
            msg = _(u'error_no_roles', default=u'Please select a role')
            raise Invalid(msg)
Exemplo n.º 4
0
    def __call__(self, iid=None):
        """
        """
        if not iid:
            iid = self.request.get('iid')

        self.load(iid)
        notify(InvitationRejectedEvent(self.target, self.invitation))

        self.send_email()

        # add status message
        msg = _(u'info_invitation_rejected',
                default=u'You have rejected the invitation.')
        IStatusMessage(self.request).addStatusMessage(msg, type='info')

        # destroy the invitation
        self.storage.remove_invitation(self.invitation)
        del self.invitation

        # redirect back
        url = self.request.get('HTTP_REFERER',
                               os.path.join(self.context.portal_url(),
                                            '@@invitations'))
        return self.request.RESPONSE.redirect(url)
Exemplo n.º 5
0
    def handle_pending_invitations(self):
        """When the `iid` of a invitation is in the request
        (@@invitaitons?iid=bla) and the user is not authenticated, we mark this
        invitation in the session. If there is a `iid` but the user is
        authenticated we can reassign the invitation to this user.

        """
        iid = self.request.get('iid', False)
        if not iid:
            return
        invitation = self.storage.get_invitation_by_iid(iid)
        if not invitation:
            # the invitation is expired or answered
            msg = _(u'warning_invitaiton_expired',
                    default=u'The invitation has expired.')
            IStatusMessage(self.request).addStatusMessage(msg, type='warning')
            return

        if self.is_logged_in():
            # reassign to current user
            mtool = getToolByName(self.context, 'portal_membership')
            member = mtool.getAuthenticatedMember()
            new_email = member.getProperty('email', False) or member.getId()
            self.storage.reassign_invitation(invitation, new_email)
        else:
            # set pending for session
            self.storage.set_invitation_pending_for_session(invitation)
Exemplo n.º 6
0
    def get_subject(self):
        """Returns the translated subject of the email.
        """

        context_title = self.context.pretty_title_or_id().decode('utf-8')
        # -- i18ndude hint --
        if 0:
            _(u'mail_invitation_subject',
              default=u'Invitation for paticipating in ${title}',
              mapping=dict(title=context_title))
        # / -- i18ndude hint --
        # do not use translation messages - translate directly
        return translate(u'mail_invitation_subject',
                         domain='ftw.participation',
                         context=self.request,
                         default=u'Invitation for paticipating in ${title}',
                         mapping=dict(title=context_title))
Exemplo n.º 7
0
    def _validate_addresses(self, addresses):
        """E-Mail address validation
        """

        for addr in addresses:
            addr = addr.strip()
            if not self.email_expression.match(addr):
                msg = _(u'error_invalid_addresses',
                        default=u'At least one of the defined addresses '
                        'are not valid.')
                raise Invalid(msg)
Exemplo n.º 8
0
    def save_local_roles(self, data):
        # Remove all managed roles
        user_roles = get_user_local_roles(data['memberid'], self.context)
        managed_roles = extract_roles(self.context)
        filtered = filter(lambda role: role not in managed_roles, user_roles)

        # Append new roles
        filtered.extend(data['roles'])
        self.context.manage_setLocalRoles(data['memberid'], filtered)
        self.context.reindexObjectSecurity()
        msg = _(u'message_roles_changes', default=u'Changed roles')
        IStatusMessage(self.request).addStatusMessage(msg, type='info')
Exemplo n.º 9
0
 def get_subject(self):
     """Returns the translated subject of the email.
     """
     member = getToolByName(self.context,
                            'portal_membership').getAuthenticatedMember()
     fullname = member.getProperty(
         'fullname', member.getId()).decode('utf8')
     context_title = self.context.pretty_title_or_id().decode('utf-8')
     # -- i18ndude hint --
     if 0:
         _(u'mail_invitation_rejected_subject',
           default=u'The Invitation to participate in ${title} '
           u'was rejected by ${user}',
           mapping=dict(title=context_title,
                        user=fullname))
     # / -- i18ndude hint --
     # do not use translation messages - translate directly
     return translate(u'mail_invitation_rejected_subject',
                      domain='ftw.participation',
                      context=self.request,
                      default=u'The Invitation to participate in ${title} '
                      u'was rejected by ${user}',
                      mapping=dict(title=context_title,
                                   user=fullname))
Exemplo n.º 10
0
    def load(self, iid):
        """Loads storage, invitation, target, etc
        """
        self.storage = IInvitationStorage(self.context)
        self.invitation = self.storage.get_invitation_by_iid(iid)
        self.target = self.invitation.get_target()

        # sanity check
        mtool = getToolByName(self.context, 'portal_membership')
        self.member = mtool.getAuthenticatedMember()
        if not self.invitation \
                or self.invitation.inviter != self.member.getId():
            msg = _(u'error_invitation_not_found',
                    default=u'Could not find the invitation.')
            IStatusMessage(self.request).addStatusMessage(msg, type='error')
            raise Redirect(self.context.portal_url())
Exemplo n.º 11
0
    def handle_invite(self, action):
        """Invite the users: create Invitations and send email
        """
        registry = getUtility(IRegistry)
        config = registry.forInterface(IParticipationRegistry)

        data, errors = self.extractData()
        if len(errors) == 0:
            # get inviter
            mtool = getToolByName(self.context, 'portal_membership')
            inviter = mtool.getAuthenticatedMember()

            # get all addresses
            addresses = []
            if config.allow_invite_email and \
                    data.get('addresses') and len(data.get('addresses')):
                for addr in data.get('addresses').split('\n'):
                    addresses.append(addr.strip())

            if config.allow_invite_users and data.get('users'):
                for username in data['users']:
                    member = api.user.get(username=username)
                    addresses.append(member.getProperty('email'))

            # get roles
            roles = data.get('roles', [])

            # handle every email seperate
            emails = []  # used for info msg
            for email in addresses:
                email = email.strip()
                if not email:
                    continue
                inv = Invitation(self.context, email, inviter.getId(), roles)
                self.send_invitation(inv, email, inviter, data.get('comment'))
                notify(InvitationCreatedEvent(self.context, inv,
                                              data.get('comment')))
                emails.append(email)

            # notify user
            emails.sort()
            msg = _(u'info_invitations_sent',
                    default=u'The invitation mails were sent to ${emails}.',
                    mapping={'emails': ', '.join(emails), })
            IStatusMessage(self.request).addStatusMessage(msg, type='info')
            return self.redirect()
Exemplo n.º 12
0
    def __call__(self):
        form = self.request.form

        del_userids = form.get('userids', [])
        del_invitations = form.get('invitations', [])

        if form.get('form.delete') and (del_userids or del_invitations):
            self.remove_users(del_userids)
            self.remove_invitations(del_invitations)

            IStatusMessage(self.request).addStatusMessage(_(u"Changes saved."),
                                                          type='info')

        elif form.get('form.cancel'):
            return self.request.RESPONSE.redirect(self.cancel_url())

        return self.template()
Exemplo n.º 13
0
    def load(self, iid):
        """Loads the storage, the invitation and the target and does some
        more things.

        """
        self.storage = IInvitationStorage(self.context)
        self.invitation = self.storage.get_invitation_by_iid(iid)
        self.target = self.invitation.get_target()

        # sanity check
        mtool = getToolByName(self.context, 'portal_membership')
        self.member = mtool.getAuthenticatedMember()
        valid_emails = (self.member.getId(),
                        self.member.getProperty('email', object()))
        if not self.invitation or self.invitation.email not in valid_emails:
            msg = _(u'error_invitation_not_found',
                    default=u'Could not find the invitation.')
            IStatusMessage(self.request).addStatusMessage(msg, type='error')
            raise Redirect(self.context.portal_url())
Exemplo n.º 14
0
    def __call__(self, iid=None, redirect=True):
        if not iid:
            iid = self.request.get('iid')

        self.load(iid)

        self.set_participation()
        notify(InvitationAcceptedEvent(self.target, self.invitation))
        self.send_email()

        # add status message
        msg = _(u'info_invitation_accepted',
                default=u'You have accepted the invitation.')
        IStatusMessage(self.request).addStatusMessage(msg, type='info')

        # destroy the invitation
        self.storage.remove_invitation(self.invitation)
        del self.invitation

        # redirect context (where the user now has access)
        if redirect:
            return self.request.RESPONSE.redirect(self.target.absolute_url())
Exemplo n.º 15
0
def translate_and_join_roles(roles, context, request):
    roles = get_friendly_role_names(roles, context, request)
    and_ = translate(_(' and '), context=request)
    return ', '.join(roles[:-2] + [and_.join(roles[-2:])])
Exemplo n.º 16
0
    def send_email(self):
        """Sends the notification email to the invitor.
        """
        properties = getUtility(IPropertiesTool)
        mtool = getToolByName(self.context, 'portal_membership')
        # prepare from address for header
        from_str = Header(properties.email_from_name, 'utf-8')
        from_str.append(u'<%s>' % properties.email_from_address.decode('utf-8'))

        # To
        to_member = mtool.getMemberById(self.invitation.inviter)
        if not to_member.getProperty('email'):
            msg = _(u'error_inviter_email_missing',
                    default=u'Invitor could not be notified: he has '
                    'no email address defined.')
            IStatusMessage(self.request).addStatusMessage(msg, type='error')
            return
        to_str = to_member.getProperty('fullname', to_member.getId())
        if isinstance(to_str, unicode):
            to_str = to_str.encode('utf8')
        header_to = Header(to_str, 'utf-8')
        header_to.append(u'<%s>' % to_member.getProperty(
                'email').decode('utf-8'))
        # Subject
        subject = self.get_subject()
        if isinstance(subject, unicode):
            subject = subject.encode('utf8')
        header_subject = Header(subject, 'utf8')

        # Options for templated
        options = {
            'invitation': self.invitation,
            'inviter': to_member,
            'inviter_name': to_member.getProperty('fullname',
                                                  to_member.getId()),
            'invited': self.member,
            'invited_name': self.member.getProperty('fullname',
                                                    self.member.getId()),
            'invited_email': self.member.getProperty('email',
                                                     self.member.getId()),
            'target': self.target,
            }

        # make the mail
        msg = MIMEMultipart('alternative')
        msg['Subject'] = header_subject
        msg['From'] = str(from_str)
        msg['To'] = str(header_to)
        # get the body views
        html_view = self.get_mail_body_html_view()
        text_view = self.get_mail_body_text_view()

        # render and emmbed body
        text_body = text_view(**options).encode('utf-8')
        msg.attach(MIMEText(text_body, 'plain', 'utf-8'))
        html_body = html_view(**options).encode('utf-8')
        msg.attach(MIMEText(html_body, 'html', 'utf-8'))

        # send the email
        mh = getToolByName(self.context, 'MailHost')
        mh.send(msg)