コード例 #1
0
ファイル: main.py プロジェクト: ngnamuit/odoo_14_enterprise
    def get_avatar(self, access_token=None, share_id=None):
        """
        :param share_id: id of the share.
        :param access_token: share access token
        :returns the picture of the share author for the front-end view.
        """
        try:
            env = request.env
            share = env['documents.share'].sudo().browse(share_id)
            if share._get_documents_and_check_access(
                    access_token, document_ids=[],
                    operation='read') is not False:
                image = env['res.users'].sudo().browse(
                    share.create_uid.id).image_128

                if not image:
                    binary = Binary()
                    return binary.placeholder()

                return base64.b64decode(image)
            else:
                return request.not_found()
        except Exception:
            logger.exception("Failed to download portrait")
        return request.not_found()
コード例 #2
0
    def image_shape(self, module, filename, img_key, **kwargs):
        svg = self._get_shape_svg(module, 'image_shapes', filename)
        _, _, image_base64 = request.env['ir.http'].binary_content(
            xmlid=img_key,
            model='ir.attachment',
            field='datas',
            default_mimetype='image/png')
        if not image_base64:
            image_base64 = b64encode(Binary.placeholder())
        image = base64_to_image(image_base64)
        width, height = tuple(str(size) for size in image.size)
        root = etree.fromstring(svg)
        root.attrib.update({'width': width, 'height': height})
        # Update default color palette on shape SVG.
        svg, _ = self._update_svg_colors(
            kwargs,
            etree.tostring(root, pretty_print=True).decode('utf-8'))
        # Add image in base64 inside the shape.
        uri = image_data_uri(image_base64)
        svg = svg.replace('<image xlink:href="', '<image xlink:href="%s' % uri)

        return request.make_response(svg, [
            ('Content-type', 'image/svg+xml'),
            ('Cache-control', 'max-age=%s' % http.STATIC_CACHE_LONG),
        ])
コード例 #3
0
 def content_image(self, id=None, max_width=0, max_height=0, **kw):
     if max_width:
         kw['width'] = max_width
     if max_height:
         kw['height'] = max_height
     if id:
         id, _, unique = id.partition('_')
         kw['id'] = int(id)
         if unique:
             kw['unique'] = unique
     return Binary().content_image(**kw)
コード例 #4
0
ファイル: main.py プロジェクト: ws-manatec/odoo
    def survey_get_background(self, survey_token, answer_token):
        access_data = self._get_access_data(survey_token, answer_token, ensure_token=True)
        if access_data['validity_code'] is not True:
            return werkzeug.exceptions.Forbidden()

        survey_sudo, answer_sudo = access_data['survey_sudo'], access_data['answer_sudo']

        status, headers, image_base64 = request.env['ir.http'].sudo().binary_content(
            model='survey.survey', id=survey_sudo.id, field='background_image',
            default_mimetype='image/png')

        return Binary._content_image_get_response(status, headers, image_base64)
コード例 #5
0
ファイル: main.py プロジェクト: ws-manatec/odoo
    def survey_get_question_image(self, survey_token, answer_token, question_id, suggested_answer_id):
        access_data = self._get_access_data(survey_token, answer_token, ensure_token=True)
        if access_data['validity_code'] is not True:
            return werkzeug.exceptions.Forbidden()

        survey_sudo, answer_sudo = access_data['survey_sudo'], access_data['answer_sudo']

        if not survey_sudo.question_ids.filtered(lambda q: q.id == question_id)\
                          .suggested_answer_ids.filtered(lambda a: a.id == suggested_answer_id):
            return werkzeug.exceptions.NotFound()

        status, headers, image_base64 = request.env['ir.http'].sudo().binary_content(
            model='survey.question.answer', id=suggested_answer_id, field='value_image',
            default_mimetype='image/png')

        return Binary._content_image_get_response(status, headers, image_base64)
コード例 #6
0
	def core_content_image(self, xmlid=None, model='ir.attachment', id=None, field='datas',
					  filename_field='datas_fname', unique=None, filename=None, mimetype=None,
					  download=None, width=0, height=0, crop=False, access_token=None, **kwargs):
		contenttype = kwargs.get('wk_mime_type') or 'image/jpg'
		status, headers, content = binary_content(
			xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
			filename_field=filename_field, download=download, mimetype=mimetype,
			default_mimetype='image/jpg', access_token=access_token)
		if status == 304:
			return werkzeug.wrappers.Response(status=304, headers=headers)
		elif status == 301:
			return werkzeug.utils.redirect(content, code=301)
		elif status != 200 and download:
			return request.not_found()

		height = int(height or 0)
		width = int(width or 0)

		if crop and (width or height):
			content = crop_image(content, type='center', size=(width, height), ratio=(1, 1))

		elif content and (width or height):
			# resize maximum 500*500
			if width > 500:
				width = 500
			if height > 500:
				height = 500
			content = odoo.tools.image_resize_image(base64_source=content, size=(width or None, height or None), encoding='base64', filetype='PNG')
			# resize force jpg as filetype
			headers = Binary().force_contenttype(headers, contenttype='image/jpg')

		if content:
			image_base64 = base64.b64decode(content)
		else:
			image_base64 = Binary().placeholder(image='placeholder.jpg')  # could return (contenttype, content) in master
			headers = Binary().force_contenttype(headers, contenttype='image/jpg')

		headers.append(('Content-Length', len(image_base64)))
		response = request.make_response(image_base64, headers)
		response.status_code = status
		return response
コード例 #7
0
 def resize_to_48(b64source):
     if not b64source:
         b64source = base64.b64encode(Binary.placeholder())
     return image_process(b64source, size=(48, 48))
コード例 #8
0
class ExportHelpWizard(models.TransientModel):
    _name = "export.help.wizard"
    _description = 'Export Help Online'

    data = fields.Binary('XML', readonly=True)
    export_filename = fields.Char('Export XML Filename', size=128)

    binary = Binary()
    websiteBinary = WebsiteBinary()

    img_url_map = Map([
        Rule('/web/image'),
        Rule('/web/image/<string:xmlid>'),
        Rule('/web/image/<string:xmlid>/<string:filename>'),
        Rule('/web/image/<string:xmlid>/<int:width>x<int:height>'),
        Rule('/web/image/<string:xmlid>/<int:width>x<int:height>/'
             '<string:filename>'),
        Rule('/web/image/<string:model>/<int:id>/<string:field>'),
        Rule('/web/image/<string:model>/<int:id>/<string:field>/'
             '<string:filename>'),
        Rule('/web/image/<string:model>/<int:id>/<string:field>/'
             '<int:width>x<int:height>'),
        Rule('/web/image/<string:model>/<int:id>/<string:field>/'
             '<int:width>x<int:height>/<string:filename>'),
        Rule('/web/image/<int:id>'),
        Rule('/web/image/<int:id>/<string:filename>'),
        Rule('/web/image/<int:id>/<int:width>x<int:height>'),
        Rule('/web/image/<int:id>/<int:width>x<int:height>/<string:filename>'),
        Rule('/web/image/<int:id>-<string:unique>'),
        Rule('/web/image/<int:id>-<string:unique>/<string:filename>'),
        Rule('/web/image/<int:id>-<string:unique>/<int:width>x<int:height>'),
        Rule('/web/image/<int:id>-<string:unique>/<int:width>x<int:height>'
             '/<string:filename>'),
        Rule('/website/image'),
        Rule('/website/image/<xmlid>'),
        Rule('/website/image/<xmlid>/<int:width>x<int:height>'),
        Rule('/website/image/<xmlid>/<field>'),
        Rule('/website/image/<xmlid>/<field>/<int:width>x<int:height>'),
        Rule('/website/image/<model>/<id>/<field>'),
        Rule('/website/image/<model>/<id>/<field>/<int:width>x<int:height>')
    ])

    def _manage_images_on_page(self, page_node, data_node, exported_resources):
        """
            - Extract images from page and generate an xml node
            - Replace db id in url with xml id
        """
        img_model = 'ir.attachment'
        urls = self.img_url_map.bind("dummy.org", "/")
        for img_elem in page_node.iter('img'):
            img_src = img_elem.get('src')
            parse_result = urlparse.urlparse(img_src)
            path = parse_result.path
            query_args = parse_result.query
            if urls.test(parse_result.path, "GET"):
                endpoint, kwargs = urls.match(path,
                                              "GET",
                                              query_args=query_args)
                kwargs.update(dict(urlparse.parse_qsl(query_args)))
                image = None
                # get the binary object
                xml_id = kwargs.get('xmlid')
                if xml_id:
                    image = self.env.ref(xml_id, False)
                else:
                    _id = kwargs.get('id')
                    model = kwargs.get('model', 'ir.attachment')
                    if _id and model:
                        _id, _, unique = str(_id).partition('_')
                        image = self.env[model].browse(int(_id))
                if (not image or not image.exists()
                        or image._name != img_model):
                    raise exceptions.UserError(
                        _('Only images from ir.attachment are supported when '
                          'exporting help pages'))
                exported_data = image.export_data([
                    'id', 'datas', 'datas_fname', 'name', 'res_model',
                    'mimetype'
                ],
                                                  raw_data=False)['datas'][0]
                xml_id = exported_data[0]
                new_src = '/web/image/%s' % xml_id
                img_elem.attrib['src'] = new_src
                if xml_id in exported_resources:
                    continue
                img_node = ET.SubElement(data_node,
                                         'record',
                                         attrib={
                                             'id': xml_id,
                                             'model': image._name
                                         })
                field_node = ET.SubElement(img_node,
                                           'field',
                                           attrib={'name': 'datas'})
                field_node.text = str(exported_data[1])
                field_node = ET.SubElement(img_node,
                                           'field',
                                           attrib={'name': 'datas_fname'})
                field_node.text = exported_data[2]
                field_node = ET.SubElement(img_node,
                                           'field',
                                           attrib={'name': 'name'})
                field_node.text = exported_data[3]
                field_node = ET.SubElement(img_node,
                                           'field',
                                           attrib={'name': 'res_model'})
                field_node.text = exported_data[4]
                field_node = ET.SubElement(img_node,
                                           'field',
                                           attrib={'name': 'mimetype'})
                field_node.text = exported_data[5]
                data_node.append(img_node)
                exported_resources.add(xml_id)

    def _clean_href_urls(self, page_node, page_prefix, template_prefix):
        """
            Remove host address for href urls
        """
        for a_elem in page_node.iter('a'):
            if not a_elem.get('href'):
                continue
            href = a_elem.get('href')
            if not href.startswith('http'):
                continue
            page_url = '/page/%s' % page_prefix
            template_url = '/page/%s' % template_prefix
            if page_url not in href and template_url not in href:
                continue
            elif page_url in href and template_url not in href:
                pass
            elif page_url not in href and template_url in href:
                page_url = template_url
            else:
                if page_prefix in template_prefix:
                    page_url = template_url
                else:
                    pass

            if page_url:
                trail = href.split(page_url, 1)[1]
                a_elem.attrib['href'] = page_url + trail

    def _generate_snippet_from_template(self, page_node, template_id,
                                        template_prefix):
        """
            Generate a website snippet from a template
        """
        page = copy.deepcopy(page_node)
        snippet = ET.Element('template')
        snippet.attrib['id'] = template_id + '_snippet'
        snippet.attrib['inherit_id'] = 'website.snippets'
        snippet.attrib['name'] = page_node.attrib['name']

        xpath = ET.SubElement(snippet,
                              'xpath',
                              attrib={
                                  'expr': "//div[@id='snippet_structure']",
                                  'position': 'inside'
                              })
        main_div = ET.SubElement(xpath, 'div')
        thumbnail = ET.SubElement(main_div,
                                  'div',
                                  attrib={'class': 'oe_snippet_thumbnail'})
        ET.SubElement(thumbnail,
                      'img',
                      attrib={
                          'class': 'oe_snippet_thumbnail_img',
                          'src': HELP_ONLINE_SNIPPET_IMAGE_PATH
                      })
        span = ET.SubElement(thumbnail,
                             'span',
                             attrib={'class': 'oe_snippet_thumbnail_title'})
        span.text = page_node.attrib['name'].replace(template_prefix, '')
        body = ET.SubElement(
            main_div,
            'section',
            attrib={'class': 'oe_snippet_body '
                    'mt_simple_snippet'})

        template = page.find(".//div[@id='wrap']")

        for node in template.getchildren():
            body.append(node)

        return snippet

    def _get_qweb_views_data(self):
        parameter_model = self.env['ir.config_parameter']
        page_prefix = parameter_model.get_param(PAGE_PREFIX_PARAMETER, False)
        template_prefix = parameter_model.get_param(TEMPLATE_PREFIX_PARAMETER,
                                                    False)

        if not page_prefix or not template_prefix:
            return False

        domain = [('type', '=', 'qweb'), ('page', '=', True), '|',
                  ('name', 'like', '%s%%' % page_prefix),
                  ('name', 'like', '%s%%' % template_prefix)]

        ir_ui_views = self.env['ir.ui.view'].search(domain, order='name')
        xml_to_export = ET.Element('odoo')
        data_node = ET.SubElement(xml_to_export, 'data')
        exported_resources = set()
        for ir_ui_view in ir_ui_views:
            parser = ET.XMLParser(remove_blank_text=True)
            root = ET.XML(ir_ui_view.arch, parser=parser)
            root.tag = 'template'
            xml_id = self._get_ir_ui_view_xml_id(ir_ui_view,
                                                 root.attrib.pop('t-name'))
            root.attrib['name'] = ir_ui_view.name.replace('website.', '')
            root.attrib['id'] = xml_id
            root.attrib['page'] = 'True'
            root.attrib['key'] = ir_ui_view.key

            self._manage_images_on_page(root, data_node, exported_resources)
            self._clean_href_urls(root, page_prefix, template_prefix)
            data_node.append(root)

            if root.attrib['name'].startswith(template_prefix):
                snippet = self._generate_snippet_from_template(
                    root, xml_id, template_prefix)
                data_node.append(snippet)

        if len(ir_ui_views) > 0:
            return ET.tostring(xml_to_export,
                               encoding='utf-8',
                               xml_declaration=True,
                               pretty_print=True)
        else:
            return False

    @api.model
    def _get_ir_ui_view_xml_id(self, ir_ui_view, template_name):
        """This method check if an xml_id exists for the given ir.ui.view
        If no xml_id exists, a new one is created with template name as
        value to ensure that the import of the generated file will update
        the existing view in place of creating new copies.
        """
        ir_model_data = self.sudo().env['ir.model.data']
        data = ir_model_data.search([('model', '=', ir_ui_view._name),
                                     ('res_id', '=', ir_ui_view.id)])
        if data:
            if data[0].module:
                return '%s.%s' % (data[0].module, data[0].name)
            else:
                return data[0].name
        else:
            module, name = template_name.split('.')
            # always use __export__  as module by convention to
            # avoid the removal by odoo of the exported pages on system
            # update (-u )
            module = "__export__"
            postfix = ir_model_data.search_count([('module', '=', module),
                                                  ('name', 'like', name)])
            if postfix:
                name = '%s_%s' % (name, postfix)
            ir_model_data.create({
                'model': ir_ui_view._name,
                'res_id': ir_ui_view.id,
                'module': module,
                'name': name,
            })
            return module + '.' + name

    @api.multi
    def export_help(self):
        """
        Export all Qweb views related to help online in a Odoo
        data XML file
        """
        xml_data = self._get_qweb_views_data()
        if not xml_data:
            raise exceptions.Warning(_('No data to export !'))
        out = base64.encodestring(xml_data)

        self.write({'data': out, 'export_filename': 'help_online_data.xml'})

        return {
            'name': _('Export Help'),
            'type': 'ir.actions.act_window',
            'res_model': self._name,
            'view_mode': 'form',
            'view_type': 'form',
            'res_id': self.id,
            'views': [(False, 'form')],
            'target': 'new',
        }

    @api.model
    def auto_backup(self):
        """
            Export data to a file on home directory of user
        """
        parameter_model = self.env['ir.config_parameter']
        autobackup_path = parameter_model.get_param(AUTOBACKUP_PARAMETER,
                                                    False)

        if autobackup_path:
            xml_data = self._get_qweb_views_data()
            try:
                timestr = time.strftime("%Y%m%d-%H%M%S")
                filename = '%s/help_online_backup-%s.xml' % (autobackup_path,
                                                             timestr)
                backup_file = open(filename, 'w')
                backup_file.write(xml_data)
                backup_file.close()
            except:
                _logger.warning(
                    _('Unable to write autobackup file '
                      'in given directory: %s' % autobackup_path))
コード例 #9
0
    def core_content_image(self,
                           xmlid=None,
                           model='ir.attachment',
                           id=None,
                           field='datas',
                           filename_field='datas_fname',
                           unique=None,
                           filename=None,
                           mimetype=None,
                           download=None,
                           width=0,
                           height=0,
                           crop=False,
                           access_token=None,
                           **kwargs):
        contenttype = kwargs.get('wk_mime_type') or 'image/jpg'
        status, headers, content = request.env['ir.http'].sudo(
        ).binary_content(xmlid=xmlid,
                         model=model,
                         id=id,
                         field=field,
                         unique=unique,
                         filename=filename,
                         filename_field=filename_field,
                         download=download,
                         mimetype=mimetype,
                         access_token=access_token)

        if status == 304:
            return werkzeug.wrappers.Response(status=304, headers=headers)
        elif status == 301:
            return werkzeug.utils.redirect(content, code=301)
        elif status != 200 and download:
            return request.not_found()

        height = int(height or 0)
        width = int(width or 0)

        if crop and (width or height):
            # default crop is fron center
            content = image_process(base64_source=content,
                                    size=(width or 0, height or 0),
                                    crop=crop)
        elif content and (width or height):
            # resize maximum 500*500
            if width > 500:
                width = 500
            if height > 500:
                height = 500
            content = image_process(base64_source=content,
                                    size=(width or 0, height or 0))
            # resize force jpg as filetype

        if content:
            image_base64 = base64.b64decode(content)
        else:
            image_base64 = Binary().placeholder(
            )  # could return (contenttype, content) in master

        headers.append(('Content-Length', len(image_base64)))
        response = request.make_response(image_base64, headers)
        response.status_code = status
        return response
コード例 #10
0
    def _content_image(self,
                       xmlid=None,
                       model='ir.attachment',
                       id=None,
                       field='datas',
                       filename_field='name',
                       unique=None,
                       filename=None,
                       mimetype=None,
                       download=None,
                       width=0,
                       height=0,
                       crop=False,
                       quality=0,
                       access_token=None,
                       placeholder='placeholder.png',
                       **kwargs):
        webp_support = check_webp_support(request)
        is_webp = False

        if model and model == 'ir.attachment' and id:
            attachment = request.env[model].sudo().search([('id', '=', id)])
        else:
            attachment = request.env['ir.attachment'].sudo().search(
                [('res_model', '=', model), ('res_id', '=', id),
                 ('res_field', '=', field)],
                limit=1)

        if attachment and attachment.mimetype == "image/webp":
            is_webp = True

        status, headers, image_base64 = request.env['ir.http'].binary_content(
            xmlid=xmlid,
            model=model,
            id=id,
            field=field,
            unique=unique,
            filename=filename,
            filename_field=filename_field,
            download=download,
            mimetype=mimetype,
            default_mimetype='image/png',
            access_token=access_token)

        if status in [301, 304] or (status != 200 and download):
            return request.env['ir.http']._response_by_status(
                status, headers, image_base64)
        if not image_base64:
            status = 200
            image_base64 = base64.b64encode(
                Binary().placeholder(image=placeholder))
            if not (width or height):
                width, height = odoo.tools.image_guess_size_from_field_name(
                    field)

        if not is_webp:
            image_base64 = image_process(image_base64,
                                         size=(int(width), int(height)),
                                         crop=crop,
                                         quality=quality)
        else:
            if webp_support:
                width = width or height or 0
                height = height or width or 0

                webp_data = webp.WebPData.from_buffer(
                    base64.b64decode(image_base64))
                arr = webp_data.decode()
                source_image = Image.fromarray(arr, 'RGBA')

                if width or height:
                    source_image.thumbnail((width, height))

                pic = webp.WebPPicture.from_pil(source_image)
                config = webp.WebPConfig.new(
                    preset=webp.WebPPreset.PHOTO,
                    quality=quality
                    or int(request.session.get('webp_image_quality', 95))
                    or 95)
                image_base64 = base64.b64encode(pic.encode(config).buffer())

        img_data = base64.b64decode(image_base64)
        headers = http.set_safe_image_headers(headers, img_data)

        if headers and dict(headers).get('Content-Type',
                                         '') != 'image/svg+xml':
            width = width or height or 0
            height = height or width or 0

            if webp_support:
                quality = quality or int(
                    request.session.get('webp_image_quality', 95)) or 95

                if not is_webp:
                    source_image = Image.open(
                        io.BytesIO(img_data)).convert("RGBA")
                    pic = webp.WebPPicture.from_pil(source_image)
                    config = webp.WebPConfig.new(preset=webp.WebPPreset.PHOTO,
                                                 quality=quality)
                    img_data = pic.encode(config).buffer()
            else:
                if is_webp:
                    webp_data = webp.WebPData.from_buffer(img_data)
                    arr = webp_data.decode()
                    source_image = Image.fromarray(arr, 'RGBA')

                    if width or height:
                        source_image.thumbnail((width, height))

                    convert_to_png = io.BytesIO()
                    source_image.save(convert_to_png, 'PNG')
                    img_data = convert_to_png.getvalue()

            for key, item in enumerate(headers):
                if item[0] == 'Content-Type':
                    headers[key] = ('Content-Type',
                                    webp_support and 'image/webp'
                                    or 'image/png')
                    break

        response = request.make_response(img_data, headers)
        response.status_code = status
        return response