84 lines
3.2 KiB
Python
84 lines
3.2 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import io
|
|
import logging
|
|
import zipfile
|
|
|
|
from odoo.http import (
|
|
Controller,
|
|
content_disposition,
|
|
request,
|
|
route,
|
|
serialize_exception,
|
|
)
|
|
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
|
|
|
|
from .export_utils import StudioExportSerializer
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class StudioExporter(Controller):
|
|
@route('/web_studio/export', type='http', auth='user')
|
|
def export(self, token, active_id):
|
|
""" Exports a zip file containing the 'studio_customization' module
|
|
gathering all customizations done with Studio (customizations of
|
|
existing apps and freshly created apps) along with the
|
|
StudioExportModel's related data.
|
|
|
|
Returns:
|
|
Response: A zip file containing the exported data
|
|
|
|
Raises:
|
|
Forbidden: If the user is not an admin.
|
|
NotFound: If the export wizard is not found.
|
|
InternalServerError: If the export wizard is not found.
|
|
"""
|
|
if not self.env.is_admin():
|
|
raise Forbidden()
|
|
|
|
module = self.env['ir.module.module'].get_studio_module()
|
|
wizard_id = int(active_id)
|
|
wizard = self.env['studio.export.wizard'].browse(wizard_id).exists()
|
|
if not wizard:
|
|
raise NotFound()
|
|
|
|
try:
|
|
export_info = wizard.get_export_info()
|
|
content = self.generate_archive(module, export_info)
|
|
return request.make_response(content, headers=[
|
|
('Content-Disposition', content_disposition('customizations.zip')),
|
|
('Content-Type', 'application/zip'),
|
|
('Content-Length', len(content)),
|
|
])
|
|
except Exception as e:
|
|
_logger.warning("Error while generating studio export %s", module.name, exc_info=True)
|
|
se = serialize_exception(e)
|
|
error = {
|
|
'code': 0,
|
|
'message': "Odoo Server Error",
|
|
'data': se
|
|
}
|
|
res = request.make_json_response(error, status=500)
|
|
raise InternalServerError(response=res) from e
|
|
|
|
def generate_archive(self, module, export_info):
|
|
""" Returns a zip file containing the given module with the given data.
|
|
Returns:
|
|
bytes: A byte string containing the zip file.
|
|
"""
|
|
with io.BytesIO() as f:
|
|
with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as archive:
|
|
for filename, content in self.generate_module_files(module, export_info):
|
|
archive.writestr(module.name + '/' + filename, content)
|
|
return f.getvalue()
|
|
|
|
def generate_module_files(self, module, export_info):
|
|
""" Return an iterator of pairs (filename, content) to put in the exported
|
|
module. Returned filenames are local to the module directory.
|
|
Groups exported data by model in separated files.
|
|
The content of the files is yielded as an encoded bytestring (utf-8)
|
|
Yields:
|
|
tuple: A tuple containing the filename and content.
|
|
"""
|
|
yield from StudioExportSerializer(self.env, module, export_info).serialize()
|