Beispiel #1
0
    def clean(self):
        dt = self.cleaned_data['document_type']
        fields = self.cleaned_data['user_fields']
        cc = DocumentNotificationSubscription.get_addrs(
            self.cleaned_data.get('recipients_cc'))

        if cc:
            bad_addrrs = {addr for addr in cc if parseaddr(addr)[1] != addr}
            if bad_addrrs:
                self.add_error('recipients_cc',
                               'Invalid emails in CC: {0}'.format(bad_addrrs))

        wrong_fields = list()
        for field in fields.all():  # type: DocumentField
            if field.document_type_id != dt.pk:
                wrong_fields.append(field)

        if wrong_fields:
            self.add_error(
                'document_fields',
                'Document fields should be owned by the specified document type.\n'
                'The following fields do not match:\n'
                '{wrong_fields}'.format(wrong_fields=';\n'.join(
                    [f.long_code for f in wrong_fields])))

        return super().clean()
    def render_notification(
        package_id: str,
        subscription: DocumentNotificationSubscription,
        data: DocumentNotificationSource,
        log_routine: Optional[Callable[[str], None]] = None
    ) -> Optional[RenderedNotification]:
        if package_id in NotificationRenderer.package_already_sent_user_ids:
            already_sent_user_ids = NotificationRenderer.package_already_sent_user_ids[
                package_id]
        else:
            already_sent_user_ids = set()
            NotificationRenderer.package_already_sent_user_ids[
                package_id] = already_sent_user_ids

        document_type = data.document.document_type
        event_info = subscription.get_event_info()
        if not event_info:
            return None

        NotificationRenderer.get_document_fields(data, document_type,
                                                 subscription, data.changes)
        doc_field_values = data.field_values
        if not doc_field_values:
            return None
        display_fields = set(doc_field_values.keys())

        recipients = subscription.resolve_recipients(data.field_values)
        recipients = {
            r
            for r in recipients if r.id not in already_sent_user_ids
        } if recipients else None
        if not recipients:
            return None

        changes_filtered = dict()
        if data.changes:
            for code, old_new in data.changes.items():
                if code in FIELD_CODES_HIDE_BY_DEFAULT:
                    continue
                if old_new[0] == old_new[1] or data.field_values.get(
                        code) == old_new[0]:
                    continue
                changes_filtered[code] = old_new
        changes = changes_filtered

        display_fields.update(changes.keys())

        template_context = {
            'app_url':
            root_url(),
            'doc_url':
            doc_editor_url(document_type.code, data.document.project_id,
                           data.document.pk),
            'event_code':
            event_info.code,
            'event_title':
            event_info.title,
            'event_initiator':
            data.changed_by_user,
            'document':
            data.field_values,
            'fields': [{
                'code': h.field_code,
                'title': h.field_title,
                'type': h.field_type,
                'value': data.field_values.get(h.field_code),
                'changed': h.field_code in changes,
                'changes': changes.get(h.field_code),
            } for h in data.field_handlers if h.field_code in display_fields],
            'changes':
            changes,
            'changed_by_user':
            data.changed_by_user,
            'logo_url':
            'images/logo.png'
        }  # type: Dict[str, Any]

        subject_template = subscription.subject or event_info.default_subject
        header_template = subscription.header or event_info.default_header

        subject = Template(subject_template).render(template_context)
        header = Template(header_template).render(template_context)

        template_context.update({'subject': subject, 'header': header})

        html = None

        html_template = get_notification_template_resource(
            os.path.join(subscription.template_name, 'template.html'))
        if html_template:
            template_src = html_template.decode('utf-8')
            template_obj = Template(template_src)
            html = template_obj.render(template_context)

        txt_template_name = os.path.join(subscription.template_name,
                                         'template.txt')
        txt_template = get_notification_template_resource(txt_template_name)
        if not txt_template:
            raise RuntimeError(f'Txt template not found: {txt_template_name}')
        txt = Template(txt_template.decode('utf-8')).render(template_context)

        image_dir = os.path.join(subscription.template_name, 'images')

        return RenderedNotification(dst_users=recipients,
                                    subject=subject,
                                    txt=txt,
                                    html=html,
                                    image_dir=image_dir,
                                    cc=subscription.get_cc_addrs())
    def render_notification_pack(
            package_ids: List[str],
            subscription: DocumentNotificationSubscription,
            data: List[DocumentNotificationSource]
    ) -> List[RenderedNotification]:
        notifications_pack = []  # type: List[RenderedNotification]
        if not data:
            return notifications_pack
        event_info = subscription.get_event_info()
        if not event_info:
            return notifications_pack

        already_sent_user_ids = set()
        for pack_id in package_ids:
            if pack_id in NotificationRenderer.package_already_sent_user_ids:
                stored = NotificationRenderer.package_already_sent_user_ids[
                    pack_id]
                if stored:
                    already_sent_user_ids.update(stored)
            else:
                NotificationRenderer.package_already_sent_user_ids[
                    pack_id] = set()

        # merge message bodies
        # all the documents have the same type
        document_type = data[0].document.document_type

        template_context = {
            'app_url': root_url(),
            'event_code': event_info.code,
            'event_title': event_info.title,
            'documents': [],
            'logo_url': 'images/logo.png'
        }

        # get recipients per message, split message packs by recipients
        msgs_by_recipients = {}  # type:[str, List[DocumentNotificationSource]]
        recipients_by_key = {}  # type:[str, List[User]]
        for msg_data in data:
            NotificationRenderer.get_document_fields(msg_data, document_type,
                                                     subscription,
                                                     msg_data.changes)
            if not msg_data.field_values:
                continue

            recipients = subscription.resolve_recipients(
                msg_data.field_values)  # type:Set[User]
            recipients = {
                r
                for r in recipients if r.id not in already_sent_user_ids
            } if recipients else None
            if not recipients:
                continue
            recp_ids = [str(r.pk) for r in recipients]
            recp_ids.sort()
            recp_key = ','.join(recp_ids)
            if recp_key in msgs_by_recipients:
                msgs_by_recipients[recp_key].append(msg_data)
            else:
                msgs_by_recipients[recp_key] = [msg_data]
                recipients_by_key[recp_key] = recipients

        for recp_key in msgs_by_recipients:
            recipients = recipients_by_key[recp_key]
            for msg_data in msgs_by_recipients[recp_key]:
                doc_field_values = msg_data.field_values
                display_fields = set(doc_field_values.keys())

                changes_filtered = dict()

                if msg_data.changes:
                    for code, old_new in msg_data.changes.items():
                        if code in FIELD_CODES_HIDE_BY_DEFAULT:
                            continue
                        if old_new[0] == old_new[
                                1] or msg_data.field_values.get(
                                    code) == old_new[0]:
                            continue
                        changes_filtered[code] = old_new
                changes = changes_filtered

                display_fields.update(changes.keys())

                document_context = {
                    'doc_url':
                    doc_editor_url(document_type.code,
                                   msg_data.document.project_id,
                                   msg_data.document.pk),
                    'event_initiator':
                    msg_data.changed_by_user,
                    'document':
                    msg_data.field_values,
                    'fields': [{
                        'code': h.field_code,
                        'title': h.field_title,
                        'type': h.field_type,
                        'value': msg_data.field_values.get(h.field_code),
                        'changed': h.field_code in changes,
                        'changes': changes.get(h.field_code),
                    } for h in msg_data.field_handlers
                               if h.field_code in display_fields],
                    'changes':
                    changes,
                    'changed_by_user':
                    msg_data.changed_by_user
                }  # type: Dict[str, Any]
                template_context['documents'].append(document_context)

            html = None
            subject_template = subscription.subject or event_info.default_bulk_subject
            header_template = subscription.header or event_info.default_bulk_header

            subject = Template(subject_template).render(template_context)
            header = Template(header_template).render(template_context)

            template_context.update({'subject': subject, 'header': header})

            html_template = get_notification_template_resource(
                os.path.join(subscription.template_name, 'template_pack.html'))
            if html_template:
                html = Template(
                    html_template.decode('utf-8')).render(template_context)

            txt_template_name = os.path.join(subscription.template_name,
                                             'template_pack.txt')
            txt_template = get_notification_template_resource(
                txt_template_name)
            if not txt_template:
                raise RuntimeError(
                    'Txt template not found: {0}'.format(txt_template_name))
            txt = Template(
                txt_template.decode('utf-8')).render(template_context)

            image_dir = os.path.join(subscription.template_name, 'images')

            notification = RenderedNotification(dst_users=recipients,
                                                subject=subject,
                                                txt=txt,
                                                html=html,
                                                image_dir=image_dir,
                                                cc=subscription.get_cc_addrs())
            notifications_pack.append(notification)
        return notifications_pack