forked from Techsystech/web
[MIG] Migrate to 9.0
parent
b7a980abcd
commit
80cd9e9024
|
@ -0,0 +1,69 @@
|
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
|
||||
===========
|
||||
Help Online
|
||||
===========
|
||||
|
||||
|
||||
This module allows the creation of an online help available from the lists
|
||||
and forms in Odoo.
|
||||
|
||||
When loading a view, the module generates a button allowing access to an help
|
||||
page for the related model if the page exists and the user is member of the
|
||||
group 'Help reader'. If the page doesn't exist and the user is member of
|
||||
the group 'Help writer', the module generate a button allowing the creation an
|
||||
help page.
|
||||
|
||||
The help pages are created and managed via the website Module.
|
||||
|
||||
Note: When updating the page prefix parameters, the record rules must be
|
||||
adapted.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/162/9.0
|
||||
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
Even if the generated urls to the documentation contains an anchor (website/hel-xx#view_type),
|
||||
it's no more possible to insert/edit anchors elements into the website since this functionnality is not supported
|
||||
by the new html editor in Odoo 9.0 (summernote).
|
||||
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues
|
||||
<https://github.com/OCA/web/issues>`_. In case of trouble, please
|
||||
check there if your issue has already been reported. If you spotted it first,
|
||||
help us smashing it by providing a detailed and welcomed feedback.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Laurent Mignon <laurent.mignon@acsone.eu>
|
||||
* Jonathan Nemry <jonathan.nemry@acsone.eu>
|
||||
* Cédric Pigeon <cedric.pigeon@acsone.eu>
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
|
||||
|
||||
To contribute to this module, please visit https://odoo-community.org.
|
|
@ -1,22 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Nemry Jonathan
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
from . import wizards
|
||||
|
|
|
@ -1,65 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Nemry Jonathan
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
'name': 'Help Online',
|
||||
'version': '8.0.1.0.0',
|
||||
'version': '9.0.1.0.0',
|
||||
'author': "ACSONE SA/NV,Odoo Community Association (OCA)",
|
||||
'maintainer': 'ACSONE SA/NV',
|
||||
'website': 'http://www.acsone.eu',
|
||||
'license': 'AGPL-3',
|
||||
'category': 'Documentation',
|
||||
'depends': [
|
||||
'base',
|
||||
'website',
|
||||
],
|
||||
'description': """
|
||||
Help Online
|
||||
===========
|
||||
|
||||
This module allows the creation of an online help available from the lists
|
||||
and forms in Odoo.
|
||||
|
||||
When loading a view, the module generates a button allowing access to an help
|
||||
page for the related model if the page exists and the user is member of the
|
||||
group 'Help reader'. If the page doesn't exist and the user is member of
|
||||
the group 'Help writer', the module generate a button allowing the creation an
|
||||
help page.
|
||||
|
||||
The help pages are created and managed via the website Module.
|
||||
|
||||
Note: When updating the page prefix parameters, the record rules must be
|
||||
adapted.
|
||||
""",
|
||||
'data': [
|
||||
'security/help_online_groups.xml',
|
||||
'security/help_online_rules.xml',
|
||||
'views/export_help_wizard_view.xml',
|
||||
'views/import_help_wizard_view.xml',
|
||||
'wizards/export_help_wizard_view.xml',
|
||||
'wizards/import_help_wizard_view.xml',
|
||||
'views/ir_ui_view_view.xml',
|
||||
'views/help_online_view.xml',
|
||||
'views/website_help_online.xml',
|
||||
'data/ir_config_parameter_data.xml',
|
||||
],
|
||||
'qweb': [
|
||||
'static/src/xml/help_online.xml',
|
||||
],
|
||||
'installable': False,
|
||||
'auto_install': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
|
|
@ -1,21 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Laurent Mignon
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from .import help_online_controllers
|
||||
|
|
|
@ -1,23 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Laurent Mignon
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import openerp.http as http
|
||||
from openerp.http import request
|
||||
|
|
|
@ -1,24 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Nemry Jonathan
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import help_online
|
||||
from . import export_help_wizard
|
||||
from . import import_help_wizard
|
||||
from . import ir_model
|
||||
|
|
|
@ -1,23 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Laurent Mignon
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, exceptions
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
@ -34,9 +18,9 @@ class HelpOnline(models.TransientModel):
|
|||
name = '%s-%s' % (page_prefix, model.replace('.', '-'))
|
||||
return name
|
||||
|
||||
def page_exists(self, name):
|
||||
website_model = self.env['website']
|
||||
return website_model.page_exists(name)
|
||||
def get_existing_pages(self, name, limit=None):
|
||||
website = self.env['website']
|
||||
return website.search_pages(needle=name, limit=limit)
|
||||
|
||||
def get_page_url(self, model, view_type, domain=None, context=None):
|
||||
user_model = self.env['res.users']
|
||||
|
@ -48,8 +32,9 @@ class HelpOnline(models.TransientModel):
|
|||
if res:
|
||||
description = res[0][1]
|
||||
name = self._get_view_name(model, view_type, domain, context)
|
||||
if self.page_exists(name):
|
||||
url = '/page/%s' % name
|
||||
pages = self.get_existing_pages(name, limit=1)
|
||||
if pages:
|
||||
url = pages[0]['loc']
|
||||
if view_type:
|
||||
url = url + '#' + view_type
|
||||
title = _('Help on %s') % description
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
# All Rights Reserved
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsibility of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs.
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# guarantees and support are strongly advised to contact a Free Software
|
||||
# Service Company.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp import models, fields, api
|
||||
from openerp.tools import convert
|
||||
|
||||
import base64
|
||||
from cStringIO import StringIO
|
||||
|
||||
|
||||
class ImportHelpWizard(models.TransientModel):
|
||||
_name = "import.help.wizard"
|
||||
|
||||
source_file = fields.Binary('Source File')
|
||||
|
||||
@api.one
|
||||
def import_help(self):
|
||||
source_file = base64.decodestring(self.source_file)
|
||||
convert.convert_xml_import(self.env.cr,
|
||||
self._module,
|
||||
StringIO(source_file),
|
||||
idref=None,
|
||||
mode='init',
|
||||
noupdate=False,
|
||||
report=None)
|
|
@ -1,29 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Cédric Pigeon
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, api
|
||||
|
||||
from lxml import etree as ET
|
||||
|
||||
|
||||
class ir_model_data(models.Model):
|
||||
class IrModelData(models.Model):
|
||||
_inherit = 'ir.model.data'
|
||||
|
||||
@api.model
|
||||
|
@ -38,14 +22,14 @@ class ir_model_data(models.Model):
|
|||
xml_str = self.manageImageReferences(values['arch'], module)
|
||||
values['arch'] = xml_str
|
||||
|
||||
return super(ir_model_data, self)._update(model,
|
||||
module,
|
||||
values,
|
||||
xml_id=xml_id,
|
||||
store=store,
|
||||
noupdate=noupdate,
|
||||
mode=mode,
|
||||
res_id=res_id)
|
||||
return super(IrModelData, self)._update(model,
|
||||
module,
|
||||
values,
|
||||
xml_id=xml_id,
|
||||
store=store,
|
||||
noupdate=noupdate,
|
||||
mode=mode,
|
||||
res_id=res_id)
|
||||
|
||||
def manageImageReferences(self, xml_str, module):
|
||||
parser = ET.XMLParser(remove_blank_text=True)
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<openerp>
|
||||
<data>
|
||||
<record id="help_online_group_reader" model="res.groups">
|
||||
<field name="name">Help reader</field>
|
||||
<field name="category_id" ref="base.module_category_documentation"/>
|
||||
</record>
|
||||
<record id="help_online_group_writer" model="res.groups">
|
||||
<field name="name">Help writer</field>
|
||||
<field name="category_id" ref="base.module_category_documentation"/>
|
||||
<field name="implied_ids" eval="[
|
||||
(4, ref('help_online_group_reader')),
|
||||
(4, ref('base.group_website_publisher')),
|
||||
]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="help_online_group_reader" model="res.groups">
|
||||
<field name="name">Help reader</field>
|
||||
<field name="category_id" ref="base.module_category_documentation"/>
|
||||
</record>
|
||||
<record id="help_online_group_writer" model="res.groups">
|
||||
<field name="name">Help writer</field>
|
||||
<field name="category_id" ref="base.module_category_documentation"/>
|
||||
<field name="implied_ids" eval="[
|
||||
(4, ref('help_online_group_reader')),
|
||||
(4, ref('base.group_website_publisher')),
|
||||
]"/>
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="online_help_confidential_rule" model="ir.rule">
|
||||
<field name="name">Online Help Hidden by Default</field>
|
||||
<field name="model_id" ref="base.model_ir_ui_view"/>
|
||||
<field name="domain_force">[
|
||||
'|',
|
||||
('type', '!=', 'qweb'),
|
||||
('name','not like','help-%'),
|
||||
]</field>
|
||||
<field name="groups" eval="[(6, 0, [
|
||||
ref('base.group_portal'),
|
||||
ref('base.group_public'),
|
||||
ref('base.group_user'),
|
||||
])]"/>
|
||||
<field name="perm_read" eval="1"/><field name="perm_write" eval="0"/>
|
||||
<field name="perm_create" eval="0"/><field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record id="online_help_reader_rule" model="ir.rule">
|
||||
<field name="name">Online Help for Help Reader</field>
|
||||
<field name="model_id" ref="base.model_ir_ui_view"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(6, 0, [
|
||||
ref('help_online.help_online_group_reader'),
|
||||
])]"/>
|
||||
<field name="perm_read" eval="1"/><field name="perm_write" eval="0"/>
|
||||
<field name="perm_create" eval="0"/><field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
<odoo noupdate="1">
|
||||
<record id="online_help_confidential_rule" model="ir.rule">
|
||||
<field name="name">Online Help Hidden by Default</field>
|
||||
<field name="model_id" ref="base.model_ir_ui_view"/>
|
||||
<field name="domain_force">[
|
||||
'|',
|
||||
('type', '!=', 'qweb'),
|
||||
('name','not like','help-%'),
|
||||
]</field>
|
||||
<field name="groups" eval="[(6, 0, [
|
||||
ref('base.group_portal'),
|
||||
ref('base.group_public'),
|
||||
ref('base.group_user'),
|
||||
])]"/>
|
||||
<field name="perm_read" eval="1"/><field name="perm_write" eval="0"/>
|
||||
<field name="perm_create" eval="0"/><field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record id="online_help_reader_rule" model="ir.rule">
|
||||
<field name="name">Online Help for Help Reader</field>
|
||||
<field name="model_id" ref="base.model_ir_ui_view"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(6, 0, [
|
||||
ref('help_online.help_online_group_reader'),
|
||||
])]"/>
|
||||
<field name="perm_read" eval="1"/><field name="perm_write" eval="0"/>
|
||||
<field name="perm_create" eval="0"/><field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
li.oe_help_online_not_found {
|
||||
a.o_help_online_not_found {
|
||||
background-color: #df3f3f;
|
||||
}
|
||||
|
||||
.openerp .oe_view_manager .oe_view_manager_switch .oe_list_button_help_online:after {
|
||||
font-size: 28px;
|
||||
content: "?";
|
||||
text-align: center;
|
||||
margin: 3px auto 4px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
|
@ -1,115 +1,86 @@
|
|||
openerp.help_online = function (instance) {
|
||||
var QWeb = instance.web.qweb;
|
||||
var _t = instance.web._t;
|
||||
var _lt = instance.web._lt;
|
||||
odoo.define('oca.HelpOnline', function (require) {
|
||||
"use strict";
|
||||
|
||||
instance.web.ListView.include({
|
||||
load_list: function () {
|
||||
var self = this;
|
||||
var add_button = false;
|
||||
if (!this.$buttons) {
|
||||
add_button = true;
|
||||
}
|
||||
var core = require('web.core');
|
||||
var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
var ViewManager = require('web.ViewManager');
|
||||
var ControlPanel = require('web.ControlPanel');
|
||||
var Dialog = require('web.Dialog');
|
||||
|
||||
ControlPanel.include({
|
||||
start: function(){
|
||||
this._super.apply(this, arguments);
|
||||
this.$buttons.on('click', '.oe_list_button_help_online', function() {
|
||||
self.do_action({
|
||||
type: 'ir.actions.act_url',
|
||||
url: '/partner_mobile',
|
||||
target: 'self',
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
openerp.web.TreeView.include({
|
||||
view_loading: function(r) {
|
||||
var ret = this._super(r);
|
||||
if(! _.isUndefined(this.ViewManager.load_help_buttons)){
|
||||
this.ViewManager.load_help_buttons();
|
||||
}
|
||||
return ret
|
||||
},
|
||||
});
|
||||
|
||||
openerp.web.ListView.include({
|
||||
view_loading: function(r) {
|
||||
var ret = this._super(r);
|
||||
if(! _.isUndefined(this.ViewManager.load_help_buttons)){
|
||||
this.ViewManager.load_help_buttons();
|
||||
}
|
||||
return ret
|
||||
},
|
||||
});
|
||||
|
||||
openerp.web.FormView.include({
|
||||
view_loading: function(r) {
|
||||
var ret = this._super(r);
|
||||
if(!_.isUndefined(this.ViewManager.clean_help_buttons)){
|
||||
this.ViewManager.clean_help_buttons();
|
||||
}
|
||||
return ret
|
||||
},
|
||||
|
||||
do_show: function (options){
|
||||
var ret = this._super(options);
|
||||
if(! _.isUndefined(this.ViewManager.load_help_buttons)){
|
||||
this.ViewManager.load_help_buttons();
|
||||
}
|
||||
return ret
|
||||
this._toggle_visibility(true);
|
||||
this.nodes = _.extend(
|
||||
this.nodes,
|
||||
{$help_online_buttons: this.$('.o_help_online_buttons')});
|
||||
this._toggle_visibility(false);
|
||||
},
|
||||
});
|
||||
|
||||
openerp.web.ViewManager.include({
|
||||
clean_help_buttons:function() {
|
||||
this.$el.find("div.oe_help_online_buttons").first().remove();
|
||||
ViewManager.include({
|
||||
|
||||
/**
|
||||
* This function render the help button with the informations received
|
||||
* from the call to the method build_url from the help_online controller
|
||||
*/
|
||||
render_help_button: function(url_info){
|
||||
var $helpButton = $(QWeb.render("HelpOnline.Button", {'view_manager':this, 'url_info': url_info}));
|
||||
$helpButton.tooltip();
|
||||
if (url_info.exists === false) {
|
||||
$helpButton.on('click', function (event) {
|
||||
var evt = event;
|
||||
evt.preventDefault();
|
||||
Dialog.confirm(
|
||||
self,
|
||||
_t('Page does not exist. Do you want to create?'),
|
||||
{confirm_callback: function() {
|
||||
var form = $("<form></form>");
|
||||
form.attr({
|
||||
id : "formform",
|
||||
// The location given in the link itself
|
||||
action : evt.target.href,
|
||||
method : "GET",
|
||||
// Open in new window/tab
|
||||
target : evt.target.target
|
||||
});
|
||||
$("body").append(form);
|
||||
$("#formform").submit();
|
||||
$("#formform").remove();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return $helpButton;
|
||||
},
|
||||
|
||||
load_help_buttons:function() {
|
||||
var self = this;
|
||||
this.rpc('/help_online/build_url', {model: this.dataset.model, view_type: this.active_view}).then(function(result) {
|
||||
self.clean_help_buttons();
|
||||
|
||||
/**
|
||||
* This function render the help buttons container on the view.
|
||||
* It should be called after start() by render_view_control_elements.
|
||||
* @param {control_elements} the list of control elements to display into the ControlPanel
|
||||
*/
|
||||
render_help_buttons: function(control_elements){
|
||||
if (! control_elements.$help_online_buttons){
|
||||
control_elements.$help_online_buttons = $('<div/>');
|
||||
}
|
||||
var self = this;
|
||||
this.rpc('/help_online/build_url', {model: this.dataset.model, view_type: this.active_view.type}).then(function(result) {
|
||||
if (result && ! _.isEmpty(result)) {
|
||||
self.$helpButtonsEl = $(QWeb.render("HelpOnline.Buttons", {'view_manager':self, 'url_info': result}));
|
||||
self.$el.find("ul.oe_view_manager_switch.oe_button_group.oe_right").first().before(self.$helpButtonsEl);
|
||||
self.$helpButtonsEl.find('a.oe_list_button_help_online').tooltip();
|
||||
if (result.exists === false) {
|
||||
self.$helpButtonsEl.find('li').addClass('oe_help_online_not_found')
|
||||
self.$helpButtonsEl.find('a.oe_list_button_help_online').on('click', function (event) {
|
||||
var evt = event;
|
||||
evt.preventDefault();
|
||||
var dialog = new instance.web.Dialog(this, {
|
||||
title: _t('Confirm'),
|
||||
buttons: [
|
||||
{text: _t("Cancel"), click: function() {
|
||||
this.parents('.modal').modal('hide');
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{text: _t("Ok"), click: function() {
|
||||
this.parents('.modal').modal('hide');
|
||||
var form = $("<form></form>");
|
||||
form.attr(
|
||||
{
|
||||
id : "formform",
|
||||
// The location given in the link itself
|
||||
action : evt.target.href,
|
||||
method : "GET",
|
||||
// Open in new window/tab
|
||||
target : evt.target.target
|
||||
});
|
||||
$("body").append(form);
|
||||
$("#formform").submit();
|
||||
$("#formform").remove();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
],
|
||||
}, $('<div/>').text(_t('Page does not exist. Do you want to create?'))).open();
|
||||
});
|
||||
}
|
||||
var $helpButton = self.render_help_button(result);
|
||||
control_elements.$help_online_buttons = $helpButton;
|
||||
// update the control panel with the new help button
|
||||
self.update_control_panel({cp_content: _.extend({}, self.searchview_elements, control_elements)}, {clear: false});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render_view_control_elements: function() {
|
||||
var control_elements = this._super.apply(this, arguments);
|
||||
this.render_help_buttons(control_elements);
|
||||
return control_elements;
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
var website = openerp.website;
|
||||
var _t = openerp._t;
|
||||
website.RTE.include({
|
||||
_config: function () {
|
||||
// add anchor button
|
||||
var config = this._super();
|
||||
config.plugins = config.plugins.concat(',link');
|
||||
_.each(config.toolbar, function (tb) {
|
||||
if (tb.name === 'span'){
|
||||
tb.items.unshift('Anchor');
|
||||
}
|
||||
});
|
||||
return config;
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -1,13 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates>
|
||||
<t t-name='HelpOnline.Buttons'>
|
||||
<div class='oe_help_online_buttons'>
|
||||
<ul class='oe_view_manager_switch oe_button_group oe_right'>
|
||||
<li class='oe_i'>
|
||||
<a class='oe_list_button_help_online'
|
||||
t-att-title='url_info.title'
|
||||
t-att-href='url_info.url' target='_blank'></a>
|
||||
</li>
|
||||
</ul>
|
||||
<t t-name='HelpOnline.Button'>
|
||||
<t t-if='url_info'>
|
||||
<a t-att-class="'fa fa-question-circle btn btn-icon o_help_online_button ' + (url_info.exists? '': 'o_help_online_not_found')"
|
||||
t-att-title='url_info.title' t-att-href='url_info.url'
|
||||
target='_blank'></a>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name='HelpOnline.ButtonsContainer'>
|
||||
<div class='hidden-xs btn-group btn-group-sm o_help_online_buttons'>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-extend="ControlPanel">
|
||||
<t t-jquery="div.o_cp_switch_buttons" t-operation="after">
|
||||
<t t-call='HelpOnline.ButtonsContainer' />
|
||||
</t>
|
||||
<t t-jquery="div.oe-cp-switch-buttons" t-operation="after">
|
||||
<t t-call='HelpOnline.ButtonsContainer' />
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-extend="X2ManyControlPanel">
|
||||
<t t-jquery="div.o_cp_pager" t-operation="after">
|
||||
<t t-call='HelpOnline.ButtonsContainer' />
|
||||
</t>
|
||||
<t t-jquery="div.oe-cp-pager" t-operation="after">
|
||||
<div class="pull-right">
|
||||
<t t-call='HelpOnline.ButtonsContainer' />
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
|
@ -1,27 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import test_help_online
|
||||
from . import test_export_help_wizard
|
||||
|
||||
fast_suite = [
|
||||
]
|
||||
|
||||
checks = [
|
||||
test_export_help_wizard,
|
||||
]
|
||||
from . import test_import_help_wizard
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import os
|
||||
import sys
|
||||
from lxml import etree as ET
|
||||
|
||||
from openerp.tools.convert import convert_xml_import
|
||||
|
||||
|
||||
class TestWizardCommon(object):
|
||||
_data_files = ('data/help_test_data.xml',)
|
||||
|
||||
_module_ns = 'help_online'
|
||||
|
||||
def createPage(self, pageName, imgXmlId=False):
|
||||
imgId = False
|
||||
if imgXmlId:
|
||||
imgId = self.ref(imgXmlId)
|
||||
|
||||
rootNode = ET.Element('t')
|
||||
rootNode.attrib['name'] = pageName
|
||||
rootNode.attrib['t-name'] = "website.%s" % pageName
|
||||
tNode = ET.SubElement(rootNode,
|
||||
't',
|
||||
attrib={'t-call': 'website.layout'})
|
||||
structDivNode = ET.SubElement(tNode,
|
||||
'div',
|
||||
attrib={'class': 'oe_structure oe_empty',
|
||||
'id': 'wrap'})
|
||||
sectionNode = ET.SubElement(structDivNode,
|
||||
'section',
|
||||
attrib={'class': 'mt16 mb16'})
|
||||
containerNode = ET.SubElement(sectionNode,
|
||||
'div',
|
||||
attrib={'class': 'container'})
|
||||
rowNode = ET.SubElement(containerNode,
|
||||
'div',
|
||||
attrib={'class': 'row'})
|
||||
bodyDivNode = ET.SubElement(rowNode,
|
||||
'div',
|
||||
attrib={'class': 'col-md-12 '
|
||||
'text-center mt16 mb32'})
|
||||
style = "font-family: 'Helvetica Neue', Helvetica,"\
|
||||
" Arial, sans-serif; color: rgb(51, 51, 51);"\
|
||||
" text-align: left;"
|
||||
h2Node = ET.SubElement(bodyDivNode,
|
||||
'h2',
|
||||
attrib={'style': style})
|
||||
h2Node.text = "Test Sample Title"
|
||||
if imgId:
|
||||
imgDivNode = ET.SubElement(bodyDivNode,
|
||||
'div',
|
||||
attrib={'style': 'text-align: left;'})
|
||||
src = "/website/image?field=datas&"\
|
||||
"model=ir.attachment&id=%s" % str(imgId)
|
||||
ET.SubElement(imgDivNode,
|
||||
'img',
|
||||
attrib={'class': 'img-thumbnail',
|
||||
'src': src})
|
||||
imgDivNode = ET.SubElement(bodyDivNode,
|
||||
'div',
|
||||
attrib={'style': 'text-align: left;'})
|
||||
src = "/website/image/ir.attachment/%s_ccc838d/datas" % str(imgId)
|
||||
ET.SubElement(imgDivNode,
|
||||
'img',
|
||||
attrib={'class': 'img-thumbnail',
|
||||
'src': src})
|
||||
imgDivNode = ET.SubElement(bodyDivNode,
|
||||
'div',
|
||||
attrib={'style': 'text-align: left;'})
|
||||
src = "/web/image/%s" % str(imgId)
|
||||
ET.SubElement(imgDivNode,
|
||||
'img',
|
||||
attrib={'class': 'img-thumbnail',
|
||||
'src': src})
|
||||
arch = ET.tostring(rootNode, encoding='utf-8', xml_declaration=False)
|
||||
vals = {
|
||||
'name': pageName,
|
||||
'type': 'qweb',
|
||||
'arch': arch,
|
||||
'page': True,
|
||||
}
|
||||
view_id = self.env['ir.ui.view'].create(vals)
|
||||
return view_id.id
|
||||
|
||||
def setUp(self):
|
||||
super(TestWizardCommon, self).setUp()
|
||||
self.pageName = False
|
||||
self.imgXmlId = False
|
||||
self.pageTemplate = False
|
||||
# Loads the data file before
|
||||
module = sys.modules[self.__class__.__module__]
|
||||
base_path = os.path.dirname(module.__file__)
|
||||
for path in self._data_files:
|
||||
path = path.split('/')
|
||||
path.insert(0, base_path)
|
||||
path = os.path.join(*path)
|
||||
convert_xml_import(self.cr, self._module_ns, path)
|
|
@ -75,4 +75,4 @@ YFBaQ6YYbTbt679Y0nIRIfKXS1d/8J7oqRWRGxO2b92S+NyzK2n3aAwoCf/7jpEfsQAoxU3nESI/
|
|||
<field name="mimetype">image/png</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</openerp>
|
||||
|
|
|
@ -1,105 +1,17 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Cédric Pigeon
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import logging
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import base64
|
||||
from lxml import etree as ET
|
||||
|
||||
from anybox.testing.openerp import SharedSetupTransactionCase
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
import openerp.tests.common as common
|
||||
from .common import TestWizardCommon
|
||||
|
||||
|
||||
class test_export_help_wizard(object):
|
||||
_data_files = ('data/help_test_data.xml',)
|
||||
|
||||
_module_ns = 'help_online'
|
||||
|
||||
def createPage(self, pageName, imgXmlId=False):
|
||||
imgId = False
|
||||
if imgXmlId:
|
||||
imgId = self.ref('%s.%s' % (self._module_ns, imgXmlId))
|
||||
|
||||
rootNode = ET.Element('t')
|
||||
rootNode.attrib['name'] = pageName
|
||||
rootNode.attrib['t-name'] = "website.%s" % pageName
|
||||
tNode = ET.SubElement(rootNode,
|
||||
't',
|
||||
attrib={'t-call': 'website.layout'})
|
||||
structDivNode = ET.SubElement(tNode,
|
||||
'div',
|
||||
attrib={'class': 'oe_structure oe_empty',
|
||||
'id': 'wrap'})
|
||||
sectionNode = ET.SubElement(structDivNode,
|
||||
'section',
|
||||
attrib={'class': 'mt16 mb16'})
|
||||
containerNode = ET.SubElement(sectionNode,
|
||||
'div',
|
||||
attrib={'class': 'container'})
|
||||
rowNode = ET.SubElement(containerNode,
|
||||
'div',
|
||||
attrib={'class': 'row'})
|
||||
bodyDivNode = ET.SubElement(rowNode,
|
||||
'div',
|
||||
attrib={'class': 'col-md-12 '
|
||||
'text-center mt16 mb32'})
|
||||
style = "font-family: 'Helvetica Neue', Helvetica,"\
|
||||
" Arial, sans-serif; color: rgb(51, 51, 51);"\
|
||||
" text-align: left;"
|
||||
h2Node = ET.SubElement(bodyDivNode,
|
||||
'h2',
|
||||
attrib={'style': style})
|
||||
h2Node.text = "Test Sample Title"
|
||||
if imgId:
|
||||
imgDivNode = ET.SubElement(bodyDivNode,
|
||||
'div',
|
||||
attrib={'style': 'text-align: left;'})
|
||||
src = "/website/image?field=datas&"\
|
||||
"model=ir.attachment&id=%s" % str(imgId)
|
||||
ET.SubElement(imgDivNode,
|
||||
'img',
|
||||
attrib={'class': 'img-thumbnail',
|
||||
'src': src})
|
||||
imgDivNode = ET.SubElement(bodyDivNode,
|
||||
'div',
|
||||
attrib={'style': 'text-align: left;'})
|
||||
src = "/website/image/ir.attachment/%s_ccc838d/datas" % str(imgId)
|
||||
ET.SubElement(imgDivNode,
|
||||
'img',
|
||||
attrib={'class': 'img-thumbnail',
|
||||
'src': src})
|
||||
arch = ET.tostring(rootNode, encoding='utf-8', xml_declaration=False)
|
||||
vals = {
|
||||
'name': pageName,
|
||||
'type': 'qweb',
|
||||
'arch': arch,
|
||||
'page': True,
|
||||
}
|
||||
view_id = self.env['ir.ui.view'].create(vals)
|
||||
return view_id.id
|
||||
|
||||
def setUp(self):
|
||||
super(test_export_help_wizard, self).setUp()
|
||||
self.pageName = False
|
||||
self.imgXmlId = False
|
||||
self.pageTemplate = False
|
||||
class TestExportHelpWizard(TestWizardCommon):
|
||||
pageName = None
|
||||
imgXmlId = None
|
||||
|
||||
def test_export_help(self):
|
||||
"""
|
||||
|
@ -123,7 +35,8 @@ class test_export_help_wizard(object):
|
|||
if self.imgXmlId:
|
||||
xPath = ".//record[@id='%s']" % self.imgXmlId
|
||||
imgNodeList = rootXml.findall(xPath)
|
||||
self.assertEqual(len(imgNodeList), 2)
|
||||
self.assertEqual(len(imgNodeList), 1,
|
||||
'The same image should be exported only once')
|
||||
|
||||
for imgElem in templateNodeList[0].iter('img'):
|
||||
imgSrc = imgElem.get('src')
|
||||
|
@ -131,7 +44,7 @@ class test_export_help_wizard(object):
|
|||
self.assertIn("/ir.attachment/%s|"
|
||||
% self.imgXmlId, imgSrc)
|
||||
else:
|
||||
self.assertIn("id=%s" % self.imgXmlId, imgSrc)
|
||||
self.assertIn("/web/image/%s" % self.imgXmlId, imgSrc)
|
||||
|
||||
if self.pageTemplate:
|
||||
xPath = ".//template[@id='website.%s_snippet']" % self.pageName
|
||||
|
@ -140,20 +53,18 @@ class test_export_help_wizard(object):
|
|||
self.assertNotIn("website.", templateNodeList[0].attrib['name'])
|
||||
|
||||
|
||||
class test_export_help_with_image(test_export_help_wizard,
|
||||
SharedSetupTransactionCase):
|
||||
class TestExportHelpWithImage(TestExportHelpWizard, common.TransactionCase):
|
||||
def setUp(self):
|
||||
super(test_export_help_with_image, self).setUp()
|
||||
super(TestExportHelpWithImage, self).setUp()
|
||||
parameter_model = self.env['ir.config_parameter']
|
||||
page_prefix = parameter_model.get_param('help_online_page_prefix')
|
||||
self.pageName = '%stest-page' % page_prefix
|
||||
self.imgXmlId = 'test_img_1'
|
||||
self.imgXmlId = '%s.test_img_1' % self._module_ns
|
||||
|
||||
|
||||
class test_export_help_template(test_export_help_wizard,
|
||||
SharedSetupTransactionCase):
|
||||
class TestExportHelpTemplate(TestExportHelpWizard, common.TransactionCase):
|
||||
def setUp(self):
|
||||
super(test_export_help_template, self).setUp()
|
||||
super(TestExportHelpTemplate, self).setUp()
|
||||
parameter_model = self.env['ir.config_parameter']
|
||||
param = 'help_online_template_prefix'
|
||||
template_prefix = parameter_model.get_param(param)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import mock
|
||||
|
||||
import openerp.tests.common as common
|
||||
from .common import TestWizardCommon
|
||||
|
||||
|
||||
class TestHelpOnline(TestWizardCommon, common.TransactionCase):
|
||||
|
||||
def test_get_page_url(self):
|
||||
model = 'res.partner'
|
||||
help_online = self.env['help.online']
|
||||
user = self.env.user
|
||||
group_writer = self.env.ref('help_online.help_online_group_writer')
|
||||
group_reader = self.env.ref('help_online.help_online_group_reader')
|
||||
self.assertTrue(user.has_group('help_online.help_online_group_writer'))
|
||||
with mock.patch('openerp.addons.website.models.website'
|
||||
'.website.search_pages') as search_pages:
|
||||
# The expected page dosn't exist
|
||||
search_pages.return_value = []
|
||||
info = help_online.get_page_url(model, 'form')
|
||||
self.assertDictEqual(
|
||||
{'exists': False,
|
||||
'title': 'Create Help page for Partner',
|
||||
'url': 'website/add/help-res-partner'}, info,
|
||||
"If the user is member of help_online_group_writer "
|
||||
"and the page doesn't exist, the module should return an url "
|
||||
"to create the page")
|
||||
# remove user of group writer.
|
||||
group_writer.write({'users': [(3, self.env.user.id)]})
|
||||
info = help_online.get_page_url(model, 'form')
|
||||
self.assertDictEqual(
|
||||
{}, info,
|
||||
"If the user is not member of help_online_group_writer "
|
||||
"and the page doesn't exist, the module should return an "
|
||||
"empty dict")
|
||||
# The expected page exists
|
||||
search_pages.return_value = [{'loc': 'pages/help-res-partner'}]
|
||||
self.assertTrue(
|
||||
user.has_group('help_online.help_online_group_reader'))
|
||||
info = help_online.get_page_url(model, 'form')
|
||||
self.assertDictEqual(
|
||||
{'exists': True,
|
||||
'title': 'Help on Partner',
|
||||
'url': 'pages/help-res-partner#form'}, info,
|
||||
"If the user is member of help_online_group_reader "
|
||||
"and the page exists, the module should return an url "
|
||||
"to the page")
|
||||
# remove user from group reader
|
||||
group_reader.write({'users': [(3, self.env.user.id)]})
|
||||
info = help_online.get_page_url(model, 'form')
|
||||
self.assertDictEqual(
|
||||
{}, info,
|
||||
"If the user is not member of help_online_group_reader "
|
||||
"and the page exists, the module should return an empty dict")
|
|
@ -0,0 +1,59 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import base64
|
||||
|
||||
import openerp.tests.common as common
|
||||
from .common import TestWizardCommon
|
||||
|
||||
|
||||
class TestImportHelpWizard(TestWizardCommon, common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestImportHelpWizard, self).setUp()
|
||||
self.page_name = "export_import_help"
|
||||
self.img_xml_id = '%s.test_img_1' % self._module_ns
|
||||
self.img_name = self.env.ref(self.img_xml_id).name
|
||||
self.ir_attchement = self.env['ir.attachment']
|
||||
self.ir_ui_view = self.env['ir.ui.view']
|
||||
self.export_help_wizard = self.env['export.help.wizard']
|
||||
self.import_help_wizard = self.env['import.help.wizard']
|
||||
|
||||
def _do_check_resources(self, expected=1):
|
||||
pages = self.ir_ui_view.search([('name', '=', self.page_name)])
|
||||
self.assertEqual(expected, len(pages))
|
||||
attachments = self.ir_attchement.search(
|
||||
[('name', '=', self.img_name)])
|
||||
self.assertEqual(expected, len(attachments))
|
||||
|
||||
def test_import_help(self):
|
||||
self.createPage(pageName=self.page_name, imgXmlId=self.img_xml_id)
|
||||
self._do_check_resources()
|
||||
wizard = self.export_help_wizard.create({})
|
||||
wizard.export_help()
|
||||
xmlData = base64.decodestring(wizard.data)
|
||||
self.env.ref(self.img_xml_id).unlink()
|
||||
self.ir_ui_view.search([('name', '=', self.page_name)]).unlink()
|
||||
self._do_check_resources(0)
|
||||
wizard = self.import_help_wizard.create({
|
||||
'source_file': base64.encodestring(xmlData)
|
||||
})
|
||||
wizard.import_help()
|
||||
self._do_check_resources()
|
||||
|
||||
def test_import_export_help(self):
|
||||
"""Check that exported data are not ducplicated by export / import
|
||||
"""
|
||||
self.createPage(pageName=self.page_name, imgXmlId=self.img_xml_id)
|
||||
self._do_check_resources()
|
||||
# export
|
||||
wizard = self.export_help_wizard.create({})
|
||||
wizard.export_help()
|
||||
xmlData = base64.decodestring(wizard.data)
|
||||
self._do_check_resources()
|
||||
wizard = self.import_help_wizard.create({
|
||||
'source_file': base64.encodestring(xmlData)
|
||||
})
|
||||
wizard.import_help()
|
||||
self._do_check_resources()
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="export_help_wizard_view">
|
||||
<field name="name">export.help.wizard.view</field>
|
||||
<field name="model">export.help.wizard</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Export Help Data">
|
||||
<group colspan="2">
|
||||
<field name="export_filename"
|
||||
invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<p>
|
||||
This wizard allow you to export all QWeb views
|
||||
related to help online. The result will be an Odoo
|
||||
data xml file.
|
||||
</p>
|
||||
</group>
|
||||
<group>
|
||||
<field name="data"
|
||||
nolabel="1"
|
||||
readonly="1"
|
||||
filename="export_filename" />
|
||||
</group>
|
||||
<footer>
|
||||
<span name="go-wizard" attrs="{'invisible': [('export_filename', '!=', False)]}">
|
||||
<button name="export_help"
|
||||
string="Export"
|
||||
type="object"
|
||||
icon="gtk-execute"
|
||||
class="oe_highlight" />
|
||||
or
|
||||
</span>
|
||||
<button string="Close" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_export_help_wizard">
|
||||
<field name="name">Export Help</field>
|
||||
<field name="res_model">export.help.wizard</field>
|
||||
<field name="view_id" ref="export_help_wizard_view"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,28 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- vim:fdn=3:
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="assets_backend" name="help.online.assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/help_online/static/src/css/help_online.css" type="text/css"/>
|
||||
<script type="text/javascript" src="/help_online/static/src/js/help_online.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_website_pages">
|
||||
<field name="name">Website Pages</field>
|
||||
<field name="res_model">ir.ui.view</field>
|
||||
<field name="search_view_id" ref="view_view_search" />
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{"search_default_website":1}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_help_main" name="Help Online" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help" name="Help Online" parent="menu_help_main" sequence="90" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help_pages" name="Website Pages" parent="menu_help" sequence="10" action="action_website_pages" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help_import" name="Import Help Online" parent="menu_help" sequence="20" action="action_import_help_wizard" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help_export" name="Export Help Online" parent="menu_help" sequence="30" action="action_export_help_wizard" groups="help_online_group_writer"/>
|
||||
</data>
|
||||
</openerp>
|
||||
<odoo>
|
||||
<template id="assets_backend" name="help.online.assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/help_online/static/src/css/help_online.css" type="text/css"/>
|
||||
<script type="text/javascript" src="/help_online/static/src/js/help_online.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_website_pages">
|
||||
<field name="name">Website Pages</field>
|
||||
<field name="res_model">ir.ui.view</field>
|
||||
<field name="search_view_id" ref="view_view_search" />
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{"search_default_website":1}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_help_main" name="Help Online" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help" name="Help Online" parent="menu_help_main" sequence="90" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help_pages" name="Website Pages" parent="menu_help" sequence="10" action="action_website_pages" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help_import" name="Import Help Online" parent="menu_help" sequence="20" action="action_import_help_wizard" groups="help_online_group_writer"/>
|
||||
<menuitem id="menu_help_export" name="Export Help Online" parent="menu_help" sequence="30" action="action_export_help_wizard" groups="help_online_group_writer"/>
|
||||
</odoo>
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="import_help_wizard_view">
|
||||
<field name="name">import.help.wizard.view</field>
|
||||
<field name="model">import.help.wizard</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Import Help Data">
|
||||
<group>
|
||||
<p>
|
||||
This wizard allow you to import QWeb views
|
||||
related to help online. The required file format is an Odoo
|
||||
data xml file.
|
||||
</p>
|
||||
</group>
|
||||
<group>
|
||||
<field name="source_file"/>
|
||||
</group>
|
||||
<footer>
|
||||
<span name="go-wizard" attrs="{'invisible': [('source_file', '=', False)]}">
|
||||
<button name="import_help"
|
||||
string="Import"
|
||||
type="object"
|
||||
icon="gtk-execute"
|
||||
class="oe_highlight" />
|
||||
or
|
||||
</span>
|
||||
<button string="Close" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_import_help_wizard">
|
||||
<field name="name">Import Help</field>
|
||||
<field name="res_model">import.help.wizard</field>
|
||||
<field name="view_id" ref="import_help_wizard_view"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,28 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="0">
|
||||
<odoo>
|
||||
<record id="view_view_search" model="ir.ui.view">
|
||||
<field name="name">ir.ui.view search (help_online)</field>
|
||||
<field name="inherit_id" ref="base.view_view_search"/>
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[last()]" position="after">
|
||||
<filter name="website" string="Website Page" domain="[('type', '=', 'qweb'),('page', '=', True)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_view_search" model="ir.ui.view">
|
||||
<field name="name">ir.ui.view search (help_online)</field>
|
||||
<field name="inherit_id" ref="base.view_view_search"/>
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[@string='QWeb']" position="after">
|
||||
<filter name="website" string="Website Page" domain="[('type', '=', 'qweb'),('page', '=', True)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_view_form" model="ir.ui.view">
|
||||
<field name="name">ir.ui.view form (help_online)</field>
|
||||
<field name="inherit_id" ref="base.view_view_form"/>
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='type']" position="after">
|
||||
<field name="page" string="Website Page?" readonly="1" attrs="{'invisible': [('type', '!=', 'qweb')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
<record id="view_view_form" model="ir.ui.view">
|
||||
<field name="name">ir.ui.view form (help_online)</field>
|
||||
<field name="inherit_id" ref="base.view_view_form"/>
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='type']" position="after">
|
||||
<field name="page" string="Website Page?" readonly="1" attrs="{'invisible': [('type', '!=', 'qweb')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="assets_editor" inherit_id="website.assets_editor" name="Help online customization">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/help_online/static/src/js/website_help_online.editor.js" groups="base.group_website_publisher"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import export_help_wizard
|
||||
from . import import_help_wizard
|
|
@ -1,31 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Authors: Cédric Pigeon
|
||||
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
import base64
|
||||
import time
|
||||
import copy
|
||||
|
||||
import urlparse
|
||||
from werkzeug.routing import Map, Rule
|
||||
from lxml import etree as ET
|
||||
from openerp import models, fields, api, exceptions
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.web.controllers.main import Binary
|
||||
from openerp.addons.website.controllers.main import WebsiteBinary
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -43,94 +30,114 @@ class ExportHelpWizard(models.TransientModel):
|
|||
data = fields.Binary('XML', readonly=True)
|
||||
export_filename = fields.Char('Export XML Filename', size=128)
|
||||
|
||||
def _manage_images_on_page(self, page_node, data_node, images_reference):
|
||||
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 a xml node
|
||||
- Extract images from page and generate an xml node
|
||||
- Replace db id in url with xml id
|
||||
"""
|
||||
|
||||
def get_attach_id(images_reference,
|
||||
img_model, img_src, generated_xml_id=False):
|
||||
attach_id = False
|
||||
if 'id=' in img_src:
|
||||
id_pos = img_src.index('id=') + 3
|
||||
attach_id = img_src[id_pos:]
|
||||
else:
|
||||
fragments = img_src.split('ir.attachment/')
|
||||
attach_id, _ = fragments[1].split('_', 1)
|
||||
|
||||
if attach_id in images_reference:
|
||||
xml_id = images_reference[attach_id]
|
||||
else:
|
||||
ir_data = self.env['ir.model.data'].search(
|
||||
[('model', '=', img_model),
|
||||
('res_id', '=', attach_id)])
|
||||
xml_id = generated_xml_id
|
||||
if ir_data:
|
||||
xml_id = ir_data[0].name
|
||||
images_reference[attach_id] = xml_id
|
||||
|
||||
return attach_id, xml_id
|
||||
|
||||
def substitute_id_by_xml_id(img_src, attach_id, xml_id):
|
||||
new_src = False
|
||||
if 'id=' in img_src:
|
||||
new_src = img_src.replace(attach_id, xml_id)
|
||||
else:
|
||||
fragments = img_src.split('ir.attachment/')
|
||||
_, trail = fragments[1].split('_', 1)
|
||||
new_src = "/website/image/ir.attachment/%s|%s" % \
|
||||
(xml_id, trail)
|
||||
return new_src
|
||||
|
||||
i_img = 0
|
||||
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')
|
||||
if img_model in img_src:
|
||||
i_img += 1
|
||||
generated_xml_id = "%s_img_%s" % \
|
||||
(page_node.attrib['name'], str(i_img).rjust(2, '0'))
|
||||
attach_id, xml_id = get_attach_id(images_reference,
|
||||
img_model,
|
||||
img_src,
|
||||
generated_xml_id)
|
||||
|
||||
new_src = substitute_id_by_xml_id(img_src, attach_id, xml_id)
|
||||
|
||||
if not attach_id:
|
||||
continue
|
||||
|
||||
image = self.env[img_model].browse(int(attach_id))
|
||||
if not image:
|
||||
continue
|
||||
|
||||
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
|
||||
img_node = ET.SubElement(data_node,
|
||||
'record',
|
||||
attrib={'id': xml_id,
|
||||
'model': img_model})
|
||||
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(image.datas)
|
||||
field_node.text = str(exported_data[1])
|
||||
field_node = ET.SubElement(img_node,
|
||||
'field',
|
||||
attrib={'name': 'datas_fname'})
|
||||
field_node.text = image.datas_fname
|
||||
field_node.text = exported_data[2]
|
||||
field_node = ET.SubElement(img_node,
|
||||
'field',
|
||||
attrib={'name': 'name'})
|
||||
field_node.text = image.name
|
||||
field_node.text = exported_data[3]
|
||||
field_node = ET.SubElement(img_node,
|
||||
'field',
|
||||
attrib={'name': 'res_model'})
|
||||
field_node.text = image.res_model
|
||||
field_node.text = exported_data[4]
|
||||
field_node = ET.SubElement(img_node,
|
||||
'field',
|
||||
attrib={'name': 'mimetype'})
|
||||
field_node.text = image.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):
|
||||
"""
|
||||
|
@ -216,39 +223,67 @@ class ExportHelpWizard(models.TransientModel):
|
|||
('name', 'like', '%s%%' % page_prefix),
|
||||
('name', 'like', '%s%%' % template_prefix)]
|
||||
|
||||
view_data_list = self.env['ir.ui.view'].search_read(domain,
|
||||
['arch', 'name'],
|
||||
order='name')
|
||||
ir_ui_views = self.env['ir.ui.view'].search(domain, order='name')
|
||||
xml_to_export = ET.Element('openerp')
|
||||
data_node = ET.SubElement(xml_to_export, 'data')
|
||||
images_reference = {}
|
||||
for view_data in view_data_list:
|
||||
exported_resources = set()
|
||||
for ir_ui_view in ir_ui_views:
|
||||
parser = ET.XMLParser(remove_blank_text=True)
|
||||
root = ET.XML(view_data['arch'], parser=parser)
|
||||
|
||||
root = ET.XML(ir_ui_view.arch, parser=parser)
|
||||
root.tag = 'template'
|
||||
template_id = root.attrib.pop('t-name')
|
||||
root.attrib['name'] = view_data['name'].replace('website.', '')
|
||||
root.attrib['id'] = template_id
|
||||
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'
|
||||
|
||||
self._manage_images_on_page(root, data_node, images_reference)
|
||||
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,
|
||||
template_id,
|
||||
xml_id,
|
||||
template_prefix)
|
||||
data_node.append(snippet)
|
||||
|
||||
if len(view_data_list) > 0:
|
||||
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('.')
|
||||
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):
|
||||
"""
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="export_help_wizard_view">
|
||||
<field name="name">export.help.wizard.view</field>
|
||||
<field name="model">export.help.wizard</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Export Help Data">
|
||||
<group colspan="2">
|
||||
<field name="export_filename"
|
||||
invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<p>
|
||||
This wizard allow you to export all QWeb views
|
||||
related to help online. The result will be an Odoo
|
||||
data xml file.
|
||||
</p>
|
||||
</group>
|
||||
<group>
|
||||
<field name="data"
|
||||
nolabel="1"
|
||||
readonly="1"
|
||||
filename="export_filename" />
|
||||
</group>
|
||||
<footer>
|
||||
<span name="go-wizard" attrs="{'invisible': [('export_filename', '!=', False)]}">
|
||||
<button name="export_help"
|
||||
string="Export"
|
||||
type="object"
|
||||
icon="gtk-execute"
|
||||
class="oe_highlight" />
|
||||
or
|
||||
</span>
|
||||
<button string="Close" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_export_help_wizard">
|
||||
<field name="name">Export Help</field>
|
||||
<field name="res_model">export.help.wizard</field>
|
||||
<field name="view_id" ref="export_help_wizard_view"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
</record>
|
||||
</odoo>
|
|
@ -0,0 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 ACSONE SA/NV (<http://acsone.eu>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import base64
|
||||
from cStringIO import StringIO
|
||||
from lxml import etree
|
||||
import logging
|
||||
import os
|
||||
|
||||
from openerp import api, fields, models
|
||||
from openerp.tools import convert, misc
|
||||
from openerp.tools.config import config
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XmlImport(convert.xml_import):
|
||||
"""Override base xml_import to be able to import record with an exported
|
||||
xml_id ('__export__.XXX-XXX')
|
||||
"""
|
||||
|
||||
def _test_xml_id(self, xml_id):
|
||||
if '.' in xml_id:
|
||||
module, _id = xml_id.split('.')
|
||||
if module == '__export__':
|
||||
return True
|
||||
super(XmlImport, self)._test_xml_id(xml_id)
|
||||
|
||||
|
||||
class ImportHelpWizard(models.TransientModel):
|
||||
_name = "import.help.wizard"
|
||||
|
||||
source_file = fields.Binary('Source File')
|
||||
|
||||
@api.multi
|
||||
def import_help(self):
|
||||
for this in self:
|
||||
xmlfile = StringIO(base64.decodestring(this.source_file))
|
||||
doc = etree.parse(xmlfile)
|
||||
relaxng = etree.RelaxNG(
|
||||
etree.parse(
|
||||
os.path.join(config['root_path'], 'import_xml.rng')))
|
||||
try:
|
||||
relaxng.assert_(doc)
|
||||
except Exception:
|
||||
_logger.info('The XML file does not fit the required schema !',
|
||||
exc_info=True)
|
||||
_logger.info(misc.ustr(relaxng.error_log.last_error))
|
||||
raise
|
||||
obj = XmlImport(self.env.cr, self._module, idref={}, mode='init',
|
||||
report=None, noupdate=False, xml_filename=None)
|
||||
obj.parse(doc.getroot(), mode='init')
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="import_help_wizard_view">
|
||||
<field name="name">import.help.wizard.view</field>
|
||||
<field name="model">import.help.wizard</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Import Help Data">
|
||||
<group>
|
||||
<p>
|
||||
This wizard allow you to import QWeb views
|
||||
related to help online. The required file format is an Odoo
|
||||
data xml file.
|
||||
</p>
|
||||
</group>
|
||||
<group>
|
||||
<field name="source_file"/>
|
||||
</group>
|
||||
<footer>
|
||||
<span name="go-wizard" attrs="{'invisible': [('source_file', '=', False)]}">
|
||||
<button name="import_help"
|
||||
string="Import"
|
||||
type="object"
|
||||
icon="gtk-execute"
|
||||
class="oe_highlight" />
|
||||
or
|
||||
</span>
|
||||
<button string="Close" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_import_help_wizard">
|
||||
<field name="name">Import Help</field>
|
||||
<field name="res_model">import.help.wizard</field>
|
||||
<field name="view_id" ref="import_help_wizard_view"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
</record>
|
||||
</odoo>
|
|
@ -0,0 +1 @@
|
|||
__import__('pkg_resources').declare_namespace(__name__)
|
|
@ -0,0 +1 @@
|
|||
../../../help_online
|
|
@ -0,0 +1,6 @@
|
|||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
Loading…
Reference in New Issue