Example #1
0
    def execute_callback(self):
        res = None
        for transaction in self:
            # limited sudo env, only for checking callback presence, not for running it!
            # manual transactions have no callback, and can pass without being run by admin user
            tx_sudo = transaction.sudo()
            if not (tx_sudo.callback_model_id and tx_sudo.callback_res_id
                    and tx_sudo.callback_method):
                continue

            valid_token = transaction._generate_callback_hash()
            if not consteq(ustr(valid_token), transaction.callback_hash):
                _logger.warning(
                    "Invalid callback signature for transaction %d" %
                    (transaction.id))
                continue

            record = self.env[transaction.callback_model_id.model].browse(
                transaction.callback_res_id).exists()
            if record:
                res = getattr(record, transaction.callback_method)(transaction)
            else:
                _logger.warning(
                    "Did not found record %s.%s for callback of transaction %d"
                    % (transaction.callback_model_id.model,
                       transaction.callback_res_id, transaction.id))
        return res
Example #2
0
 def _check_token(cls, token):
     base_link = request.httprequest.path
     params = dict(request.params)
     params.pop('token', '')
     valid_token = request.env['mail.thread']._generate_notification_token(
         base_link, params)
     return consteq(valid_token, str(token))
Example #3
0
 def _order_check_access(self, order_id, access_token=None):
     order = request.env['sale.order'].browse([order_id])
     order_sudo = order.sudo()
     try:
         order.check_access_rights('read')
         order.check_access_rule('read')
     except AccessError:
         if not access_token or not consteq(order_sudo.access_token, access_token):
             raise
     return order_sudo
Example #4
0
 def _invoice_check_access(self, invoice_id, access_token=None):
     invoice = request.env['account.invoice'].browse([invoice_id])
     invoice_sudo = invoice.sudo()
     try:
         invoice.check_access_rights('read')
         invoice.check_access_rule('read')
     except AccessError:
         if not access_token or not consteq(invoice_sudo.access_token,
                                            access_token):
             raise
     return invoice_sudo
Example #5
0
 def _stock_picking_check_access(self, picking_id, access_token=None):
     picking = request.env['stock.picking'].browse([picking_id])
     picking_sudo = picking.sudo()
     try:
         picking.check_access_rights('read')
         picking.check_access_rule('read')
     except exceptions.AccessError:
         if not access_token or not consteq(
                 picking_sudo.sale_id.access_token, access_token):
             raise
     return picking_sudo
Example #6
0
    def mailing(self, mailing_id, email=None, res_id=None, token="", **post):
        mailing = request.env['mail.mass_mailing'].sudo().browse(mailing_id)
        if mailing.exists():
            res_id = res_id and int(res_id)
            res_ids = []
            if mailing.mailing_model_name == 'mail.mass_mailing.list':
                contacts = request.env['mail.mass_mailing.contact'].sudo(
                ).search([('email', '=', email),
                          ('list_ids', 'in', [
                              mailing_list.id
                              for mailing_list in mailing.contact_list_ids
                          ])])
                res_ids = contacts.ids
            else:
                res_ids = [res_id]

            right_token = mailing._unsubscribe_token(res_id, email)
            if not consteq(str(token), right_token):
                raise exceptions.AccessDenied()
            mailing.update_opt_out(email, res_ids, True)
            return _('You have been unsubscribed successfully')
Example #7
0
def _has_token_access(res_model, res_id, token=''):
    record = request.env[res_model].browse(res_id).sudo()
    token_field = request.env[res_model]._mail_post_token_field
    return (token and record and consteq(record[token_field], token))
Example #8
0
    def binary_content(cls,
                       xmlid=None,
                       model='ir.attachment',
                       id=None,
                       field='datas',
                       unique=False,
                       filename=None,
                       filename_field='datas_fname',
                       download=False,
                       mimetype=None,
                       default_mimetype='application/octet-stream',
                       access_token=None,
                       env=None):
        """ Get file, attachment or downloadable content

        If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the
        binary field (via ``default_get``), otherwise fetches the field for
        that precise record.

        :param str xmlid: xmlid of the record
        :param str model: name of the model to fetch the binary from
        :param int id: id of the record from which to fetch the binary
        :param str field: binary field
        :param bool unique: add a max-age for the cache control
        :param str filename: choose a filename
        :param str filename_field: if not create an filename with model-id-field
        :param bool download: apply headers to download the file
        :param str mimetype: mintype of the field (for headers)
        :param str default_mimetype: default mintype if no mintype found
        :param str access_token: optional token for unauthenticated access
                                 only available  for ir.attachment
        :param Environment env: by default use request.env
        :returns: (status, headers, content)
        """
        env = env or request.env
        # get object and content
        obj = None
        if xmlid:
            obj = env.ref(xmlid, False)
        elif id and model == 'ir.attachment' and access_token:
            obj = env[model].sudo().browse(int(id))
            if not consteq(obj.access_token, access_token):
                return (403, [], None)
        elif id and model in env.registry:
            obj = env[model].browse(int(id))

        # obj exists
        if not obj or not obj.exists() or field not in obj:
            return (404, [], None)

        # check read access
        try:
            last_update = obj['__last_update']
        except AccessError:
            return (403, [], None)

        status, headers, content = None, [], None

        # attachment by url check
        module_resource_path = None
        if model == 'ir.attachment' and obj.type == 'url' and obj.url:
            url_match = re.match("^/(\w+)/(.+)$", obj.url)
            if url_match:
                module = url_match.group(1)
                module_path = get_module_path(module)
                module_resource_path = get_resource_path(
                    module, url_match.group(2))
                if module_path and module_resource_path:
                    module_path = os.path.join(
                        os.path.normpath(module_path),
                        '')  # join ensures the path ends with '/'
                    module_resource_path = os.path.normpath(
                        module_resource_path)
                    if module_resource_path.startswith(module_path):
                        with open(module_resource_path, 'rb') as f:
                            content = base64.b64encode(f.read())
                        last_update = pycompat.text_type(
                            os.path.getmtime(module_resource_path))

            if not module_resource_path:
                module_resource_path = obj.url

            if not content:
                status = 301
                content = module_resource_path
        else:
            content = obj[field] or ''

        # filename
        if not filename:
            if filename_field in obj:
                filename = obj[filename_field]
            elif module_resource_path:
                filename = os.path.basename(module_resource_path)
            else:
                filename = "%s-%s-%s" % (obj._name, obj.id, field)

        # mimetype
        mimetype = 'mimetype' in obj and obj.mimetype or False
        if not mimetype:
            if filename:
                mimetype = mimetypes.guess_type(filename)[0]
            if not mimetype and getattr(env[model]._fields[field],
                                        'attachment', False):
                # for binary fields, fetch the ir_attachement for mimetype check
                attach_mimetype = env['ir.attachment'].search_read(
                    domain=[('res_model', '=', model), ('res_id', '=', id),
                            ('res_field', '=', field)],
                    fields=['mimetype'],
                    limit=1)
                mimetype = attach_mimetype and attach_mimetype[0]['mimetype']
            if not mimetype:
                mimetype = guess_mimetype(base64.b64decode(content),
                                          default=default_mimetype)

        headers += [('Content-Type', mimetype),
                    ('X-Content-Type-Options', 'nosniff')]

        # cache
        etag = bool(request) and request.httprequest.headers.get(
            'If-None-Match')
        retag = '"%s"' % hashlib.md5(
            pycompat.to_text(content).encode('utf-8')).hexdigest()
        status = status or (304 if etag == retag else 200)
        headers.append(('ETag', retag))
        headers.append(
            ('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0)))

        # content-disposition default name
        if download:
            headers.append(
                ('Content-Disposition', cls.content_disposition(filename)))
        return (status, headers, content)