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.

127 lines
4.7 KiB

  1. # #############################################################################
  2. #
  3. # OpenERP, Open Source Management Solution
  4. # This module copyright (C) 2010 - 2014 Savoir-faire Linux
  5. # (<http://www.savoirfairelinux.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 base64
  22. import os
  23. import zipfile
  24. from io import BytesIO, StringIO
  25. from collections import namedtuple
  26. from odoo import fields, models, api
  27. class PrototypeModuleExport(models.TransientModel):
  28. _name = "module_prototyper.module.export"
  29. def _default_api_version(self):
  30. return self.env.ref("module_prototyper.api_version_100").id
  31. name = fields.Char("File Name", readonly=True)
  32. api_version = fields.Many2one(
  33. comodel_name="module_prototyper.api_version",
  34. string="API version",
  35. required=True,
  36. default=_default_api_version,
  37. )
  38. data = fields.Binary("File", readonly=True)
  39. state = fields.Selection(
  40. [("choose", "choose"), ("get", "get")], # choose version # get module
  41. default="choose",
  42. )
  43. @api.model
  44. def action_export(self, ids):
  45. """
  46. Export a zip file containing the module based on the information
  47. provided in the prototype, using the templates chosen in the wizard.
  48. """
  49. if isinstance(ids, int):
  50. ids = [ids]
  51. wizard = self.browse(ids)
  52. active_model = self._context.get("active_model")
  53. # checking if the wizard was called by a prototype.
  54. msg = '%s has to be called from a "module_prototyper" , not a "%s"'
  55. assert active_model == "module_prototyper", msg % (self, active_model)
  56. # getting the prototype of the wizard
  57. prototypes = self.env[active_model].browse(
  58. [self._context.get("active_id")]
  59. )
  60. zip_details = self.zip_files(wizard, prototypes)
  61. if len(prototypes) == 1:
  62. zip_name = prototypes[0].name
  63. else:
  64. zip_name = "prototyper_export"
  65. wizard.write(
  66. {
  67. "name": "%s.zip" % (zip_name,),
  68. "state": "get",
  69. "data": base64.encodestring(zip_details.BytesIO.getvalue()),
  70. }
  71. )
  72. return {
  73. "type": "ir.actions.act_window",
  74. "res_model": "module_prototyper.module.export",
  75. "view_mode": "form",
  76. "view_type": "form",
  77. "res_id": wizard.id,
  78. "views": [(False, "form")],
  79. "target": "new",
  80. }
  81. @staticmethod
  82. def zip_files(wizard, prototypes):
  83. """Takes a set of file and zips them.
  84. :param file_details: tuple (filename, file_content)
  85. :return: tuple (zip_file, stringIO)
  86. """
  87. zip_details = namedtuple("Zip_details", ["zip_file", "BytesIO"])
  88. out = BytesIO()
  89. with zipfile.ZipFile(out, "w") as target:
  90. for prototype in prototypes:
  91. # setting the jinja environment.
  92. # They will help the program to find the template to render the
  93. # files with.
  94. prototype.setup_env(wizard.api_version)
  95. # generate_files ask the prototype to investigate the input and
  96. # to generate the file templates according to it. zip_files,
  97. # in another hand, put all the template files into a package
  98. # ready to be saved by the user.
  99. file_details = prototype.generate_files()
  100. for filename, file_content in file_details:
  101. if isinstance(file_content, str):
  102. file_content = file_content.encode("utf-8")
  103. # Prefix all names with module technical name
  104. filename = os.path.join(prototype.name, filename)
  105. info = zipfile.ZipInfo(filename)
  106. info.compress_type = zipfile.ZIP_DEFLATED
  107. info.external_attr = 2175008768 # specifies mode 0644
  108. target.writestr(info, file_content)
  109. return zip_details(zip_file=target, BytesIO=out)