Add sql export module (migration from v7)
Add rollback after executing query as a double security with blacklist terms add known issue in readmepull/671/head
parent
d153fff830
commit
5fabbb4330
|
@ -0,0 +1,56 @@
|
||||||
|
.. 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.
|
||||||
|
|
||||||
|
Known issues / Roadmap
|
||||||
|
======================
|
||||||
|
|
||||||
|
Some words are prohibeted and can't be used is the query in anyways, even in a select query :
|
||||||
|
|
||||||
|
* delete
|
||||||
|
* drop
|
||||||
|
* insert
|
||||||
|
* alter
|
||||||
|
* truncate
|
||||||
|
* execute
|
||||||
|
* create
|
||||||
|
* update
|
||||||
|
|
||||||
|
|
||||||
|
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:%208.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.
|
|
@ -0,0 +1,2 @@
|
||||||
|
from . import sql_export
|
||||||
|
from . import wizard
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- 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',
|
||||||
|
'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,
|
||||||
|
'images': [],
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * sql_export
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 8.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2016-02-05 13:10+0000\n"
|
||||||
|
"PO-Revision-Date: 2016-02-05 13:10+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
|
||||||
|
#: model:ir.model,name:sql_export.model_sql_file_wizard
|
||||||
|
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:sql_export.sql_export_view_form
|
||||||
|
#: field:sql.export,user_ids:0
|
||||||
|
msgid "Allowed Users"
|
||||||
|
msgstr "Utilisateurs Autorisés"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: view:sql.export:sql_export.sql_export_view_form
|
||||||
|
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
|
||||||
|
#: field:sql.export,create_uid:0
|
||||||
|
#: field:sql.file.wizard,create_uid:0
|
||||||
|
msgid "Created by"
|
||||||
|
msgstr "Créé par"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,create_date:0
|
||||||
|
#: field:sql.file.wizard,create_date:0
|
||||||
|
msgid "Created on"
|
||||||
|
msgstr "Créé le"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: view:sql.file.wizard:sql_export.sql_file_wizard_view_form
|
||||||
|
msgid "Csv File"
|
||||||
|
msgstr "Fichier CSV"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: view:sql.export:sql_export.sql_export_view_form
|
||||||
|
msgid "Execute Query"
|
||||||
|
msgstr "Exécuter"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.file.wizard,binary_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
|
||||||
|
#: field:sql.export,id:0
|
||||||
|
#: field:sql.file.wizard,id:0
|
||||||
|
msgid "ID"
|
||||||
|
msgstr "ID"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,write_uid:0
|
||||||
|
#: field:sql.file.wizard,write_uid:0
|
||||||
|
msgid "Last Updated by"
|
||||||
|
msgstr "Last Updated by"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,write_date:0
|
||||||
|
#: field:sql.file.wizard,write_date:0
|
||||||
|
msgid "Last Updated on"
|
||||||
|
msgstr "Last Updated on"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,name:0
|
||||||
|
msgid "Name"
|
||||||
|
msgstr "Nom"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,query:0
|
||||||
|
msgid "Query"
|
||||||
|
msgstr "Requête"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: model:ir.actions.act_window,name:sql_export.sql_export_tree_action
|
||||||
|
#: view:sql.export:sql_export.sql_export_view_tree
|
||||||
|
msgid "SQL Export"
|
||||||
|
msgstr "SQL Export"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: model:ir.model,name:sql_export.model_sql_export
|
||||||
|
#: view:sql.export:sql_export.sql_export_view_form
|
||||||
|
msgid "SQL export"
|
||||||
|
msgstr "Export SQL"
|
||||||
|
|
||||||
|
#. 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 "Export SQL"
|
||||||
|
|
||||||
|
#. 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:132
|
||||||
|
#, python-format
|
||||||
|
msgid "The Sql query is not valid."
|
||||||
|
msgstr "La requête SQL n'est pas valide"
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: constraint:sql.export:0
|
||||||
|
msgid "The query you want make is not allowed : prohibited actions (delete, drop, insert, alter, truncate, execute, create, update)"
|
||||||
|
msgstr "La requête que vous voulez faire n'est pas autorisée : actions interdites (delete, drop, insert, alter, truncate, execute, create, update)"
|
||||||
|
|
||||||
|
#. 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 "Vous ne pouvez pas utiliser les mots suivants : delete, drop, create, insert, alter, truncate, execute, update"
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * sql_export
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 8.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2016-02-05 13:10+0000\n"
|
||||||
|
"PO-Revision-Date: 2016-02-05 13:10+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
|
||||||
|
#: model:ir.model,name:sql_export.model_sql_file_wizard
|
||||||
|
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:sql_export.sql_export_view_form
|
||||||
|
#: field:sql.export,user_ids:0
|
||||||
|
msgid "Allowed Users"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: view:sql.export:sql_export.sql_export_view_form
|
||||||
|
msgid "Allowed Users Groups"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,copy_options:0
|
||||||
|
msgid "Copy Options"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,create_uid:0
|
||||||
|
#: field:sql.file.wizard,create_uid:0
|
||||||
|
msgid "Created by"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,create_date:0
|
||||||
|
#: field:sql.file.wizard,create_date:0
|
||||||
|
msgid "Created on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: view:sql.file.wizard:sql_export.sql_file_wizard_view_form
|
||||||
|
msgid "Csv File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: view:sql.export:sql_export.sql_export_view_form
|
||||||
|
msgid "Execute Query"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.file.wizard,binary_file:0
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.file.wizard,file_name:0
|
||||||
|
msgid "File Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,id:0
|
||||||
|
#: field:sql.file.wizard,id:0
|
||||||
|
msgid "ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,write_uid:0
|
||||||
|
#: field:sql.file.wizard,write_uid:0
|
||||||
|
msgid "Last Updated by"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: field:sql.export,write_date:0
|
||||||
|
#: field:sql.file.wizard,write_date:0
|
||||||
|
msgid "Last Updated on"
|
||||||
|
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:sql_export.sql_export_view_tree
|
||||||
|
msgid "SQL Export"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sql_export
|
||||||
|
#: model:ir.model,name:sql_export.model_sql_export
|
||||||
|
#: view:sql.export:sql_export.sql_export_view_form
|
||||||
|
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:132
|
||||||
|
#, 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, insert, alter, truncate, execute, create, update)"
|
||||||
|
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 ""
|
||||||
|
|
|
@ -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
|
|
|
@ -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>
|
|
@ -0,0 +1,149 @@
|
||||||
|
# -*- 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 import models, fields, api, _, exceptions
|
||||||
|
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class SqlExport(models.Model):
|
||||||
|
_name = "sql.export"
|
||||||
|
_description = "SQL export"
|
||||||
|
|
||||||
|
PROHIBITED_WORDS = [
|
||||||
|
'delete',
|
||||||
|
'drop',
|
||||||
|
'insert',
|
||||||
|
'alter',
|
||||||
|
'truncate',
|
||||||
|
'execute',
|
||||||
|
'create',
|
||||||
|
'update'
|
||||||
|
]
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _check_query_allowed(self):
|
||||||
|
for obj in self:
|
||||||
|
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
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_editor_group(self):
|
||||||
|
ir_model_obj = self.env['ir.model.data']
|
||||||
|
return [ir_model_obj.xmlid_to_res_id(
|
||||||
|
'sql_export.group_sql_request_editor')]
|
||||||
|
|
||||||
|
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,
|
||||||
|
default="CSV HEADER DELIMITER ';'")
|
||||||
|
group_ids = fields.Many2many(
|
||||||
|
'res.groups',
|
||||||
|
'groups_sqlquery_rel',
|
||||||
|
'sql_id',
|
||||||
|
'group_id',
|
||||||
|
'Allowed Groups',
|
||||||
|
default=_get_editor_group)
|
||||||
|
user_ids = fields.Many2many(
|
||||||
|
'res.users',
|
||||||
|
'users_sqlquery_rel',
|
||||||
|
'sql_id',
|
||||||
|
'user_id',
|
||||||
|
'Allowed Users')
|
||||||
|
|
||||||
|
_constraints = [(_check_query_allowed,
|
||||||
|
'The query you want make is not allowed : prohibited '
|
||||||
|
'actions (%s)' % ', '.join(PROHIBITED_WORDS),
|
||||||
|
['query'])]
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def export_sql_query(self):
|
||||||
|
for obj in self:
|
||||||
|
today = datetime.datetime.now()
|
||||||
|
today_tz = fields.Datetime.context_timestamp(
|
||||||
|
obj, today)
|
||||||
|
date = today_tz.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
output = StringIO.StringIO()
|
||||||
|
query = "COPY (" + obj.query + ") TO STDOUT WITH " + \
|
||||||
|
obj.copy_options
|
||||||
|
name = 'export_query_%s' % uuid.uuid1().hex
|
||||||
|
self.env.cr.execute("SAVEPOINT %s" % name)
|
||||||
|
try:
|
||||||
|
self.env.cr.copy_expert(query, output)
|
||||||
|
output.getvalue()
|
||||||
|
new_output = base64.b64encode(output.getvalue())
|
||||||
|
output.close()
|
||||||
|
finally:
|
||||||
|
self.env.cr.execute("ROLLBACK TO SAVEPOINT %s" % name)
|
||||||
|
wiz = self.env['sql.file.wizard'].create(
|
||||||
|
{
|
||||||
|
'binary_file': new_output,
|
||||||
|
'file_name': obj.name + '_' + date + '.csv'})
|
||||||
|
return {
|
||||||
|
'view_type': 'form',
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_model': 'sql.file.wizard',
|
||||||
|
'res_id': wiz.id,
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'target': 'new',
|
||||||
|
'context': self._context,
|
||||||
|
'nodestroy': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def check_query_syntax(self, vals):
|
||||||
|
if vals.get('query', False):
|
||||||
|
vals['query'] = vals['query'].strip()
|
||||||
|
if vals['query'][-1] == ';':
|
||||||
|
vals['query'] = vals['query'][:-1]
|
||||||
|
try:
|
||||||
|
self.env.cr.execute(vals['query'])
|
||||||
|
except:
|
||||||
|
raise exceptions.Warning(
|
||||||
|
_("The Sql query is not valid."))
|
||||||
|
finally:
|
||||||
|
self.env.cr.rollback()
|
||||||
|
return vals
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def write(self, vals):
|
||||||
|
vals = self.check_query_syntax(vals)
|
||||||
|
return super(SqlExport, self).write(vals)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def create(self, vals):
|
||||||
|
vals = self.check_query_syntax(vals)
|
||||||
|
return super(SqlExport, self).create(vals)
|
|
@ -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>
|
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import test_sql_query
|
|
@ -0,0 +1,71 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# 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 import exceptions
|
||||||
|
|
||||||
|
|
||||||
|
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.binary_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 sql_export WHERE name = 'test';",
|
||||||
|
" DELETE FROM sql_export WHERE name = 'test' ;",
|
||||||
|
"""DELETE
|
||||||
|
FROM
|
||||||
|
sql_export
|
||||||
|
WHERE name = 'test'
|
||||||
|
""",
|
||||||
|
]
|
||||||
|
for query in prohibited_queries:
|
||||||
|
with self.assertRaises(exceptions.ValidationError):
|
||||||
|
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)
|
|
@ -0,0 +1 @@
|
||||||
|
from . import wizard_file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# -*- 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 import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class SqlFileWizard(models.TransientModel):
|
||||||
|
_name = "sql.file.wizard"
|
||||||
|
_description = "Allow the user to save the file with sql request's data"
|
||||||
|
|
||||||
|
binary_file = fields.Binary('File', required=True, readonly=True)
|
||||||
|
file_name = fields.Char('File Name', readonly=True)
|
|
@ -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="binary_file" filename="file_name"/>
|
||||||
|
<field name="file_name" invisible="1"/>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
Loading…
Reference in New Issue