Exemplo n.º 1
0
 def _execute_command_lead(self, **kwargs):
     partner = self.env.user.partner_id
     key = kwargs['body']
     channel_partners = self.env['mail.channel.partner'].search(
         [('partner_id', '!=', partner.id), ('channel_id', '=', self.id)],
         limit=1)
     if key.strip() == '/lead':
         msg = self._define_command_lead()['help']
     else:
         description = ''.join(
             '%s: %s\n' %
             (message.author_id.name or self.anonymous_name, message.body)
             for message in self.channel_message_ids.sorted('id'))
         lead = self.env['crm.lead'].create({
             'name':
             html2plaintext(key[5:]),
             'partner_id':
             channel_partners.partner_id.id,
             'user_id':
             None,
             'team_id':
             None,
             'description':
             html2plaintext(description),
             'referred':
             partner.name
         })
         lead._onchange_partner_id()
         msg = _(
             'Created a new lead: <a href="#" data-oe-id="%s" data-oe-model="crm.lead">%s</a>'
         ) % (lead.id, lead.name)
     self._send_transient_message(partner, msg)
Exemplo n.º 2
0
 def _compute_teaser(self):
     for blog_post in self:
         if blog_post.teaser_manual:
             blog_post.teaser = blog_post.teaser_manual
         else:
             content = html2plaintext(blog_post.content).replace('\n', ' ')
             blog_post.teaser = content[:150] + '...'
Exemplo n.º 3
0
 def _compute_description(self):
     for message in self:
         if message.subject:
             message.description = message.subject
         else:
             plaintext_ct = '' if not message.body else html2plaintext(message.body)
             message.description = plaintext_ct[:30] + '%s' % (' [...]' if len(plaintext_ct) >= 30 else '')
Exemplo n.º 4
0
    def pad_generate_url(self):
        company = self.env.user.sudo().company_id

        pad = {
            "server": company.pad_server,
            "key": company.pad_key,
        }

        # make sure pad server in the form of http://hostname
        if not pad["server"]:
            return pad
        if not pad["server"].startswith('http'):
            pad["server"] = 'http://' + pad["server"]
        pad["server"] = pad["server"].rstrip('/')
        # generate a salt
        s = string.ascii_uppercase + string.digits
        salt = ''.join([
            s[random.SystemRandom().randint(0,
                                            len(s) - 1)] for i in range(10)
        ])
        # path
        # etherpad hardcodes pad id length limit to 50
        path = '-%s-%s' % (self._name, salt)
        path = '%s%s' % (self.env.cr.dbname.replace(
            '_', '-')[0:50 - len(path)], path)
        # contruct the url
        url = '%s/p/%s' % (pad["server"], path)

        # if create with content
        if self.env.context.get('field_name') and self.env.context.get(
                'model') and self.env.context.get('object_id'):
            myPad = EtherpadLiteClient(pad["key"], pad["server"] + '/api')
            try:
                myPad.createPad(path)
            except IOError:
                raise UserError(
                    _("Pad creation failed, either there is a problem with your pad server URL or with your connection."
                      ))

            # get attr on the field model
            model = self.env[self.env.context["model"]]
            field = model._fields[self.env.context['field_name']]
            real_field = field.pad_content_field

            # get content of the real field
            for record in model.browse([self.env.context["object_id"]]):
                if record[real_field]:
                    myPad.setText(
                        path,
                        (html2plaintext(record[real_field]).encode('utf-8')))
                    # Etherpad for html not functional
                    # myPad.setHTML(path, record[real_field])

        return {
            "server": pad["server"],
            "path": path,
            "url": url,
        }
Exemplo n.º 5
0
 def setHtmlFallbackText(self, padID, html):
     try:
         # Prevents malformed HTML errors
         html_wellformed = '<html><body>' + html + '</body></html>'
         return self.setHtml(padID, html_wellformed)
     except Exception:
         _logger.exception(
             'Falling back to setText. SetHtml failed with message:')
         return self.setText(padID, html2plaintext(html).encode('UTF-8'))
Exemplo n.º 6
0
 def _compute_teaser(self):
     for blog_post in self:
         if blog_post.teaser_manual:
             blog_post.teaser = blog_post.teaser_manual
         else:
             content = html2plaintext(blog_post.content).replace('\n', ' ')
             blog_post.teaser = ' '.join(
                 itertools.islice(
                     (c for c in content.split(' ') if c), 50)) + '...'
Exemplo n.º 7
0
    def assertSMSNotification(self, recipients_info, content, messages=None, check_sms=True, sent_unlink=False):
        """ Check content of notifications.

          :param recipients_info: list[{
            'partner': res.partner record (may be empty),
            'number': number used for notification (may be empty, computed based on partner),
            'state': ready / sent / exception / canceled (sent by default),
            'failure_type': optional: sms_number_missing / sms_number_format / sms_credit / sms_server
            }, { ... }]
        """
        partners = self.env['res.partner'].concat(*list(p['partner'] for p in recipients_info if p.get('partner')))
        numbers = [p['number'] for p in recipients_info if p.get('number')]
        # special case of void notifications: check for False / False notifications
        if not partners and not numbers:
            numbers = [False]
        base_domain = [
            '|', ('res_partner_id', 'in', partners.ids),
            '&', ('res_partner_id', '=', False), ('sms_number', 'in', numbers),
            ('notification_type', '=', 'sms')
        ]
        if messages is not None:
            base_domain += [('mail_message_id', 'in', messages.ids)]
        notifications = self.env['mail.notification'].search(base_domain)

        self.assertEqual(notifications.mapped('res_partner_id'), partners)

        for recipient_info in recipients_info:
            partner = recipient_info.get('partner', self.env['res.partner'])
            number = recipient_info.get('number')
            state = recipient_info.get('state', 'sent')
            if number is None and partner:
                number = partner.phone_get_sanitized_number()

            notif = notifications.filtered(lambda n: n.res_partner_id == partner and n.sms_number == number and n.notification_status == state)
            self.assertTrue(notif, 'SMS: not found notification for %s (number: %s, state: %s)' % (partner, number, state))

            if state not in ('sent', 'ready', 'canceled'):
                self.assertEqual(notif.failure_type, recipient_info['failure_type'])
            if check_sms:
                if state == 'sent':
                    if sent_unlink:
                        self.assertSMSIapSent([number], content=content)
                    else:
                        self.assertSMS(partner, number, 'sent', content=content)
                elif state == 'ready':
                    self.assertSMS(partner, number, 'outgoing', content=content)
                elif state == 'exception':
                    self.assertSMS(partner, number, 'error', error_code=recipient_info['failure_type'], content=content)
                elif state == 'canceled':
                    self.assertSMS(partner, number, 'canceled', error_code=recipient_info['failure_type'], content=content)
                else:
                    raise NotImplementedError('Not implemented')

        if messages is not None:
            for message in messages:
                self.assertEqual(content, tools.html2plaintext(message.body).rstrip('\n'))
Exemplo n.º 8
0
    def _convert_visitor_to_lead(self, partner, channel_partners, key):
        """ Create a lead from channel /lead command
        :param partner: internal user partner (operator) that created the lead;
        :param channel_partners: channel members;
        :param key: operator input in chat ('/lead Lead about Product')
        """
        description = ''.join(
            '%s: %s\n' %
            (message.author_id.name or self.anonymous_name, message.body)
            for message in self.channel_message_ids.sorted('id'))
        # if public user is part of the chat: consider lead to be linked to an
        # anonymous user whatever the participants. Otherwise keep only share
        # partners (no user or portal user) to link to the lead.
        customers = self.env['res.partner']
        for customer in channel_partners.partner_id.filtered(
                'partner_share').with_context(active_test=False):
            if customer.user_ids and all(user._is_public()
                                         for user in customer.user_ids):
                customers = self.env['res.partner']
                break
            else:
                customers |= customer

        utm_source = self.env.ref('crm_livechat.utm_source_livechat',
                                  raise_if_not_found=False)
        return self.env['crm.lead'].create({
            'name':
            html2plaintext(key[5:]),
            'partner_id':
            customers[0].id if customers else False,
            'user_id':
            False,
            'team_id':
            False,
            'description':
            html2plaintext(description),
            'referred':
            partner.name,
            'source_id':
            utm_source and utm_source.id,
        })
Exemplo n.º 9
0
    def _message_sms(self,
                     body,
                     subtype_id=False,
                     partner_ids=False,
                     number_field=False,
                     sms_numbers=None,
                     sms_pid_to_number=None,
                     **kwargs):
        """ Main method to post a message on a record using SMS-based notification
        method.

        :param body: content of SMS;
        :param subtype_id: mail.message.subtype used in mail.message associated
          to the sms notification process;
        :param partner_ids: if set is a record set of partners to notify;
        :param number_field: if set is a name of field to use on current record
          to compute a number to notify;
        :param sms_numbers: see ``_notify_record_by_sms``;
        :param sms_pid_to_number: see ``_notify_record_by_sms``;
        """
        self.ensure_one()
        sms_pid_to_number = sms_pid_to_number if sms_pid_to_number is not None else {}

        if number_field or (partner_ids is False and sms_numbers is None):
            info = self._sms_get_recipients_info(
                force_field=number_field)[self.id]
            info_partner_ids = info['partner'].ids if info['partner'] else False
            info_number = info['sanitized'] if info['sanitized'] else info[
                'number']
            if info_partner_ids and info_number:
                sms_pid_to_number[info_partner_ids[0]] = info_number
            if info_partner_ids:
                partner_ids = info_partner_ids + (partner_ids or [])
            if not info_partner_ids:
                if info_number:
                    sms_numbers = [info_number] + (sms_numbers or [])
                    # will send a falsy notification allowing to fix it through SMS wizards
                elif not sms_numbers:
                    sms_numbers = [False]

        if subtype_id is False:
            subtype_id = self.env['ir.model.data'].xmlid_to_res_id(
                'mail.mt_note')

        return self.message_post(
            body=plaintext2html(html2plaintext(body)),
            partner_ids=partner_ids
            or [],  # TDE FIXME: temp fix otherwise crash mail_thread.py
            message_type='sms',
            subtype_id=subtype_id,
            sms_numbers=sms_numbers,
            sms_pid_to_number=sms_pid_to_number,
            **kwargs)
Exemplo n.º 10
0
 def message_new(self, msg, custom_values=None):
     if custom_values is None:
         custom_values = {}
     desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
     defaults = {
         'name': msg.get('subject') or _("No Subject"),
         'description': desc,
         'email_from': msg.get('from'),
         'email_cc': msg.get('cc'),
         'partner_id': msg.get('author_id', False),
     }
     if msg.get('priority'):
         defaults['priority'] = msg.get('priority')
     defaults.update(custom_values)
     return super(crm_claim, self).message_new(msg, custom_values=defaults)
Exemplo n.º 11
0
    def send_get_email_dict(self, partner=None):
        """Return a dictionary for specific email values, depending on a
        partner, or generic to the whole recipients given by mail.email_to.

            :param Model partner: specific recipient partner
        """
        self.ensure_one()
        body = self.send_get_mail_body(partner=partner)
        body_alternative = tools.html2plaintext(body)
        res = {
            'body': body,
            'body_alternative': body_alternative,
            'email_to': self.send_get_mail_to(partner=partner),
        }
        return res
Exemplo n.º 12
0
 def _get_discussion_detail(self, ids, publish=False, **post):
     values = []
     for message in request.env['mail.message'].sudo().browse(ids):
         values.append({
             "id": message.id,
             "author_name": message.author_id.name,
             "author_image": message.author_id.image and \
                 (b"data:image/png;base64,%s" % message.author_id.image) or \
                 b'/website_blog/static/src/img/anonymous.png',
             "date": message.date,
             'body': html2plaintext(message.body),
             'website_published' : message.website_published,
             'publish' : publish,
         })
     return values
Exemplo n.º 13
0
    def _set_pad_value(self, vals):

        # Update the pad if the `pad_content_field` is modified
        for k, field in self._fields.items():
            if hasattr(field, 'pad_content_field') and vals.get(field.pad_content_field) and self[k]:
                company = self.env.user.sudo().company_id
                myPad = EtherpadLiteClient(company.pad_key, company.pad_server + '/api')
                path = self[k].split('/p/')[1]
                myPad.setText(path, (html2plaintext(vals[field.pad_content_field]).encode('utf-8')))

        # Update the `pad_content_field` if the pad is modified
        for k, v in list(vals.items()):
            field = self._fields[k]
            if hasattr(field, 'pad_content_field'):
                vals[field.pad_content_field] = self.pad_get_content(v)
Exemplo n.º 14
0
 def action_create_calendar_event(self):
     self.ensure_one()
     action = self.env.ref('calendar.action_calendar_event').read()[0]
     action['context'] = {
         'default_activity_type_id':
         self.activity_type_id.id,
         'default_res_id':
         self.env.context.get('default_res_id'),
         'default_res_model':
         self.env.context.get('default_res_model'),
         'default_name':
         self.summary,
         'default_description':
         self.note and tools.html2plaintext(self.note) or '',
         'default_activity_ids': [(6, 0, self.ids)],
     }
     return action
Exemplo n.º 15
0
 def action_create_calendar_event(self):
     self.ensure_one()
     action = self.env["ir.actions.actions"]._for_xml_id(
         "calendar.action_calendar_event")
     action['context'] = {
         'default_activity_type_id':
         self.activity_type_id.id,
         'default_res_id':
         self.env.context.get('default_res_id'),
         'default_res_model':
         self.env.context.get('default_res_model'),
         'default_name':
         self.summary or self.res_name,
         'default_description':
         self.note and tools.html2plaintext(self.note).strip() or '',
         'default_activity_ids': [(6, 0, self.ids)],
     }
     return action
Exemplo n.º 16
0
    def _send_prepare_values(self, partner=None):
        """Return a dictionary for specific email values, depending on a
        partner, or generic to the whole recipients given by mail.email_to.

            :param Model partner: specific recipient partner
        """
        self.ensure_one()
        body = self._send_prepare_body()
        body_alternative = tools.html2plaintext(body)
        if partner:
            email_to = [
                tools.formataddr((partner.name or 'False', partner.email
                                  or 'False'))
            ]
        else:
            email_to = tools.email_split_and_format(self.email_to)
        res = {
            'body': body,
            'body_alternative': body_alternative,
            'email_to': email_to,
        }
        return res
Exemplo n.º 17
0
    def _mark_done(self):
        """ Will add certification to employee's resumé if
        - The survey is a certification
        - The user is linked to an employee
        - The user succeeded the test """

        super(SurveyUserInput, self)._mark_done()

        certification_user_inputs = self.filtered(lambda user_input: user_input.survey_id.certification and user_input.scoring_success)
        partner_has_completed = {user_input.partner_id.id: user_input.survey_id for user_input in certification_user_inputs}
        employees = self.env['hr.employee'].sudo().search([('user_id.partner_id', 'in', certification_user_inputs.mapped('partner_id').ids)])
        for employee in employees:
            line_type = self.env.ref('hr_skills_survey.resume_type_certification', raise_if_not_found=False)
            survey = partner_has_completed.get(employee.user_id.partner_id.id)
            self.env['hr.resume.line'].create({
                'employee_id': employee.id,
                'name': survey.title,
                'date_start': fields.Date.today(),
                'date_end': fields.Date.today(),
                'description': html2plaintext(survey.description),
                'line_type_id': line_type and line_type.id,
                'display_type': 'certification',
                'survey_id': survey.id
            })
Exemplo n.º 18
0
    def _notify_record_by_sms(self,
                              message,
                              recipients_data,
                              msg_vals=False,
                              sms_numbers=None,
                              sms_pid_to_number=None,
                              check_existing=False,
                              put_in_queue=False,
                              **kwargs):
        """ Notification method: by SMS.

        :param message: mail.message record to notify;
        :param recipients_data: see ``_notify_thread``;
        :param msg_vals: see ``_notify_thread``;

        :param sms_numbers: additional numbers to notify in addition to partners
          and classic recipients;
        :param pid_to_number: force a number to notify for a given partner ID
              instead of taking its mobile / phone number;
        :param check_existing: check for existing notifications to update based on
          mailed recipient, otherwise create new notifications;
        :param put_in_queue: use cron to send queued SMS instead of sending them
          directly;
        """
        sms_pid_to_number = sms_pid_to_number if sms_pid_to_number is not None else {}
        sms_numbers = sms_numbers if sms_numbers is not None else []
        sms_create_vals = []
        sms_all = self.env['sms.sms'].sudo()

        # pre-compute SMS data
        body = msg_vals['body'] if msg_vals and msg_vals.get(
            'body') else message.body
        sms_base_vals = {
            'body': html2plaintext(body),
            'mail_message_id': message.id,
            'state': 'outgoing',
        }

        # notify from computed recipients_data (followers, specific recipients)
        partners_data = [
            r for r in recipients_data['partners'] if r['notif'] == 'sms'
        ]
        partner_ids = [r['id'] for r in partners_data]
        if partner_ids:
            for partner in self.env['res.partner'].sudo().browse(partner_ids):
                number = sms_pid_to_number.get(
                    partner.id) or partner.mobile or partner.phone
                sanitize_res = phone_validation.phone_sanitize_numbers_w_record(
                    [number], partner)[number]
                number = sanitize_res['sanitized'] or number
                sms_create_vals.append(
                    dict(sms_base_vals, partner_id=partner.id, number=number))

        # notify from additional numbers
        if sms_numbers:
            sanitized = phone_validation.phone_sanitize_numbers_w_record(
                sms_numbers, self)
            tocreate_numbers = [
                value['sanitized'] or original
                for original, value in sanitized.items()
            ]
            sms_create_vals += [
                dict(
                    sms_base_vals,
                    partner_id=False,
                    number=n,
                    state='outgoing' if n else 'error',
                    error_code='' if n else 'sms_number_missing',
                ) for n in tocreate_numbers
            ]

        # create sms and notification
        existing_pids, existing_numbers = [], []
        if sms_create_vals:
            sms_all |= self.env['sms.sms'].sudo().create(sms_create_vals)

            if check_existing:
                existing = self.env['mail.notification'].sudo().search([
                    '|', ('res_partner_id', 'in', partner_ids), '&',
                    ('res_partner_id', '=', False),
                    ('sms_number', 'in', sms_numbers),
                    ('notification_type', '=', 'sms'),
                    ('mail_message_id', '=', message.id)
                ])
                for n in existing:
                    if n.res_partner_id.id in partner_ids and n.mail_message_id == message:
                        existing_pids.append(n.res_partner_id.id)
                    if not n.res_partner_id and n.sms_number in sms_numbers and n.mail_message_id == message:
                        existing_numbers.append(n.sms_number)

            notif_create_values = [
                {
                    'mail_message_id':
                    message.id,
                    'res_partner_id':
                    sms.partner_id.id,
                    'sms_number':
                    sms.number,
                    'notification_type':
                    'sms',
                    'sms_id':
                    sms.id,
                    'is_read':
                    True,  # discard Inbox notification
                    'notification_status':
                    'ready' if sms.state == 'outgoing' else 'exception',
                    'failure_type':
                    '' if sms.state == 'outgoing' else sms.error_code,
                } for sms in sms_all
                if (sms.partner_id and sms.partner_id.id not in existing_pids)
                or (not sms.partner_id and sms.number not in existing_numbers)
            ]
            if notif_create_values:
                self.env['mail.notification'].sudo().create(
                    notif_create_values)

            if existing_pids or existing_numbers:
                for sms in sms_all:
                    notif = next(
                        (n for n in existing
                         if (n.res_partner_id.id in existing_pids
                             and n.res_partner_id.id == sms.partner_id.id) or
                         (not n.res_partner_id and n.sms_number in
                          existing_numbers and n.sms_number == sms.number)),
                        False)
                    if notif:
                        notif.write({
                            'notification_type': 'sms',
                            'notification_status': 'ready',
                            'sms_id': sms.id,
                            'sms_number': sms.number,
                        })

        if sms_all and not put_in_queue:
            sms_all.filtered(lambda sms: sms.state == 'outgoing').send(
                auto_commit=False, raise_exception=False)

        return True
Exemplo n.º 19
0
 def name_get(self):
     return [(ribbon.id,
              '%s (#%d)' % (tools.html2plaintext(ribbon.html), ribbon.id))
             for ribbon in self]
Exemplo n.º 20
0
 def _get_plain_content(self):
     self.plain_content = tools.html2plaintext(self.content)[0:500] if self.content else False
Exemplo n.º 21
0
 def assertSMSLogged(self, records, body):
     for record in records:
         message = record.message_ids[-1]
         self.assertEqual(message.subtype_id, self.env.ref('mail.mt_note'))
         self.assertEqual(message.message_type, 'sms')
         self.assertEqual(tools.html2plaintext(message.body).rstrip('\n'), body)
Exemplo n.º 22
0
 def _compute_name(self):
     """ Read the first line of the memo to determine the note name """
     for note in self:
         text = html2plaintext(note.memo) if note.memo else ''
         note.name = text.strip().replace('*', '').split("\n")[0]
Exemplo n.º 23
0
    def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False,
                    attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None,
                    body_alternative=None, subtype_alternative='plain'):
        """Constructs an RFC2822 email.message.Message object based on the keyword arguments passed, and returns it.

           :param string email_from: sender email address
           :param list email_to: list of recipient addresses (to be joined with commas)
           :param string subject: email subject (no pre-encoding/quoting necessary)
           :param string body: email body, of the type ``subtype`` (by default, plaintext).
                               If html subtype is used, the message will be automatically converted
                               to plaintext and wrapped in multipart/alternative, unless an explicit
                               ``body_alternative`` version is passed.
           :param string body_alternative: optional alternative body, of the type specified in ``subtype_alternative``
           :param string reply_to: optional value of Reply-To header
           :param string object_id: optional tracking identifier, to be included in the message-id for
                                    recognizing replies. Suggested format for object-id is "res_id-model",
                                    e.g. "12345-crm.lead".
           :param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'),
                                  must match the format of the ``body`` parameter. Default is 'plain',
                                  making the content part of the mail "text/plain".
           :param string subtype_alternative: optional mime subtype of ``body_alternative`` (usually 'plain'
                                              or 'html'). Default is 'plain'.
           :param list attachments: list of (filename, filecontents) pairs, where filecontents is a string
                                    containing the bytes of the attachment
           :param list email_cc: optional list of string values for CC header (to be joined with commas)
           :param list email_bcc: optional list of string values for BCC header (to be joined with commas)
           :param dict headers: optional map of headers to set on the outgoing mail (may override the
                                other headers, including Subject, Reply-To, Message-Id, etc.)
           :rtype: email.message.EmailMessage
           :return: the new RFC2822 email message
        """
        email_from = email_from or self._get_default_from_address()
        assert email_from, "You must either provide a sender address explicitly or configure "\
                           "using the combination of `mail.catchall.domain` and `mail.default.from` "\
                           "ICPs, in the server configuration file or with the "\
                           "--email-from startup parameter."

        headers = headers or {}         # need valid dict later
        email_cc = email_cc or []
        email_bcc = email_bcc or []
        body = body or u''

        msg = EmailMessage(policy=email.policy.SMTP)
        msg.set_charset('utf-8')

        if not message_id:
            if object_id:
                message_id = tools.generate_tracking_message_id(object_id)
            else:
                message_id = make_msgid()
        msg['Message-Id'] = message_id
        if references:
            msg['references'] = references
        msg['Subject'] = subject

        email_from, return_path = self._get_email_from(email_from)
        msg['From'] = email_from
        if return_path:
            headers.setdefault('Return-Path', return_path)

        del msg['Reply-To']
        msg['Reply-To'] = reply_to or email_from
        msg['To'] = email_to
        if email_cc:
            msg['Cc'] = email_cc
        if email_bcc:
            msg['Bcc'] = email_bcc
        msg['Date'] = datetime.datetime.utcnow()
        for key, value in headers.items():
            msg[pycompat.to_text(ustr(key))] = value

        email_body = ustr(body)
        if subtype == 'html' and not body_alternative:
            msg.add_alternative(tools.html2plaintext(email_body), subtype='plain', charset='utf-8')
            msg.add_alternative(email_body, subtype=subtype, charset='utf-8')
        elif body_alternative:
            msg.add_alternative(ustr(body_alternative), subtype=subtype_alternative, charset='utf-8')
            msg.add_alternative(email_body, subtype=subtype, charset='utf-8')
        else:
            msg.set_content(email_body, subtype=subtype, charset='utf-8')

        if attachments:
            for (fname, fcontent, mime) in attachments:
                maintype, subtype = mime.split('/') if mime and '/' in mime else ('application', 'octet-stream')
                msg.add_attachment(fcontent, maintype, subtype, filename=fname)
        return msg
Exemplo n.º 24
0
    def _microsoft_values(self, fields_to_sync, initial_values={}):
        values = dict(initial_values)
        if not fields_to_sync:
            return values

        values['id'] = self.microsoft_id
        microsoft_guid = self.env['ir.config_parameter'].sudo().get_param('microsoft_calendar.microsoft_guid', False)
        values['singleValueExtendedProperties'] = [{
            'id': 'String {%s} Name flectra_id' % microsoft_guid,
            'value': str(self.id),
        }, {
            'id': 'String {%s} Name owner_flectra_id' % microsoft_guid,
            'value': str(self.user_id.id),
        }]

        if self.microsoft_recurrence_master_id and 'type' not in values:
            values['seriesMasterId'] = self.microsoft_recurrence_master_id
            values['type'] = 'exception'

        if 'name' in fields_to_sync:
            values['subject'] = self.name or ''

        if 'description' in fields_to_sync:
            values['body'] = {
                'content': html2plaintext(self.description) if not is_html_empty(self.description) else '',
                'contentType': "text",
            }

        if any(x in fields_to_sync for x in ['allday', 'start', 'date_end', 'stop']):
            if self.allday:
                start = {'dateTime': self.start_date.isoformat(), 'timeZone': 'Europe/London'}
                end = {'dateTime': (self.stop_date + relativedelta(days=1)).isoformat(), 'timeZone': 'Europe/London'}
            else:
                start = {'dateTime': pytz.utc.localize(self.start).isoformat(), 'timeZone': 'Europe/London'}
                end = {'dateTime': pytz.utc.localize(self.stop).isoformat(), 'timeZone': 'Europe/London'}

            values['start'] = start
            values['end'] = end
            values['isAllDay'] = self.allday

        if 'location' in fields_to_sync:
            values['location'] = {'displayName': self.location or ''}

        if 'alarm_ids' in fields_to_sync:
            alarm_id = self.alarm_ids.filtered(lambda a: a.alarm_type == 'notification')[:1]
            values['isReminderOn'] = bool(alarm_id)
            values['reminderMinutesBeforeStart'] = alarm_id.duration_minutes

        if 'user_id' in fields_to_sync:
            values['organizer'] = {'emailAddress': {'address': self.user_id.email or '', 'name': self.user_id.display_name or ''}}
            values['isOrganizer'] = self.user_id == self.env.user

        if 'attendee_ids' in fields_to_sync:
            attendees = self.attendee_ids.filtered(lambda att: att.partner_id not in self.user_id.partner_id)
            values['attendees'] = [
                {
                    'emailAddress': {'address': attendee.email or '', 'name': attendee.display_name or ''},
                    'status': {'response': self._get_attendee_status_o2m(attendee)}
                } for attendee in attendees]

        if 'privacy' in fields_to_sync or 'show_as' in fields_to_sync:
            values['showAs'] = self.show_as
            sensitivity_o2m = {
                'public': 'normal',
                'private': 'private',
                'confidential': 'confidential',
            }
            values['sensitivity'] = sensitivity_o2m.get(self.privacy)

        if 'active' in fields_to_sync and not self.active:
            values['isCancelled'] = True

        if values.get('type') == 'seriesMaster':
            recurrence = self.recurrence_id
            pattern = {
                'interval': recurrence.interval
            }
            if recurrence.rrule_type in ['daily', 'weekly']:
                pattern['type'] = recurrence.rrule_type
            else:
                prefix = 'absolute' if recurrence.month_by == 'date' else 'relative'
                pattern['type'] = recurrence.rrule_type and prefix + recurrence.rrule_type.capitalize()

            if recurrence.month_by == 'date':
                pattern['dayOfMonth'] = recurrence.day

            if recurrence.month_by == 'day' or recurrence.rrule_type == 'weekly':
                pattern['daysOfWeek'] = [
                    weekday_name for weekday_name, weekday in {
                        'monday': recurrence.mo,
                        'tuesday': recurrence.tu,
                        'wednesday': recurrence.we,
                        'thursday': recurrence.th,
                        'friday': recurrence.fr,
                        'saturday': recurrence.sa,
                        'sunday': recurrence.su,
                    }.items() if weekday]
                pattern['firstDayOfWeek'] = 'sunday'

            if recurrence.rrule_type == 'monthly' and recurrence.month_by == 'day':
                byday_selection = {
                    '1': 'first',
                    '2': 'second',
                    '3': 'third',
                    '4': 'fourth',
                    '-1': 'last',
                }
                pattern['index'] = byday_selection[recurrence.byday]

            dtstart = recurrence.dtstart or fields.Datetime.now()
            rule_range = {
                'startDate': (dtstart.date()).isoformat()
            }

            if recurrence.end_type == 'count':  # e.g. stop after X occurence
                rule_range['numberOfOccurrences'] = min(recurrence.count, MAX_RECURRENT_EVENT)
                rule_range['type'] = 'numbered'
            elif recurrence.end_type == 'forever':
                rule_range['numberOfOccurrences'] = MAX_RECURRENT_EVENT
                rule_range['type'] = 'numbered'
            elif recurrence.end_type == 'end_date':  # e.g. stop after 12/10/2020
                rule_range['endDate'] = recurrence.until.isoformat()
                rule_range['type'] = 'endDate'

            values['recurrence'] = {
                'pattern': pattern,
                'range': rule_range
            }

        return values
Exemplo n.º 25
0
 def _get_note_first_line(self):
     for message in self:
         message.name = (message.message and html2plaintext(message.message) or "").strip().replace('*', '').split("\n")[0]
Exemplo n.º 26
0
    def mail_update_message(self,
                            res_model,
                            res_id,
                            message,
                            message_id,
                            redirect=None,
                            attachment_ids='',
                            attachment_tokens='',
                            **post):
        # keep this mechanism intern to slide currently (saas 12.5) as it is
        # considered experimental
        if res_model != 'slide.channel':
            raise Forbidden()
        res_id = int(res_id)

        attachment_ids = [
            int(attachment_id) for attachment_id in attachment_ids.split(',')
            if attachment_id
        ]
        attachment_tokens = [
            attachment_token
            for attachment_token in attachment_tokens.split(',')
            if attachment_token
        ]
        self._portal_post_check_attachments(attachment_ids, attachment_tokens)

        pid = int(post['pid']) if post.get('pid') else False
        if not _check_special_access(res_model,
                                     res_id,
                                     token=post.get('token'),
                                     _hash=post.get('hash'),
                                     pid=pid):
            raise Forbidden()

        # fetch and update mail.message
        message_id = int(message_id)
        message_body = plaintext2html(message)
        domain = [('model', '=', res_model), ('res_id', '=', res_id),
                  ('is_internal', '=', False),
                  ('author_id', '=', request.env.user.partner_id.id),
                  ('message_type', '=', 'comment'),
                  ('id', '=', message_id)]  # restrict to the given message_id
        message = request.env['mail.message'].search(domain, limit=1)
        if not message:
            raise NotFound()
        message.sudo().write({
            'body':
            message_body,
            'attachment_ids': [(4, aid) for aid in attachment_ids],
        })

        # update rating
        if post.get('rating_value'):
            domain = [('res_model', '=', res_model), ('res_id', '=', res_id),
                      ('is_internal', '=', False),
                      ('message_id', '=', message.id)]
            rating = request.env['rating.rating'].sudo().search(
                domain, order='write_date DESC', limit=1)
            rating.write({
                'rating': float(post['rating_value']),
                'feedback': html2plaintext(message.body),
            })

        # redirect to specified or referrer or simply channel page as fallback
        redirect_url = redirect or (request.httprequest.referrer
                                    and request.httprequest.referrer +
                                    '#review') or '/slides/%s' % res_id
        return werkzeug.utils.redirect(redirect_url, 302)