mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-08-17 16:54:42 -05:00
[PATCH] Upstream patch - 25062023
This commit is contained in:
@@ -10,25 +10,16 @@ import zipfile
|
||||
from collections import defaultdict
|
||||
from os.path import join as opj
|
||||
|
||||
import flectra
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.exceptions import UserError
|
||||
from flectra.modules.module import MANIFEST_NAMES
|
||||
from flectra.tools import convert_csv_import, convert_sql_import, convert_xml_import, exception_to_unicode
|
||||
from flectra.tools import file_open, file_open_temporary_directory
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
MAX_FILE_SIZE = 100 * 1024 * 1024 # in megabytes
|
||||
|
||||
__import_paths__ = {}
|
||||
|
||||
def _file_open(env, path):
|
||||
path = os.path.normcase(os.path.normpath(path))
|
||||
import_path = __import_paths__.get(env)
|
||||
if import_path and path.startswith(import_path):
|
||||
return open(path, 'rb')
|
||||
return flectra.tools.file_open(path, 'rb')
|
||||
|
||||
|
||||
class IrModule(models.Model):
|
||||
_inherit = "ir.module.module"
|
||||
@@ -54,7 +45,7 @@ class IrModule(models.Model):
|
||||
terp = {}
|
||||
manifest_path = next((opj(path, name) for name in MANIFEST_NAMES if os.path.exists(opj(path, name))), None)
|
||||
if manifest_path:
|
||||
with _file_open(self.env, manifest_path) as f:
|
||||
with file_open(manifest_path, 'rb', env=self.env) as f:
|
||||
terp.update(ast.literal_eval(f.read().decode()))
|
||||
if not terp:
|
||||
return False
|
||||
@@ -101,7 +92,7 @@ class IrModule(models.Model):
|
||||
noupdate = True
|
||||
pathname = opj(path, filename)
|
||||
idref = {}
|
||||
with _file_open(self.env, pathname) as fp:
|
||||
with file_open(pathname, 'rb', env=self.env) as fp:
|
||||
if ext == '.csv':
|
||||
convert_csv_import(self.env.cr, module, pathname, fp.read(), idref, mode, noupdate)
|
||||
elif ext == '.sql':
|
||||
@@ -115,7 +106,7 @@ class IrModule(models.Model):
|
||||
for root, dirs, files in os.walk(path_static):
|
||||
for static_file in files:
|
||||
full_path = opj(root, static_file)
|
||||
with _file_open(self.env, full_path) as fp:
|
||||
with file_open(full_path, 'rb', env=self.env) as fp:
|
||||
data = base64.b64encode(fp.read())
|
||||
url_path = '/{}{}'.format(module, full_path.split(path)[1].replace(os.path.sep, '/'))
|
||||
if not isinstance(url_path, str):
|
||||
@@ -151,49 +142,45 @@ class IrModule(models.Model):
|
||||
if zf.file_size > MAX_FILE_SIZE:
|
||||
raise UserError(_("File '%s' exceed maximum allowed file size", zf.filename))
|
||||
|
||||
with tempfile.TemporaryDirectory() as module_dir:
|
||||
try:
|
||||
__import_paths__[self.env] = module_dir
|
||||
manifest_files = [
|
||||
file
|
||||
for file in z.filelist
|
||||
if file.filename.count('/') == 1
|
||||
and file.filename.split('/')[1] in MANIFEST_NAMES
|
||||
]
|
||||
module_data_files = defaultdict(list)
|
||||
for manifest in manifest_files:
|
||||
manifest_path = z.extract(manifest, module_dir)
|
||||
mod_name = manifest.filename.split('/')[0]
|
||||
try:
|
||||
with _file_open(self.env, manifest_path) as f:
|
||||
terp = ast.literal_eval(f.read().decode())
|
||||
except Exception:
|
||||
with file_open_temporary_directory(self.env) as module_dir:
|
||||
manifest_files = [
|
||||
file
|
||||
for file in z.filelist
|
||||
if file.filename.count('/') == 1
|
||||
and file.filename.split('/')[1] in MANIFEST_NAMES
|
||||
]
|
||||
module_data_files = defaultdict(list)
|
||||
for manifest in manifest_files:
|
||||
manifest_path = z.extract(manifest, module_dir)
|
||||
mod_name = manifest.filename.split('/')[0]
|
||||
try:
|
||||
with file_open(manifest_path, 'rb', env=self.env) as f:
|
||||
terp = ast.literal_eval(f.read().decode())
|
||||
except Exception:
|
||||
continue
|
||||
for filename in terp.get('data', []) + terp.get('init_xml', []) + terp.get('update_xml', []):
|
||||
if os.path.splitext(filename)[1].lower() not in ('.xml', '.csv', '.sql'):
|
||||
continue
|
||||
for filename in terp.get('data', []) + terp.get('init_xml', []) + terp.get('update_xml', []):
|
||||
if os.path.splitext(filename)[1].lower() not in ('.xml', '.csv', '.sql'):
|
||||
continue
|
||||
module_data_files[mod_name].append('%s/%s' % (mod_name, filename))
|
||||
for file in z.filelist:
|
||||
filename = file.filename
|
||||
mod_name = filename.split('/')[0]
|
||||
is_data_file = filename in module_data_files[mod_name]
|
||||
is_static = filename.startswith('%s/static' % mod_name)
|
||||
if is_data_file or is_static:
|
||||
z.extract(file, module_dir)
|
||||
module_data_files[mod_name].append('%s/%s' % (mod_name, filename))
|
||||
for file in z.filelist:
|
||||
filename = file.filename
|
||||
mod_name = filename.split('/')[0]
|
||||
is_data_file = filename in module_data_files[mod_name]
|
||||
is_static = filename.startswith('%s/static' % mod_name)
|
||||
if is_data_file or is_static:
|
||||
z.extract(file, module_dir)
|
||||
|
||||
dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))]
|
||||
for mod_name in dirs:
|
||||
module_names.append(mod_name)
|
||||
try:
|
||||
# assert mod_name.startswith('theme_')
|
||||
path = opj(module_dir, mod_name)
|
||||
if self._import_module(mod_name, path, force=force):
|
||||
success.append(mod_name)
|
||||
except Exception as e:
|
||||
_logger.exception('Error while importing module')
|
||||
errors[mod_name] = exception_to_unicode(e)
|
||||
finally:
|
||||
__import_paths__.pop(self.env)
|
||||
dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))]
|
||||
for mod_name in dirs:
|
||||
module_names.append(mod_name)
|
||||
try:
|
||||
# assert mod_name.startswith('theme_')
|
||||
path = opj(module_dir, mod_name)
|
||||
if self._import_module(mod_name, path, force=force):
|
||||
success.append(mod_name)
|
||||
except Exception as e:
|
||||
_logger.exception('Error while importing module')
|
||||
errors[mod_name] = exception_to_unicode(e)
|
||||
r = ["Successfully imported module '%s'" % mod for mod in success]
|
||||
for mod, error in errors.items():
|
||||
r.append("Error while importing module '%s'.\n\n %s \n Make sure those modules are installed and try again." % (mod, error))
|
||||
|
||||
@@ -206,3 +206,23 @@ class TestImportModuleHttp(TestImportModule, HttpCase):
|
||||
self.assertEqual(self.url_open('/' + foo_icon_path).content, foo_icon_data)
|
||||
# Assert icon of module bar, which must be the icon of the base module as none was provided
|
||||
self.assertEqual(self.env.ref('base.module_bar').icon_image, self.env.ref('base.module_base').icon_image)
|
||||
|
||||
def test_import_module_field_file(self):
|
||||
files = [
|
||||
('foo/__manifest__.py', b"{'data': ['data.xml']}"),
|
||||
('foo/data.xml', b"""
|
||||
<data>
|
||||
<record id="logo" model="ir.attachment">
|
||||
<field name="name">Company Logo</field>
|
||||
<field name="datas" type="base64" file="foo/static/src/img/content/logo.png"/>
|
||||
<field name="res_model">ir.ui.view</field>
|
||||
<field name="public" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
"""),
|
||||
('foo/static/src/img/content/logo.png', b"foo_logo"),
|
||||
]
|
||||
self.import_zipfile(files)
|
||||
logo_path, logo_data = files[2]
|
||||
self.assertEqual(base64.b64decode(self.env.ref('foo.logo').datas), logo_data)
|
||||
self.assertEqual(self.url_open('/' + logo_path).content, logo_data)
|
||||
|
||||
@@ -1286,6 +1286,10 @@ class MailThread(models.AbstractModel):
|
||||
continue # skip container
|
||||
|
||||
filename = part.get_filename() # I may not properly handle all charsets
|
||||
if part.get_content_type() == 'text/xml' and not part.get_param('charset'):
|
||||
# for text/xml with omitted charset, the charset is assumed to be ASCII by the `email` module
|
||||
# although the payload might be in UTF8
|
||||
part.set_charset('utf-8')
|
||||
encoding = part.get_content_charset() # None if attachment
|
||||
|
||||
content = part.get_content()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<record id="equipment_request_rule_user" model="ir.rule">
|
||||
<field name="name">Users are allowed to access their own maintenance requests</field>
|
||||
<field name="model_id" ref="model_maintenance_request"/>
|
||||
<field name="domain_force">['|', ('message_partner_ids', 'in', [user.partner_id.id]), ('user_id.id', '=', user.id)]</field>
|
||||
<field name="domain_force">['|', '|', ('owner_user_id', '=', user.id), ('message_partner_ids', 'in', [user.partner_id.id]), ('user_id.id', '=', user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -326,6 +326,50 @@ Q2hhdXNz77+977+9ZSBkZSBCcnV4ZWxsZXM8L2NiYzpTdHJlZXROYW1lPg0KPC9JbnZvaWNlPg0K
|
||||
--00000000000005d9da05fa394cc0--
|
||||
"""
|
||||
|
||||
MAIL_MULTIPART_OMITTED_CHARSET = """Return-Path: <whatever-2a840@postmaster.twitter.com>
|
||||
To: {to}
|
||||
cc: {cc}
|
||||
Received: by mail1.openerp.com (Postfix, from userid 10002)
|
||||
id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
|
||||
From: {email_from}
|
||||
Subject: {subject}
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/alternative;
|
||||
boundary="00000000000005d9da05fa394cc0"
|
||||
Date: Fri, 10 Aug 2012 14:16:26 +0000
|
||||
Message-ID: {msg_id}
|
||||
{extra}
|
||||
|
||||
--00000000000005d9da05fa394cc0
|
||||
Content-Type: multipart/alternative; boundary="00000000000005d9d905fa394cbe"
|
||||
|
||||
--00000000000005d9d905fa394cbe
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
|
||||
Dear customer,
|
||||
|
||||
Please find attached the UBL attachment of your invoice
|
||||
|
||||
Cheers,
|
||||
|
||||
--00000000000005d9d905fa394cbe
|
||||
Content-Type: text/html; charset="UTF-8"
|
||||
|
||||
<div dir="ltr">Dear customer,<div><br></div><div>Please find attached the UBL attachment of your invoice</div><div><br></div><div>Cheers,</div></div>
|
||||
|
||||
--00000000000005d9d905fa394cbe--
|
||||
|
||||
--00000000000005d9da05fa394cc0
|
||||
Content-Disposition: attachment; filename="bis3.xml"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Type: text/xml; name="bis3.xml"
|
||||
Content-ID: <f_lgxgdqx40>
|
||||
X-Attachment-Id: f_lgxgdqx40
|
||||
|
||||
PEludm9pY2U+Q2hhdXNzw6llIGRlIEJydXhlbGxlczwvSW52b2ljZT4=
|
||||
--00000000000005d9da05fa394cc0--
|
||||
"""
|
||||
|
||||
|
||||
MAIL_SINGLE_BINARY = """X-Original-To: raoul@grosbedon.fr
|
||||
Delivered-To: raoul@grosbedon.fr
|
||||
|
||||
@@ -1507,6 +1507,13 @@ class TestMailgateway(TestMailCommon):
|
||||
# This explains the multiple "�" in the attachment.
|
||||
self.assertIn("Chauss������e de Bruxelles", record.message_main_attachment_id.raw.decode())
|
||||
|
||||
def test_message_process_file_omitted_charset(self):
|
||||
""" For incoming email containing an xml attachment with omitted charset and containing an UTF8 payload we
|
||||
should parse the attachment using UTF-8.
|
||||
"""
|
||||
record = self.format_and_process(test_mail_data.MAIL_MULTIPART_OMITTED_CHARSET, self.email_from, 'groups@test.com')
|
||||
self.assertEqual(record.message_main_attachment_id.name, 'bis3.xml')
|
||||
self.assertEqual("<Invoice>Chaussée de Bruxelles</Invoice>", record.message_main_attachment_id.raw.decode())
|
||||
|
||||
class TestMailThreadCC(TestMailCommon):
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ var BarChart = publicWidget.Widget.extend({
|
||||
*/
|
||||
init: function (parent, beginDate, endDate, dates) {
|
||||
this._super.apply(this, arguments);
|
||||
this.beginDate = beginDate;
|
||||
this.beginDate = beginDate.locale("en");
|
||||
this.endDate = endDate;
|
||||
this.number_of_days = this.endDate.diff(this.beginDate, 'days') + 2;
|
||||
this.dates = dates;
|
||||
@@ -162,11 +162,18 @@ publicWidget.registry.websiteLinksCharts = publicWidget.Widget.extend({
|
||||
var formattedClicksByDay = {};
|
||||
var beginDate;
|
||||
for (var i = 0; i < _clicksByDay.length; i++) {
|
||||
var date = moment(_clicksByDay[i]['create_date:day'], 'DD MMMM YYYY');
|
||||
// This is a trick to get the date without the local formatting.
|
||||
// We can't simply do .locale("en") because some Flectra languages
|
||||
// are not supported by moment.js (eg: Arabic Syria).
|
||||
const date = moment(
|
||||
_clicksByDay[i]["__domain"].find((el) => el.length && el.includes(">="))[2]
|
||||
.split(" ")[0], "YYYY MM DD"
|
||||
);
|
||||
if (i === 0) {
|
||||
beginDate = date;
|
||||
}
|
||||
formattedClicksByDay[date.format('YYYY-MM-DD')] = _clicksByDay[i]['create_date_count'];
|
||||
formattedClicksByDay[date.locale("en").format("YYYY-MM-DD")] =
|
||||
_clicksByDay[i]["create_date_count"];
|
||||
}
|
||||
|
||||
// Process all time line chart data
|
||||
@@ -241,11 +248,14 @@ publicWidget.registry.websiteLinksCharts = publicWidget.Widget.extend({
|
||||
* @private
|
||||
*/
|
||||
_lastWeekClicksByCountry: function () {
|
||||
var interval = moment().subtract(7, 'days').format('YYYY-MM-DD');
|
||||
// 7 days * 24 hours * 60 minutes * 60 seconds * 1000 milliseconds.
|
||||
const aWeekAgoDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
||||
// get the date in the format YYYY-MM-DD.
|
||||
const aWeekAgoString = aWeekAgoDate.toISOString().split("T")[0];
|
||||
return this._rpc({
|
||||
model: 'link.tracker.click',
|
||||
method: 'read_group',
|
||||
args: [[this.links_domain, ['create_date', '>', interval]], ['country_id']],
|
||||
args: [[this.links_domain, ["create_date", ">", aWeekAgoString]], ["country_id"]],
|
||||
kwargs: {groupby: 'country_id'},
|
||||
});
|
||||
},
|
||||
@@ -253,11 +263,14 @@ publicWidget.registry.websiteLinksCharts = publicWidget.Widget.extend({
|
||||
* @private
|
||||
*/
|
||||
_lastMonthClicksByCountry: function () {
|
||||
var interval = moment().subtract(30, 'days').format('YYYY-MM-DD');
|
||||
// 30 days * 24 hours * 60 minutes * 60 seconds * 1000 milliseconds.
|
||||
const aMonthAgoDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
||||
// get the date in the format YYYY-MM-DD.
|
||||
const aMonthAgoString = aMonthAgoDate.toISOString().split("T")[0];
|
||||
return this._rpc({
|
||||
model: 'link.tracker.click',
|
||||
method: 'read_group',
|
||||
args: [[this.links_domain, ['create_date', '>', interval]], ['country_id']],
|
||||
args: [[this.links_domain, ["create_date", ">", aMonthAgoString]], ["country_id"]],
|
||||
kwargs: {groupby: 'country_id'},
|
||||
});
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user