Browse Source

ADD sql_export module

pull/175/head
Florian da Costa 9 years ago
parent
commit
d66e562014
  1. 41
      sql_export/README.rst
  2. 2
      sql_export/__init__.py
  3. 43
      sql_export/__openerp__.py
  4. 127
      sql_export/i18n/fr.po
  5. 127
      sql_export/i18n/sql_export.pot
  6. 3
      sql_export/security/ir.model.access.csv
  7. 21
      sql_export/security/sql_export_security.xml
  8. 147
      sql_export/sql_export.py
  9. 56
      sql_export/sql_export_view.xml
  10. BIN
      sql_export/static/description/icon.png
  11. 5
      sql_export/tests/__init__.py
  12. 65
      sql_export/tests/test_sql_query.py
  13. 1
      sql_export/wizard/__init__.py
  14. 31
      sql_export/wizard/wizard_file.py
  15. 17
      sql_export/wizard/wizard_file_view.xml

41
sql_export/README.rst

@ -0,0 +1,41 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
SQL Export
==========
Allow to export data in csv files FROM sql requests.
There are some restrictions in the sql sql request, you can only read datas.
No update, deletion or creation are possible.
A new menu named Export is created.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/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
`here <https://github.com/OCA/server-tools/issues/new?body=module:%20sql_export%0Aversion:%207.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Florian da Costa <florian.dacosta@akretion.com>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://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 http://odoo-community.org.

2
sql_export/__init__.py

@ -0,0 +1,2 @@
from . import sql_export
from . import wizard

43
sql_export/__openerp__.py

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2015 Akretion (<http://www.akretion.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': 'SQL Export',
'version': '0.1',
'author': 'Akretion,Odoo Community Association (OCA)',
'website': 'http://www.akretion.com',
'description': """
Allow to export data in csv files FROM sql requests.
There are some restrictions in the sql sql request, you can only read datas.
No update, deletion or creation are possible.
""",
'license': 'AGPL-3',
'category': 'Generic Modules/Others',
'summary': 'Export data in csv file with SQL requests',
'depends': ['base',
],
'data': [
'sql_export_view.xml',
'wizard/wizard_file_view.xml',
'security/sql_export_security.xml',
'security/ir.model.access.csv',
],
'installable': True,
}

127
sql_export/i18n/fr.po

@ -0,0 +1,127 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * sql_export
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-08 17:32+0000\n"
"PO-Revision-Date: 2015-06-08 17:32+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: sql_export
#: code:_description:0
#: model:ir.model,name:sql_export.model_sql_file_wizard
#, python-format
msgid "Allow the user to save the file with sql request's data"
msgstr "Permet à l'utilisateur de sauvegarder le fichier contenant les données de la requête SQL"
#. module: sql_export
#: field:sql.export,group_ids:0
msgid "Allowed Groups"
msgstr "Groupes Autorisés"
#. module: sql_export
#: view:sql.export:0
#: field:sql.export,user_ids:0
msgid "Allowed Users"
msgstr "Utilisateurs Autorisés"
#. module: sql_export
#: view:sql.export:0
msgid "Allowed Users Groups"
msgstr "Groupes d'utilisateurs Autorisés"
#. module: sql_export
#: field:sql.export,copy_options:0
msgid "Copy Options"
msgstr "Copy Options"
#. module: sql_export
#: view:sql.file.wizard:0
msgid "Csv File"
msgstr "Fichier CSV"
#. module: sql_export
#: view:sql.export:0
msgid "Execute Query"
msgstr "Exécuter"
#. module: sql_export
#: model:ir.ui.menu,name:sql_export.menu_export
msgid "Export"
msgstr "Export"
#. module: sql_export
#: field:sql.file.wizard,file:0
msgid "File"
msgstr "Fichier"
#. module: sql_export
#: field:sql.file.wizard,file_name:0
msgid "File Name"
msgstr "Nom du fichier"
#. module: sql_export
#: code:addons/sql_export/sql_export.py:139
#, python-format
msgid "Invalid Query"
msgstr "Invalid Query"
#. module: sql_export
#: field:sql.export,name:0
msgid "Name"
msgstr "Nom"
#. module: sql_export
#: field:sql.export,query:0
msgid "Query"
msgstr "Query"
#. module: sql_export
#: model:ir.actions.act_window,name:sql_export.sql_export_tree_action
#: view:sql.export:0
msgid "SQL Export"
msgstr "SQL Export"
#. module: sql_export
#: code:_description:0
#: model:ir.model,name:sql_export.model_sql_export
#: view:sql.export:0
#, python-format
msgid "SQL export"
msgstr "SQL export"
#. module: sql_export
#: model:ir.ui.menu,name:sql_export.sql_export_menu
#: model:ir.ui.menu,name:sql_export.sql_export_menu_view
msgid "Sql Export"
msgstr "Sql Export"
#. module: sql_export
#: model:res.groups,name:sql_export.group_sql_request_editor
msgid "Sql Request Editor"
msgstr "Edition de Requête SQL"
#. module: sql_export
#: code:addons/sql_export/sql_export.py:140
#, python-format
msgid "The Sql query is not valid."
msgstr "The Sql query is not valid."
#. module: sql_export
#: constraint:sql.export:0
msgid "The query you want make is not allowed : prohibited actions (Delete, drop...)"
msgstr "La requête que vous voulez sauvegarder n'est pas autorisée : actions interdites (Delete, drop...)"
#. module: sql_export
#: help:sql.export,query:0
msgid "You can't use the following word : delete, drop, create, insert, alter, truncate, execute, update"
msgstr "You can't use the following word : delete, drop, create, insert, alter, truncate, execute, update"

127
sql_export/i18n/sql_export.pot

@ -0,0 +1,127 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * sql_export
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-08 17:32+0000\n"
"PO-Revision-Date: 2015-06-08 17:32+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: sql_export
#: code:_description:0
#: model:ir.model,name:sql_export.model_sql_file_wizard
#, python-format
msgid "Allow the user to save the file with sql request's data"
msgstr ""
#. module: sql_export
#: field:sql.export,group_ids:0
msgid "Allowed Groups"
msgstr ""
#. module: sql_export
#: view:sql.export:0
#: field:sql.export,user_ids:0
msgid "Allowed Users"
msgstr ""
#. module: sql_export
#: view:sql.export:0
msgid "Allowed Users Groups"
msgstr ""
#. module: sql_export
#: field:sql.export,copy_options:0
msgid "Copy Options"
msgstr ""
#. module: sql_export
#: view:sql.file.wizard:0
msgid "Csv File"
msgstr ""
#. module: sql_export
#: view:sql.export:0
msgid "Execute Query"
msgstr ""
#. module: sql_export
#: model:ir.ui.menu,name:sql_export.menu_export
msgid "Export"
msgstr ""
#. module: sql_export
#: field:sql.file.wizard,file:0
msgid "File"
msgstr ""
#. module: sql_export
#: field:sql.file.wizard,file_name:0
msgid "File Name"
msgstr ""
#. module: sql_export
#: code:addons/sql_export/sql_export.py:139
#, python-format
msgid "Invalid Query"
msgstr ""
#. module: sql_export
#: field:sql.export,name:0
msgid "Name"
msgstr ""
#. module: sql_export
#: field:sql.export,query:0
msgid "Query"
msgstr ""
#. module: sql_export
#: model:ir.actions.act_window,name:sql_export.sql_export_tree_action
#: view:sql.export:0
msgid "SQL Export"
msgstr ""
#. module: sql_export
#: code:_description:0
#: model:ir.model,name:sql_export.model_sql_export
#: view:sql.export:0
#, python-format
msgid "SQL export"
msgstr ""
#. module: sql_export
#: model:ir.ui.menu,name:sql_export.sql_export_menu
#: model:ir.ui.menu,name:sql_export.sql_export_menu_view
msgid "Sql Export"
msgstr ""
#. module: sql_export
#: model:res.groups,name:sql_export.group_sql_request_editor
msgid "Sql Request Editor"
msgstr ""
#. module: sql_export
#: code:addons/sql_export/sql_export.py:140
#, python-format
msgid "The Sql query is not valid."
msgstr ""
#. module: sql_export
#: constraint:sql.export:0
msgid "The query you want make is not allowed : prohibited actions (Delete, drop...)"
msgstr ""
#. module: sql_export
#: help:sql.export,query:0
msgid "You can't use the following word : delete, drop, create, insert, alter, truncate, execute, update"
msgstr ""

3
sql_export/security/ir.model.access.csv

@ -0,0 +1,3 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_sql_export_all","access_sql_export_all","model_sql_export",,1,0,0,0
"access_sql_export_editor","access_sql_export_editor","model_sql_export",group_sql_request_editor,1,1,1,1

21
sql_export/security/sql_export_security.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record model="res.groups" id="group_sql_request_editor">
<field name="name">Sql Request Editor</field>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record model="ir.rule" id="sql_export_restric_access_user_or_group">
<field name="name" >SQL Export users and groups rules</field>
<field name="model_id" ref="model_sql_export"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
<field eval="0" name="perm_write"/>
<field eval="0" name="perm_unlink"/>
<field name="domain_force">['|', ('user_ids','=',user.id), ('group_ids','in', [x.id for x in user.groups_id])]</field>
</record>
</data>
</openerp>

147
sql_export/sql_export.py

@ -0,0 +1,147 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2015 Akretion (<http://www.akretion.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/>.
#
##############################################################################
import StringIO
import base64
import datetime
import re
from openerp.osv.orm import Model
from openerp.osv import fields, orm
from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
class SqlExport(Model):
_name = "sql.export"
_description = "SQL export"
PROHIBITED_WORDS = [
'delete',
'drop',
'insert',
'alter',
'truncate',
'execute',
'create',
'update'
]
def _check_query_allowed(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
query = obj.query.lower()
for word in self.PROHIBITED_WORDS:
expr = r'\b%s\b' % word
is_not_safe = re.search(expr, query)
if is_not_safe:
return False
return True
def _get_editor_group(self, cr, uid, *args):
model_data_obj = self.pool['ir.model.data']
return [model_data_obj.get_object_reference(
cr, uid, 'sql_export', 'group_sql_request_editor')[1]]
_columns = {
'name': fields.char('Name', required=True),
'query': fields.text(
'Query',
required=True,
help="You can't use the following word : delete, drop, create, "
"insert, alter, truncate, execute, update"),
'copy_options': fields.char(
'Copy Options',
required=True),
'group_ids': fields.many2many(
'res.groups',
'groups_sqlquery_rel',
'sql_id',
'group_id',
'Allowed Groups'),
'user_ids': fields.many2many(
'res.users',
'users_sqlquery_rel',
'sql_id',
'user_id',
'Allowed Users'),
}
_defaults = {
'group_ids': _get_editor_group,
'copy_options': "CSV HEADER DELIMITER ';'",
}
_constraints = [(_check_query_allowed,
'The query you want make is not allowed : prohibited '
'actions (%s)' % ', '.join(PROHIBITED_WORDS),
['query'])]
def export_sql_query(self, cr, uid, ids, context=None):
if not context:
context = {}
for obj in self.browse(cr, uid, ids, context=context):
today = datetime.datetime.now()
today_tz = fields.datetime.context_timestamp(
cr, uid, today, context=context)
date = today_tz.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
output = StringIO.StringIO()
query = "COPY (" + obj.query + ") TO STDOUT WITH " + \
obj.copy_options
cr.copy_expert(query, output)
output.getvalue()
new_output = base64.b64encode(output.getvalue())
output.close()
wiz = self.pool.get('sql.file.wizard').create(
cr, uid,
{
'file': new_output,
'file_name': obj.name + '_' + date + '.csv'})
return {
'view_type': 'form',
'view_mode': 'form',
'res_model': 'sql.file.wizard',
'res_id': wiz,
'type': 'ir.actions.act_window',
'target': 'new',
'context': context,
'nodestroy': True,
}
def check_query_syntax(self, cr, uid, vals, context=None):
if vals.get('query', False):
vals['query'] = vals['query'].strip()
if vals['query'][-1] == ';':
vals['query'] = vals['query'][:-1]
try:
cr.execute(vals['query'])
except:
cr.rollback()
raise orm.except_orm(_("Invalid Query"),
_("The Sql query is not valid."))
return vals
def write(self, cr, uid, ids, vals, context=None):
vals = self.check_query_syntax(cr, uid, vals, context=context)
return super(SqlExport, self).write(
cr, uid, ids, vals, context=context)
def create(self, cr, uid, vals, context=None):
vals = self.check_query_syntax(cr, uid, vals, context=context)
return super(SqlExport, self).create(cr, uid, vals, context=context)

56
sql_export/sql_export_view.xml

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="sql_export_view_form" model="ir.ui.view">
<field name="name">Sql_export_form_view</field>
<field name="model">sql.export</field>
<field name="arch" type="xml">
<form string="SQL export">
<group col="2">
<group colspan="2" col="5">
<label for="name" colspan="1"/>
<field name="name" colspan="2" nolabel="1"/>
<button name="export_sql_query" string="Execute Query" type="object" class="oe_highlight" icon="gtk-execute" colspan="2"/>
<label for="query" colspan="1"/>
<field name="query" nolabel="1" colspan="4"/>
<label for="Copy Options" colspan="1"/>
<field name="copy_options" nolabel="1" colspan="4"/>
</group>
<group colspan="2" col="2" groups="sql_export.group_sql_request_editor">
<separator string="Allowed Users" colspan="1"/>
<separator string="Allowed Users Groups" colspan="1"/>
<field name="user_ids" nolabel="1"/>
<field name="group_ids" nolabel="1"/>
</group>
</group>
</form>
</field>
</record>
<record id="sql_export_view_tree" model="ir.ui.view">
<field name="name">Sql_export_tree_view</field>
<field name="model">sql.export</field>
<field name="arch" type="xml">
<tree string="SQL Export">
<field name="name"/>
</tree>
</field>
</record>
<record id="sql_export_tree_action" model="ir.actions.act_window">
<field name="name">SQL Export</field>
<field name="res_model">sql.export</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="sql_export_menu" name="Sql Export" parent="base.menu_reporting" sequence="80"/>
<menuitem id="sql_export_menu_view" name="Sql Export" parent="sql_export_menu" action="sql_export_tree_action" sequence="1"/>
</data>
</openerp>

BIN
sql_export/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

5
sql_export/tests/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import test_sql_query
checks = [
test_sql_query
]

65
sql_export/tests/test_sql_query.py

@ -0,0 +1,65 @@
# Author: Florian da Costa
# Copyright 2015 Akretion
#
# 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 distnaributed 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 base64
from openerp.tests.common import TransactionCase
from openerp.osv.orm import except_orm
class TestExportSqlQuery(TransactionCase):
def setUp(self):
super(TestExportSqlQuery, self).setUp()
query_vals = {
'name': 'test',
'query': "SELECT name, street FROM res_partner;"
}
self.sql_model = self.registry('sql.export')
self.query_id = self.sql_model.create(
self.cr,
self.uid,
query_vals)
def test_sql_query(self):
test = self.sql_model.export_sql_query(
self.cr, self.uid, [self.query_id])
wizard = self.registry('sql.file.wizard').browse(
self.cr, self.uid, test['res_id'])
export = base64.b64decode(wizard.file)
self.assertEqual(export.split(';')[0], 'name')
self.assertTrue(len(export.split(';')) > 6)
def test_prohibited_queries_creation(self):
prohibited_queries = [
"upDaTe res_partner SET name = 'test' WHERE id = 1",
"DELETE FROM res_partner;",
" DELETE FROM res_partner ;",
"""DELETE
FROM
res_partner
""",
]
for query in prohibited_queries:
with self.assertRaises(except_orm):
self.sql_model.create(
self.cr, self.uid,
{'name': 'test_prohibited',
'query': query})
ok_query = {
'name': 'test ok',
'query': "SELECT create_date FROM res_partner"
}
query_id = self.sql_model.create(self.cr, self.uid, ok_query)
self.assertIsNotNone(query_id)

1
sql_export/wizard/__init__.py

@ -0,0 +1 @@
from . import wizard_file

31
sql_export/wizard/wizard_file.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2015 Akretion (<http://www.akretion.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/>.
#
##############################################################################
from openerp.osv import fields, orm
class SqlFileWizard(orm.TransientModel):
_name = "sql.file.wizard"
_description = "Allow the user to save the file with sql request's data"
_columns = {
'file': fields.binary('File', required=True, readonly=True),
'file_name': fields.char('File Name', readonly=True),
}

17
sql_export/wizard/wizard_file_view.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="sql_file_wizard_view_form" model="ir.ui.view">
<field name="name">sql.file.wizard.view.form</field>
<field name="model">sql.file.wizard</field>
<field name="arch" type="xml">
<form string="Csv File">
<field name="file" filename="file_name"/>
<field name="file_name" invisible="1"/>
</form>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save