summaryrefslogtreecommitdiff
path: root/addons/base_import_module
diff options
context:
space:
mode:
authorDharmraj Jhala (OpenERP) <dizzy.zala@gmail.com>2014-04-02 11:04:58 +0530
committerDharmraj Jhala (OpenERP) <dizzy.zala@gmail.com>2014-04-02 11:04:58 +0530
commit4d320b6ecab32e13bcfff34f1cf7489a2bd78d35 (patch)
tree8cbfe260c8abdf641ad8ec3a781ea818abbb97c0 /addons/base_import_module
parent9f1400624fbf37c152629b6f0594bd8e1c1db72d (diff)
parentf07e0ff8c5dc8baab64bc4a33d8566e5fbb4df23 (diff)
[MERGE] with parent branch
bzr revid: dizzy.zala@gmail.com-20140402053458-ayv0j753nzpw1mm9
Diffstat (limited to 'addons/base_import_module')
-rw-r--r--addons/base_import_module/__init__.py2
-rw-r--r--addons/base_import_module/__openerp__.py21
-rwxr-xr-xaddons/base_import_module/bin/oe_module_deploy.py86
-rw-r--r--addons/base_import_module/controllers/__init__.py1
-rw-r--r--addons/base_import_module/controllers/main.py73
-rw-r--r--addons/base_import_module/models/__init__.py2
-rw-r--r--addons/base_import_module/models/ir_module.py71
-rw-r--r--addons/base_import_module/tests/test_module/__openerp__.py37
-rw-r--r--addons/base_import_module/tests/test_module/static/src/img/c64.pngbin0 -> 24385 bytes
-rw-r--r--addons/base_import_module/tests/test_module/static/src/js/test.js1
-rw-r--r--addons/base_import_module/tests/test_module/test.xml45
11 files changed, 339 insertions, 0 deletions
diff --git a/addons/base_import_module/__init__.py b/addons/base_import_module/__init__.py
new file mode 100644
index 00000000000..9f86759e32b
--- /dev/null
+++ b/addons/base_import_module/__init__.py
@@ -0,0 +1,2 @@
+import controllers
+import models
diff --git a/addons/base_import_module/__openerp__.py b/addons/base_import_module/__openerp__.py
new file mode 100644
index 00000000000..ba37462642c
--- /dev/null
+++ b/addons/base_import_module/__openerp__.py
@@ -0,0 +1,21 @@
+{
+ 'name': 'Base import module',
+ 'description': """
+Import a custom data module
+===========================
+
+This module allows authorized users to import a custom data module (.xml files and static assests)
+for customization purpose.
+""",
+ 'category': 'Uncategorized',
+ 'website': 'http://www.openerp.com',
+ 'author': 'OpenERP SA',
+ 'depends': ['web'],
+ 'installable': True,
+ 'auto_install': False,
+ 'data': [],
+ 'css': [],
+ 'js': [],
+ 'qweb': [],
+ 'test': [],
+}
diff --git a/addons/base_import_module/bin/oe_module_deploy.py b/addons/base_import_module/bin/oe_module_deploy.py
new file mode 100755
index 00000000000..2412382cba5
--- /dev/null
+++ b/addons/base_import_module/bin/oe_module_deploy.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+import argparse
+import os
+import sys
+import tempfile
+import zipfile
+
+
+try:
+ import requests
+except ImportError:
+ # no multipart encoding in stdlib and this script is temporary
+ sys.exit("This script requires the 'requests' module. ( pip install requests )")
+
+session = requests.session()
+
+def deploy_module(module_path, url, login, password, db=''):
+ url = url.rstrip('/')
+ authenticate(url, login, password, db)
+ module_file = zip_module(module_path)
+ try:
+ return upload_module(url, module_file)
+ finally:
+ os.remove(module_file)
+
+def upload_module(server, module_file):
+ print("Uploading module file...")
+ url = server + '/base_import_module/upload'
+ files = dict(mod_file=open(module_file, 'rb'))
+ res = session.post(url, files=files)
+ if res.status_code != 200:
+ raise Exception("Could not authenticate on server '%s'" % server)
+ return res.text
+
+def authenticate(server, login, password, db=''):
+ print("Authenticating on server '%s' ..." % server)
+
+ # Fixate session with a given db if any
+ session.get(server + '/web/login', params=dict(db=db))
+
+ args = dict(login=login, password=password, db=db)
+ res = session.post(server + '/base_import_module/login', args)
+ if res.status_code == 404:
+ raise Exception("The server '%s' does not have the 'base_import_module' installed." % server)
+ elif res.status_code != 200:
+ raise Exception(res.text)
+
+def zip_module(path):
+ path = os.path.abspath(path)
+ if not os.path.isdir(path):
+ raise Exception("Could not find module directory '%s'" % path)
+ container, module_name = os.path.split(path)
+ temp = tempfile.mktemp(suffix='.zip')
+ try:
+ print("Zipping module directory...")
+ with zipfile.ZipFile(temp, 'w') as zfile:
+ for root, dirs, files in os.walk(path):
+ for file in files:
+ file_path = os.path.join(root, file)
+ zfile.write(file_path, file_path.split(container).pop())
+ return temp
+ except Exception:
+ os.remove(temp)
+ raise
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Deploy a module on an OpenERP server.')
+ parser.add_argument('path', help="Path of the module to deploy")
+ parser.add_argument('--url', dest='url', help='Url of the server (default=http://localhost:8069)', default="http://localhost:8069")
+ parser.add_argument('--db', dest='db', help='Database to use if server does not use db-filter.')
+ parser.add_argument('--login', dest='login', default="admin", help='Login (default=admin)')
+ parser.add_argument('--password', dest='password', default="admin", help='Password (default=admin)')
+ parser.add_argument('--no-ssl-check', dest='no_ssl_check', action='store_true', help='Do not check ssl cert')
+ if len(sys.argv) == 1:
+ sys.exit(parser.print_help())
+
+ args = parser.parse_args()
+
+ if args.no_ssl_check:
+ session.verify = False
+
+ try:
+ result = deploy_module(args.path, args.url, args.login, args.password, args.db)
+ print(result)
+ except Exception, e:
+ sys.exit("ERROR: %s" % e)
diff --git a/addons/base_import_module/controllers/__init__.py b/addons/base_import_module/controllers/__init__.py
new file mode 100644
index 00000000000..8ee9bae18d9
--- /dev/null
+++ b/addons/base_import_module/controllers/__init__.py
@@ -0,0 +1 @@
+import main
diff --git a/addons/base_import_module/controllers/main.py b/addons/base_import_module/controllers/main.py
new file mode 100644
index 00000000000..cbfbd75894b
--- /dev/null
+++ b/addons/base_import_module/controllers/main.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+import functools
+import os
+import zipfile
+from os.path import join as opj
+
+import openerp
+from openerp.http import Controller, route, request, Response
+
+MAX_FILE_SIZE = 100 * 1024 * 1024 # in megabytes
+
+def webservice(f):
+ @functools.wraps(f)
+ def wrap(*args, **kw):
+ try:
+ return f(*args, **kw)
+ except Exception, e:
+ return Response(response=str(e), status=500)
+ return wrap
+
+class ImportModule(Controller):
+
+ def check_user(self, uid=None):
+ if uid is None:
+ uid = request.uid
+ is_admin = request.registry['res.users'].has_group(request.cr, uid, 'base.group_erp_manager')
+ if not is_admin:
+ raise openerp.exceptions.AccessError("Only administrators can upload a module")
+
+ @route('/base_import_module/login', type='http', auth='none', methods=['POST'])
+ @webservice
+ def login(self, login, password, db=None):
+ if db and db != request.db:
+ raise Exception("Could not select database '%s'" % db)
+ uid = request.session.authenticate(request.db, login, password)
+ if not uid:
+ return Response(response="Wrong login/password", status=401)
+ self.check_user(uid)
+ return "ok"
+
+ @route('/base_import_module/upload', type='http', auth='user', methods=['POST'])
+ @webservice
+ def upload(self, mod_file=None, **kw):
+ self.check_user()
+ imm = request.registry['ir.module.module']
+
+ if not mod_file:
+ raise Exception("No file sent.")
+ if not zipfile.is_zipfile(mod_file):
+ raise Exception("Not a zipfile.")
+
+ success = []
+ errors = dict()
+ with zipfile.ZipFile(mod_file, "r") as z:
+ for zf in z.filelist:
+ if zf.file_size > MAX_FILE_SIZE:
+ raise Exception("File '%s' exceed maximum allowed file size" % zf.filename)
+
+ with openerp.tools.osutil.tempdir() as module_dir:
+ z.extractall(module_dir)
+ dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))]
+ for mod_name in dirs:
+ try:
+ # assert mod_name.startswith('theme_')
+ path = opj(module_dir, mod_name)
+ imm.import_module(request.cr, request.uid, mod_name, path, context=request.context)
+ success.append(mod_name)
+ except Exception, e:
+ errors[mod_name] = str(e)
+ r = ["Successfully imported module '%s'" % mod for mod in success]
+ for mod, error in errors.items():
+ r.append("Error while importing module '%s': %r" % (mod, error))
+ return '\n'.join(r)
diff --git a/addons/base_import_module/models/__init__.py b/addons/base_import_module/models/__init__.py
new file mode 100644
index 00000000000..a28c82fe5ba
--- /dev/null
+++ b/addons/base_import_module/models/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+import ir_module
diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py
new file mode 100644
index 00000000000..18e60f858da
--- /dev/null
+++ b/addons/base_import_module/models/ir_module.py
@@ -0,0 +1,71 @@
+import logging
+import os
+import sys
+from os.path import join as opj
+
+import openerp
+from openerp.osv import osv
+from openerp.tools import convert_file
+
+_logger = logging.getLogger(__name__)
+
+class view(osv.osv):
+ _inherit = "ir.module.module"
+
+ def import_module(self, cr, uid, module, path, context=None):
+ known_mods = self.browse(cr, uid, self.search(cr, uid, []))
+ known_mods_names = dict([(m.name, m) for m in known_mods])
+
+ mod = known_mods_names.get(module)
+ terp = openerp.modules.load_information_from_description_file(module, mod_path=path)
+ values = self.get_values_from_terp(terp)
+
+ unmet_dependencies = set(terp['depends']).difference(known_mods_names.keys())
+ if unmet_dependencies:
+ raise Exception("Unmet module dependencies: %s" % ', '.join(unmet_dependencies))
+
+ if mod:
+ self.write(cr, uid, mod.id, values)
+ mode = 'update'
+ else:
+ assert terp.get('installable', True), "Module not installable"
+ self.create(cr, uid, dict(name=module, state='uninstalled', **values))
+ mode = 'init'
+
+ for kind in ['data', 'init_xml', 'update_xml']:
+ for filename in terp[kind]:
+ _logger.info("module %s: loading %s", module, filename)
+ noupdate = False
+ if filename.endswith('.csv') and kind in ('init', 'init_xml'):
+ noupdate = True
+ pathname = opj(path, filename)
+ idref = {}
+ convert_file(cr, module, filename, idref, mode=mode, noupdate=noupdate, kind=kind, pathname=pathname)
+
+ path_static = opj(path, 'static')
+ ir_attach = self.pool['ir.attachment']
+ if os.path.isdir(path_static):
+ for root, _, files in os.walk(path_static):
+ for static_file in files:
+ full_path = opj(root, static_file)
+ with open(full_path, 'r') as fp:
+ data = fp.read().encode('base64')
+ url_path = '/%s%s' % (module, full_path.split(path)[1].replace(os.path.sep, '/'))
+ url_path = url_path.decode(sys.getfilesystemencoding())
+ filename = os.path.split(url_path)[1]
+ values = dict(
+ name=filename,
+ datas_fname=filename,
+ url=url_path,
+ res_model='ir.ui.view',
+ type='binary',
+ datas=data,
+ )
+ att_id = ir_attach.search(cr, uid, [('url', '=', url_path), ('type', '=', 'binary'), ('res_model', '=', 'ir.ui.view')], context=context)
+ if att_id:
+ ir_attach.write(cr, uid, att_id, values, context=context)
+ else:
+ ir_attach.create(cr, uid, values, context=context)
+
+ return True
+
diff --git a/addons/base_import_module/tests/test_module/__openerp__.py b/addons/base_import_module/tests/test_module/__openerp__.py
new file mode 100644
index 00000000000..b0ecb362b3f
--- /dev/null
+++ b/addons/base_import_module/tests/test_module/__openerp__.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# 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/>.
+#
+##############################################################################
+
+{
+ 'name': 'Test Module',
+ 'category': 'Website',
+ 'summary': 'Custom',
+ 'version': '1.0',
+ 'description': """
+ Test
+ """,
+ 'author': 'OpenERP SA',
+ 'depends': ['website'],
+ 'data': [
+ 'test.xml',
+ ],
+ 'installable': True,
+ 'application': True,
+}
diff --git a/addons/base_import_module/tests/test_module/static/src/img/c64.png b/addons/base_import_module/tests/test_module/static/src/img/c64.png
new file mode 100644
index 00000000000..3e8183f934f
--- /dev/null
+++ b/addons/base_import_module/tests/test_module/static/src/img/c64.png
Binary files differ
diff --git a/addons/base_import_module/tests/test_module/static/src/js/test.js b/addons/base_import_module/tests/test_module/static/src/js/test.js
new file mode 100644
index 00000000000..de803c83c34
--- /dev/null
+++ b/addons/base_import_module/tests/test_module/static/src/js/test.js
@@ -0,0 +1 @@
+console.log('test_module javascript');
diff --git a/addons/base_import_module/tests/test_module/test.xml b/addons/base_import_module/tests/test_module/test.xml
new file mode 100644
index 00000000000..489b286d975
--- /dev/null
+++ b/addons/base_import_module/tests/test_module/test.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+<data>
+ <!-- TODO: make test suite -->
+ <record id="base.main_company" model="res.company">
+ <field name="name">The base company is noupdate=1</field>
+ </record>
+
+ <record id="main_company2" model="res.company">
+ <field name="name">Hagrid</field>
+ <field name="rml_header1">Your Company Tagline</field>
+ <field name="currency_id" ref="base.EUR"/>
+ </record>
+
+ <template id="test_page" name="Test Page" page="True">
+ <t t-call="website.layout">
+ <h1>
+ This page comes from an imported module!
+ </h1>
+ <p>
+ And this static image too !
+ <img src="/test_module/static/src/img/c64.png"/>
+ </p>
+ </t>
+ </template>
+
+ <template id="website.homepage">
+ <t t-call="website.layout">
+ <div id="wrap" class="oe_structure oe_empty">
+ This homepage has been overwritten by an imported module !
+ <p>
+ <a href="/page/test_module.test_page">Link to page added by imported module</a>
+ </p>
+ </div>
+ </t>
+ </template>
+
+ <template id="contactus_test" name="Contact Form" inherit_id="website.contactus">
+ <xpath expr="//h1" position="replace">
+ <h1>This contact us title has been changed by an imported module</h1>
+ </xpath>
+ </template>
+
+</data>
+</openerp>