Ejemplo n.º 1
0
def _send_email(sender, recipients, subject, html, send_async=True):
    if not isinstance(recipients, list):
        recipients = list(recipients)

    if send_async and config['_mailtemplates'][
            'async_sender'] == 'tgext.celery':
        from mailtemplates.lib.celery_tasks import mailtemplates_async_send_email
        mailtemplates_async_send_email.delay(subject=subject,
                                             sender=sender,
                                             recipients=recipients,
                                             html=html)
    elif send_async and config['_mailtemplates'][
            'async_sender'] == 'tgext.asyncjob':
        from tgext.asyncjob import asyncjob_perform
        mailer = get_mailer(None)
        message = Message(subject=subject,
                          sender=sender,
                          recipients=recipients,
                          html=html)
        asyncjob_perform(mailer.send_immediately, message=message)
    else:
        try:
            mailer = get_mailer(_get_request())
            log.debug('using request mailer')
        except AttributeError:
            log.debug('using global mailer in not-async context')
            mailer = get_mailer(None)
        message = Message(subject=subject,
                          sender=sender,
                          recipients=recipients,
                          html=html)
        mailer.send_immediately(message)
Ejemplo n.º 2
0
    def notify_content_update(self, content: Content):
        # TODO: Find a way to import properly without cyclic import
        from tracim.config.app_cfg import CFG
        global_config = CFG.get_instance()

        if content.get_last_action().id not \
                in global_config.EMAIL_NOTIFICATION_NOTIFIED_EVENTS:
            logger.info(
                self,
                'Skip email notification for update of content {}'
                'by user {} (the action is {})'.format(
                    content.content_id,
                    # below: 0 means "no user"
                    self._user.user_id if self._user else 0,
                    content.get_last_action().id
                )
            )
            return

        logger.info(self,
                    'About to email-notify update'
                    'of content {} by user {}'.format(
                        content.content_id,
                        # Below: 0 means "no user"
                        self._user.user_id if self._user else 0
                    )
        )

        if content.type not \
                in global_config.EMAIL_NOTIFICATION_NOTIFIED_CONTENTS:
            logger.info(
                self,
                'Skip email notification for update of content {}'
                'by user {} (the content type is {})'.format(
                    content.type,
                    # below: 0 means "no user"
                    self._user.user_id if self._user else 0,
                    content.get_last_action().id
                )
            )
            return

        logger.info(self,
                    'About to email-notify update'
                    'of content {} by user {}'.format(
                        content.content_id,
                        # Below: 0 means "no user"
                        self._user.user_id if self._user else 0
                    )
        )

        ####
        #
        # INFO - D.A. - 2014-11-05 - Emails are sent through asynchronous jobs.
        # For that reason, we do not give SQLAlchemy objects but ids only
        # (SQLA objects are related to a given thread/session)
        #
        try:
            if global_config.EMAIL_NOTIFICATION_PROCESSING_MODE.lower()==global_config.CST.ASYNC.lower():
                logger.info(self, 'Sending email in ASYNC mode')
                # TODO - D.A - 2014-11-06
                # This feature must be implemented in order to be able to scale to large communities
                raise NotImplementedError('Sending emails through ASYNC mode is not working yet')
                asyncjob_perform(EmailNotifier(self._smtp_config, global_config).notify_content_update, self._user.user_id, content.content_id)
            else:
                logger.info(self, 'Sending email in SYNC mode')
                EmailNotifier(self._smtp_config, global_config).notify_content_update(self._user.user_id, content.content_id)
        except Exception as e:
            logger.error(self, 'Exception catched during email notification: {}'.format(e.__str__()))
Ejemplo n.º 3
0
    def notify_content_update(self, event_actor_id: int, event_content_id: int):
        """
        Look for all users to be notified about the new content and send them an individual email
        :param event_actor_id: id of the user that has triggered the event
        :param event_content_id: related content_id
        :return:
        """
        # FIXME - D.A. - 2014-11-05
        # Dirty import. It's here in order to avoid circular import
        from tracim.lib.content import ContentApi

        user = UserApi(None).get_one(event_actor_id)
        logger.debug(self, 'Content: {}'.format(event_content_id))

        content = ContentApi(user, show_archived=True, show_deleted=True).get_one(event_content_id, ContentType.Any) # TODO - use a system user instead of the user that has triggered the event
        main_content = content.parent if content.type==ContentType.Comment else content
        notifiable_roles = WorkspaceApi(user).get_notifiable_roles(content.workspace)

        if len(notifiable_roles)<=0:
            logger.info(self, 'Skipping notification as nobody subscribed to in workspace {}'.format(content.workspace.label))
            return


        logger.info(self, 'Sending asynchronous emails to {} user(s)'.format(len(notifiable_roles)))
        # INFO - D.A. - 2014-11-06
        # The following email sender will send emails in the async task queue
        # This allow to build all mails through current thread but really send them (including SMTP connection)
        # In the other thread.
        #
        # This way, the webserver will return sooner (actually before notification emails are sent
        async_email_sender = EmailSender(self._smtp_config, self._global_config.EMAIL_NOTIFICATION_ACTIVATED)

        for role in notifiable_roles:
            logger.info(self, 'Sending email to {}'.format(role.user.email))
            to_addr = '{name} <{email}>'.format(name=role.user.display_name, email=role.user.email)

            #
            #  INFO - D.A. - 2014-11-06
            # We do not use .format() here because the subject defined in the .ini file
            # may not include all required labels. In order to avoid partial format() (which result in an exception)
            # we do use replace and force the use of .__str__() in order to process LazyString objects
            #
            subject = self._global_config.EMAIL_NOTIFICATION_CONTENT_UPDATE_SUBJECT
            subject = subject.replace(EST.WEBSITE_TITLE, self._global_config.WEBSITE_TITLE.__str__())
            subject = subject.replace(EST.WORKSPACE_LABEL, main_content.workspace.label.__str__())
            subject = subject.replace(EST.CONTENT_LABEL, main_content.label.__str__())
            subject = subject.replace(EST.CONTENT_STATUS_LABEL, main_content.get_status().label.__str__())

            message = MIMEMultipart('alternative')
            message['Subject'] = subject
            message['From'] = self._global_config.EMAIL_NOTIFICATION_FROM
            message['To'] = to_addr

            body_text = self._build_email_body(self._global_config.EMAIL_NOTIFICATION_CONTENT_UPDATE_TEMPLATE_TEXT, role, content, user)



            body_html = self._build_email_body(self._global_config.EMAIL_NOTIFICATION_CONTENT_UPDATE_TEMPLATE_HTML, role, content, user)

            part1 = MIMEText(body_text, 'plain', 'utf-8')
            part2 = MIMEText(body_html, 'html', 'utf-8')
            # Attach parts into message container.
            # According to RFC 2046, the last part of a multipart message, in this case
            # the HTML message, is best and preferred.
            message.attach(part1)
            message.attach(part2)

            message_str = message.as_string()
            asyncjob_perform(async_email_sender.send_mail, message)
            # s.send_message(message)

        # Note: The following action allow to close the SMTP connection.
        # This will work only if the async jobs are done in the right order
        asyncjob_perform(async_email_sender.disconnect)
Ejemplo n.º 4
0
    def notify_created_account(
            self,
            user: User,
            password: str,
    ) -> None:
        """
        Send created account email to given user
        :param password: choosed password
        :param user: user to notify
        """
        # TODO BS 20160712: Cyclic import
        from tracim.lib.notifications import EST

        logger.debug(self, 'user: {}'.format(user.user_id))
        logger.info(self, 'Sending asynchronous email to 1 user ({0})'.format(
            user.email,
        ))

        async_email_sender = EmailSender(
            self._smtp_config,
            self._global_config.EMAIL_NOTIFICATION_ACTIVATED
        )

        subject = \
            self._global_config.EMAIL_NOTIFICATION_CREATED_ACCOUNT_SUBJECT \
            .replace(
                EST.WEBSITE_TITLE,
                self._global_config.WEBSITE_TITLE.__str__()
            )
        message = MIMEMultipart('alternative')
        message['Subject'] = subject
        message['From'] = self._global_config.EMAIL_NOTIFICATION_FROM
        message['To'] = user.email

        text_template_file_path = self._global_config.EMAIL_NOTIFICATION_CREATED_ACCOUNT_TEMPLATE_TEXT  # nopep8
        html_template_file_path = self._global_config.EMAIL_NOTIFICATION_CREATED_ACCOUNT_TEMPLATE_HTML  # nopep8

        body_text = self._render(
            mako_template_filepath=text_template_file_path,
            context={
                'user': user,
                'password': password,
                'login_url': self._global_config.WEBSITE_BASE_URL,
            }
        )

        body_html = self._render(
            mako_template_filepath=html_template_file_path,
            context={
                'user': user,
                'password': password,
                'login_url': self._global_config.WEBSITE_BASE_URL,
            }
        )

        part1 = MIMEText(body_text, 'plain', 'utf-8')
        part2 = MIMEText(body_html, 'html', 'utf-8')

        # Attach parts into message container.
        # According to RFC 2046, the last part of a multipart message,
        # in this case the HTML message, is best and preferred.
        message.attach(part1)
        message.attach(part2)

        asyncjob_perform(async_email_sender.send_mail, message)

        # Note: The following action allow to close the SMTP connection.
        # This will work only if the async jobs are done in the right order
        asyncjob_perform(async_email_sender.disconnect)
Ejemplo n.º 5
0
    def notify_content_update(self, content: Content):
        # TODO: Find a way to import properly without cyclic import
        from tracim.config.app_cfg import CFG
        global_config = CFG.get_instance()

        if content.get_last_action().id not \
                in global_config.EMAIL_NOTIFICATION_NOTIFIED_EVENTS:
            logger.info(
                self,
                'Skip email notification for update of content {}'
                'by user {} (the action is {})'.format(
                    content.content_id,
                    # below: 0 means "no user"
                    self._user.user_id if self._user else 0,
                    content.get_last_action().id))
            return

        logger.info(
            self,
            'About to email-notify update'
            'of content {} by user {}'.format(
                content.content_id,
                # Below: 0 means "no user"
                self._user.user_id if self._user else 0))

        if content.type not \
                in global_config.EMAIL_NOTIFICATION_NOTIFIED_CONTENTS:
            logger.info(
                self,
                'Skip email notification for update of content {}'
                'by user {} (the content type is {})'.format(
                    content.type,
                    # below: 0 means "no user"
                    self._user.user_id if self._user else 0,
                    content.get_last_action().id))
            return

        logger.info(
            self,
            'About to email-notify update'
            'of content {} by user {}'.format(
                content.content_id,
                # Below: 0 means "no user"
                self._user.user_id if self._user else 0))

        ####
        #
        # INFO - D.A. - 2014-11-05 - Emails are sent through asynchronous jobs.
        # For that reason, we do not give SQLAlchemy objects but ids only
        # (SQLA objects are related to a given thread/session)
        #
        try:
            if global_config.EMAIL_NOTIFICATION_PROCESSING_MODE.lower(
            ) == global_config.CST.ASYNC.lower():
                logger.info(self, 'Sending email in ASYNC mode')
                # TODO - D.A - 2014-11-06
                # This feature must be implemented in order to be able to scale to large communities
                raise NotImplementedError(
                    'Sending emails through ASYNC mode is not working yet')
                asyncjob_perform(
                    EmailNotifier(self._smtp_config,
                                  global_config).notify_content_update,
                    self._user.user_id, content.content_id)
            else:
                logger.info(self, 'Sending email in SYNC mode')
                EmailNotifier(self._smtp_config,
                              global_config).notify_content_update(
                                  self._user.user_id, content.content_id)
        except Exception as e:
            logger.error(
                self, 'Exception catched during email notification: {}'.format(
                    e.__str__()))
Ejemplo n.º 6
0
    def notify_content_update(self, event_actor_id: int,
                              event_content_id: int):
        """
        Look for all users to be notified about the new content and send them an individual email
        :param event_actor_id: id of the user that has triggered the event
        :param event_content_id: related content_id
        :return:
        """
        # FIXME - D.A. - 2014-11-05
        # Dirty import. It's here in order to avoid circular import
        from tracim.lib.content import ContentApi

        user = UserApi(None).get_one(event_actor_id)
        logger.debug(self, 'Content: {}'.format(event_content_id))

        content = ContentApi(
            user, show_archived=True, show_deleted=True
        ).get_one(
            event_content_id, ContentType.Any
        )  # TODO - use a system user instead of the user that has triggered the event
        main_content = content.parent if content.type == ContentType.Comment else content
        notifiable_roles = WorkspaceApi(user).get_notifiable_roles(
            content.workspace)

        if len(notifiable_roles) <= 0:
            logger.info(
                self,
                'Skipping notification as nobody subscribed to in workspace {}'
                .format(content.workspace.label))
            return

        logger.info(
            self, 'Sending asynchronous emails to {} user(s)'.format(
                len(notifiable_roles)))
        # INFO - D.A. - 2014-11-06
        # The following email sender will send emails in the async task queue
        # This allow to build all mails through current thread but really send them (including SMTP connection)
        # In the other thread.
        #
        # This way, the webserver will return sooner (actually before notification emails are sent
        async_email_sender = EmailSender(
            self._smtp_config,
            self._global_config.EMAIL_NOTIFICATION_ACTIVATED)

        for role in notifiable_roles:
            logger.info(self, 'Sending email to {}'.format(role.user.email))
            to_addr = '{name} <{email}>'.format(name=role.user.display_name,
                                                email=role.user.email)

            #
            #  INFO - D.A. - 2014-11-06
            # We do not use .format() here because the subject defined in the .ini file
            # may not include all required labels. In order to avoid partial format() (which result in an exception)
            # we do use replace and force the use of .__str__() in order to process LazyString objects
            #
            subject = self._global_config.EMAIL_NOTIFICATION_CONTENT_UPDATE_SUBJECT
            subject = subject.replace(
                EST.WEBSITE_TITLE, self._global_config.WEBSITE_TITLE.__str__())
            subject = subject.replace(EST.WORKSPACE_LABEL,
                                      main_content.workspace.label.__str__())
            subject = subject.replace(
                EST.CONTENT_LABEL,
                main_content.label.__str__()
                if main_content.label else main_content.file_name.__str__())
            subject = subject.replace(
                EST.CONTENT_STATUS_LABEL,
                main_content.get_status().label.__str__())

            message = MIMEMultipart('alternative')
            message['Subject'] = subject
            message['From'] = self._global_config.EMAIL_NOTIFICATION_FROM
            message['To'] = to_addr

            body_text = self._build_email_body(
                self._global_config.
                EMAIL_NOTIFICATION_CONTENT_UPDATE_TEMPLATE_TEXT, role, content,
                user)

            body_html = self._build_email_body(
                self._global_config.
                EMAIL_NOTIFICATION_CONTENT_UPDATE_TEMPLATE_HTML, role, content,
                user)

            part1 = MIMEText(body_text, 'plain', 'utf-8')
            part2 = MIMEText(body_html, 'html', 'utf-8')
            # Attach parts into message container.
            # According to RFC 2046, the last part of a multipart message, in this case
            # the HTML message, is best and preferred.
            message.attach(part1)
            message.attach(part2)

            message_str = message.as_string()
            asyncjob_perform(async_email_sender.send_mail, message)
            # s.send_message(message)

        # Note: The following action allow to close the SMTP connection.
        # This will work only if the async jobs are done in the right order
        asyncjob_perform(async_email_sender.disconnect)
Ejemplo n.º 7
0
    return tg.request


def _send_email(sender, recipients, subject, html, async=True):
    if not isinstance(recipients, list):
        recipients = list(recipients)

    if async and config['_mailtemplates']['async_sender'] == 'tgext.celery':
        from mailtemplates.lib.celery_tasks import mailtemplates_async_send_email
        mailtemplates_async_send_email.delay(subject=subject, sender=sender,
                                             recipients=recipients, html=html)
    elif async and config['_mailtemplates']['async_sender'] == 'tgext.asyncjob':
        from tgext.asyncjob import asyncjob_perform
        mailer = get_mailer(None)
        message = Message(subject=subject, sender=sender, recipients=recipients, html=html)
        asyncjob_perform(mailer.send_immediately, message=message)
    else:
        mailer = get_mailer(_get_request())
        message = Message(subject=subject, sender=sender, recipients=recipients, html=html)
        mailer.send_immediately(message)


def _get_variables_for_template(tmpl):
    global_vars = []
    for elem in dir(tmpl):
        if elem.startswith('_kj_block') or elem == '__main__':
            global_vars += _get_variables_for_block(tmpl, elem)
    return global_vars


def _get_globals_py2(func):
Ejemplo n.º 8
0
    def notify_created_account(
        self,
        user: User,
        password: str,
    ) -> None:
        """
        Send created account email to given user
        :param password: choosed password
        :param user: user to notify
        """
        # TODO BS 20160712: Cyclic import
        from tracim.lib.notifications import EST

        logger.debug(self, 'user: {}'.format(user.user_id))
        logger.info(
            self,
            'Sending asynchronous email to 1 user ({0})'.format(user.email, ))

        async_email_sender = EmailSender(
            self._smtp_config,
            self._global_config.EMAIL_NOTIFICATION_ACTIVATED)

        subject = \
            self._global_config.EMAIL_NOTIFICATION_CREATED_ACCOUNT_SUBJECT \
            .replace(
                EST.WEBSITE_TITLE,
                self._global_config.WEBSITE_TITLE.__str__()
            )
        message = MIMEMultipart('alternative')
        message['Subject'] = subject
        message['From'] = self._global_config.EMAIL_NOTIFICATION_FROM
        message['To'] = user.email

        text_template_file_path = self._global_config.EMAIL_NOTIFICATION_CREATED_ACCOUNT_TEMPLATE_TEXT  # nopep8
        html_template_file_path = self._global_config.EMAIL_NOTIFICATION_CREATED_ACCOUNT_TEMPLATE_HTML  # nopep8

        body_text = self._render(
            mako_template_filepath=text_template_file_path,
            context={
                'user': user,
                'password': password,
                'login_url': self._global_config.WEBSITE_BASE_URL,
            })

        body_html = self._render(
            mako_template_filepath=html_template_file_path,
            context={
                'user': user,
                'password': password,
                'login_url': self._global_config.WEBSITE_BASE_URL,
            })

        part1 = MIMEText(body_text, 'plain', 'utf-8')
        part2 = MIMEText(body_html, 'html', 'utf-8')

        # Attach parts into message container.
        # According to RFC 2046, the last part of a multipart message,
        # in this case the HTML message, is best and preferred.
        message.attach(part1)
        message.attach(part2)

        asyncjob_perform(async_email_sender.send_mail, message)

        # Note: The following action allow to close the SMTP connection.
        # This will work only if the async jobs are done in the right order
        asyncjob_perform(async_email_sender.disconnect)