You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
5.2 KiB

  1. # -*- coding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # OpenERP, Open Source Management Solution
  5. # Copyright (C) 2015 Akretion (<http://www.akretion.com>).
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as
  9. # published by the Free Software Foundation, either version 3 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. ##############################################################################
  21. import StringIO
  22. import base64
  23. import datetime
  24. import re
  25. from openerp.osv.orm import Model
  26. from openerp.osv import fields, orm
  27. from openerp.tools.translate import _
  28. from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
  29. class SqlExport(Model):
  30. _name = "sql.export"
  31. _description = "SQL export"
  32. PROHIBITED_WORDS = [
  33. 'delete',
  34. 'drop',
  35. 'insert',
  36. 'alter',
  37. 'truncate',
  38. 'execute',
  39. 'create',
  40. 'update'
  41. ]
  42. def _check_query_allowed(self, cr, uid, ids, context=None):
  43. for obj in self.browse(cr, uid, ids, context=context):
  44. query = obj.query.lower()
  45. for word in self.PROHIBITED_WORDS:
  46. expr = r'\b%s\b' % word
  47. is_not_safe = re.search(expr, query)
  48. if is_not_safe:
  49. return False
  50. return True
  51. def _get_editor_group(self, cr, uid, *args):
  52. model_data_obj = self.pool['ir.model.data']
  53. return [model_data_obj.get_object_reference(
  54. cr, uid, 'sql_export', 'group_sql_request_editor')[1]]
  55. _columns = {
  56. 'name': fields.char('Name', required=True),
  57. 'query': fields.text(
  58. 'Query',
  59. required=True,
  60. help="You can't use the following word : delete, drop, create, "
  61. "insert, alter, truncate, execute, update"),
  62. 'copy_options': fields.char(
  63. 'Copy Options',
  64. required=True),
  65. 'group_ids': fields.many2many(
  66. 'res.groups',
  67. 'groups_sqlquery_rel',
  68. 'sql_id',
  69. 'group_id',
  70. 'Allowed Groups'),
  71. 'user_ids': fields.many2many(
  72. 'res.users',
  73. 'users_sqlquery_rel',
  74. 'sql_id',
  75. 'user_id',
  76. 'Allowed Users'),
  77. }
  78. _defaults = {
  79. 'group_ids': _get_editor_group,
  80. 'copy_options': "CSV HEADER DELIMITER ';'",
  81. }
  82. _constraints = [(_check_query_allowed,
  83. 'The query you want make is not allowed : prohibited '
  84. 'actions (%s)' % ', '.join(PROHIBITED_WORDS),
  85. ['query'])]
  86. def export_sql_query(self, cr, uid, ids, context=None):
  87. if not context:
  88. context = {}
  89. for obj in self.browse(cr, uid, ids, context=context):
  90. today = datetime.datetime.now()
  91. today_tz = fields.datetime.context_timestamp(
  92. cr, uid, today, context=context)
  93. date = today_tz.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
  94. output = StringIO.StringIO()
  95. query = "COPY (" + obj.query + ") TO STDOUT WITH " + \
  96. obj.copy_options
  97. cr.copy_expert(query, output)
  98. output.getvalue()
  99. new_output = base64.b64encode(output.getvalue())
  100. output.close()
  101. wiz = self.pool.get('sql.file.wizard').create(
  102. cr, uid,
  103. {
  104. 'file': new_output,
  105. 'file_name': obj.name + '_' + date + '.csv'})
  106. return {
  107. 'view_type': 'form',
  108. 'view_mode': 'form',
  109. 'res_model': 'sql.file.wizard',
  110. 'res_id': wiz,
  111. 'type': 'ir.actions.act_window',
  112. 'target': 'new',
  113. 'context': context,
  114. 'nodestroy': True,
  115. }
  116. def check_query_syntax(self, cr, uid, vals, context=None):
  117. if vals.get('query', False):
  118. vals['query'] = vals['query'].strip()
  119. if vals['query'][-1] == ';':
  120. vals['query'] = vals['query'][:-1]
  121. try:
  122. cr.execute(vals['query'])
  123. except:
  124. cr.rollback()
  125. raise orm.except_orm(_("Invalid Query"),
  126. _("The Sql query is not valid."))
  127. return vals
  128. def write(self, cr, uid, ids, vals, context=None):
  129. vals = self.check_query_syntax(cr, uid, vals, context=context)
  130. return super(SqlExport, self).write(
  131. cr, uid, ids, vals, context=context)
  132. def create(self, cr, uid, vals, context=None):
  133. vals = self.check_query_syntax(cr, uid, vals, context=context)
  134. return super(SqlExport, self).create(cr, uid, vals, context=context)