def test_01_debug_mode_assets(self): """ Checks that the ir.attachments records created for compiled less assets in debug mode are correctly invalidated. """ # Compile for the first time self._bundle(True, False) # Compile a second time, without changes self._bundle(False, False) # Touch the file and compile a third time path = get_resource_path('test_assetsbundle', 'static', 'src', 'less', 'test_lessfile1.less') t = time.time() + 5 utime(path, (t, t)) # touch self._bundle(True, True) # Because we are in the same transaction since the beginning of the test, the first asset # created and the second one have the same write_date, but the file's last modified date # has really been modified. If we do not update the write_date to a posterior date, we are # not able to reproduce the case where we compile this bundle again without changing # anything. self.cr.execute("update ir_attachment set write_date=clock_timestamp() + interval '10 seconds' where id = (select max(id) from ir_attachment)") # Compile a fourth time, without changes self._bundle(False, False)
def test_03_date_invalidation(self): """ Checks that a bundle is invalidated when one of its assets' modification date is changed. """ bundle0 = AssetsBundle(self.jsbundle_xmlid, cr=self.cr, uid=self.uid, context={}, registry=self.registry) bundle0.js() last_modified0 = bundle0.last_modified version0 = bundle0.version path = get_resource_path('test_assetsbundle', 'static', 'src', 'js', 'test_jsfile1.js') utime(path, None) # touch bundle1 = AssetsBundle(self.jsbundle_xmlid, cr=self.cr, uid=self.uid, context={}, registry=self.registry) bundle1.js() last_modified1 = bundle1.last_modified version1 = bundle1.version self.assertNotEquals(last_modified0, last_modified1) self.assertNotEquals(version0, version1) # check if the previous attachment is correctly cleaned self.assertEquals(len(self._any_ira_for_bundle('js')), 1)
def test_10_paginated_css_date_invalidation(self): """ Checks that a bundle is invalidated when one of its assets' modification date is changed. """ bundle0 = AssetsBundle(self.cssbundle_xmlid, env=self.env, max_css_rules=1) bundle0.css() last_modified0 = bundle0.last_modified version0 = bundle0.version path = get_resource_path('test_assetsbundle', 'static', 'src', 'css', 'test_cssfile1.css') utime(path, None) # touch bundle1 = AssetsBundle(self.cssbundle_xmlid, env=self.env, max_css_rules=1) bundle1.css() last_modified1 = bundle1.last_modified version1 = bundle1.version self.assertNotEquals(last_modified0, last_modified1) self.assertNotEquals(version0, version1) # check if the previous attachment is correctly cleaned self.assertEquals(len(self._any_ira_for_bundle('css')), 3)
def test_10_paginated_css_date_invalidation(self): """ Checks that a bundle is invalidated when one of its assets' modification date is changed. """ bundle0 = AssetsBundle( self.cssbundle_xmlid, cr=self.cr, uid=self.uid, context={}, registry=self.registry, max_css_rules=1 ) bundle0.css() last_modified0 = bundle0.last_modified version0 = bundle0.version path = get_resource_path("test_assetsbundle", "static", "src", "css", "test_cssfile1.css") utime(path, None) # touch bundle1 = AssetsBundle( self.cssbundle_xmlid, cr=self.cr, uid=self.uid, context={}, registry=self.registry, max_css_rules=1 ) bundle1.css() last_modified1 = bundle1.last_modified version1 = bundle1.version self.assertNotEquals(last_modified0, last_modified1) self.assertNotEquals(version0, version1) # check if the previous attachment is correctly cleaned self.assertEquals(len(self._any_ira_for_bundle("css")), 3)
def _get_wsdl_url(self): for cp in self: # production WebService wsdl_prod_file_path = get_resource_path( 'delivery_carrier_label_postlogistics', 'data', 'production', cp.postlogistics_version + '.wsdl') __, wsdl_prod_path = file_open(wsdl_prod_file_path, pathinfo=True) wsdl_prod_url = 'file://' + wsdl_prod_path # integration WebService wsdl_int_file_path = get_resource_path( 'delivery_carrier_label_postlogistics', 'data', 'integration', cp.postlogistics_version + '.wsdl') __, wsdl_int_path = file_open(wsdl_int_file_path, pathinfo=True) wsdl_int_url = 'file://' + wsdl_int_path if cp.postlogistics_test_mode: cp.postlogistics_wsdl_url = wsdl_int_url else: cp.postlogistics_wsdl_url = wsdl_prod_url
def _get_files(self): def get_scripts(path): if not path: return {} return { version: glob.glob1(opj(path, version), '*.py') for version in os.listdir(path) if os.path.isdir(opj(path, version)) } for pkg in self.graph: if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade' or getattr(pkg, 'load_state', None) == 'to upgrade'): continue self.migrations[pkg.name] = { 'module': get_scripts(get_resource_path(pkg.name, 'migrations')), 'maintenance': get_scripts( get_resource_path('base', 'maintenance', 'migrations', pkg.name)), }
def test_03_date_invalidation(self): """ Checks that a bundle is invalidated when one of its assets' modification date is changed. """ bundle0 = self._get_asset(self.jsbundle_xmlid) bundle0.js() last_modified0 = bundle0.last_modified version0 = bundle0.version path = get_resource_path('test_assetsbundle', 'static', 'src', 'js', 'test_jsfile1.js') utime(path, None) # touch bundle1 = self._get_asset(self.jsbundle_xmlid) bundle1.js() last_modified1 = bundle1.last_modified version1 = bundle1.version self.assertNotEquals(last_modified0, last_modified1) self.assertNotEquals(version0, version1) # check if the previous attachment is correctly cleaned self.assertEquals(len(self._any_ira_for_bundle('js')), 1)
def test_10_paginated_css_date_invalidation(self): """ Checks that a bundle is invalidated when one of its assets' modification date is changed. """ bundle0 = self._get_asset(self.cssbundle_xmlid, env=self.env(context={'max_css_rules': 1})) bundle0.css() last_modified0 = bundle0.last_modified version0 = bundle0.version path = get_resource_path('test_assetsbundle', 'static', 'src', 'css', 'test_cssfile1.css') utime(path, None) # touch bundle1 = self._get_asset(self.cssbundle_xmlid, env=self.env(context={'max_css_rules': 1})) bundle1.css() last_modified1 = bundle1.last_modified version1 = bundle1.version self.assertNotEquals(last_modified0, last_modified1) self.assertNotEquals(version0, version1) # check if the previous attachment is correctly cleaned self.assertEquals(len(self._any_ira_for_bundle('css')), 3)
def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None): """ Get file, attachment or downloadable content If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the binary field (via ``default_get``), otherwise fetches the field for that precise record. :param str xmlid: xmlid of the record :param str model: name of the model to fetch the binary from :param int id: id of the record from which to fetch the binary :param str field: binary field :param bool unique: add a max-age for the cache control :param str filename: choose a filename :param str filename_field: if not create an filename with model-id-field :param bool download: apply headers to download the file :param str mimetype: mintype of the field (for headers) :param str default_mimetype: default mintype if no mintype found :param Environment env: by default use request.env :returns: (status, headers, content) """ env = env or request.env # get object and content obj = None if xmlid: obj = env.ref(xmlid, False) elif id and model in env.registry: obj = env[model].browse(int(id)) # obj exists if not obj or not obj.exists() or field not in obj: return (404, [], None) # check read access try: last_update = obj['__last_update'] except openerp.exceptions.AccessError: return (403, [], None) status, headers, content = None, [], None # attachment by url check module_resource_path = None if model == 'ir.attachment' and obj.type == 'url' and obj.url: url_match = re.match("^/(\w+)/(.+)$", obj.url) if url_match: module = url_match.group(1) module_path = get_module_path(module) module_resource_path = get_resource_path(module, url_match.group(2)) if module_path and module_resource_path: module_path = os.path.join(os.path.normpath(module_path), '') # join ensures the path ends with '/' module_resource_path = os.path.normpath(module_resource_path) if module_resource_path.startswith(module_path): with open(module_resource_path, 'rb') as f: content = base64.b64encode(f.read()) last_update = str(os.path.getmtime(module_resource_path)) if not module_resource_path: module_resource_path = obj.url if not content: status = 301 content = module_resource_path else: content = obj[field] or '' # filename if not filename: if filename_field in obj: filename = obj[filename_field] elif module_resource_path: filename = os.path.basename(module_resource_path) else: filename = "%s-%s-%s" % (obj._model._name, obj.id, field) # mimetype mimetype = 'mimetype' in obj and obj.mimetype or False if not mimetype: if filename: mimetype = mimetypes.guess_type(filename)[0] if not mimetype and getattr(env[model]._fields[field], 'attachment', False): # for binary fields, fetch the ir_attachement for mimetype check attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1) mimetype = attach_mimetype and attach_mimetype[0]['mimetype'] if not mimetype: mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype) headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')] # cache etag = hasattr(request, 'httprequest') and request.httprequest.headers.get('If-None-Match') retag = '"%s"' % hashlib.md5(last_update).hexdigest() status = status or (304 if etag == retag else 200) headers.append(('ETag', retag)) headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0))) # content-disposition default name if download: headers.append(('Content-Disposition', self.content_disposition(filename))) return (status, headers, content)
def binary_content( self, xmlid=None, model="ir.attachment", id=None, field="datas", unique=False, filename=None, filename_field="datas_fname", download=False, mimetype=None, default_mimetype="application/octet-stream", env=None, ): """ Get file, attachment or downloadable content If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the binary field (via ``default_get``), otherwise fetches the field for that precise record. :param str xmlid: xmlid of the record :param str model: name of the model to fetch the binary from :param int id: id of the record from which to fetch the binary :param str field: binary field :param bool unique: add a max-age for the cache control :param str filename: choose a filename :param str filename_field: if not create an filename with model-id-field :param bool download: apply headers to download the file :param str mimetype: mintype of the field (for headers) :param str default_mimetype: default mintype if no mintype found :param Environment env: by default use request.env :returns: (status, headers, content) """ env = env or request.env # get object and content obj = None if xmlid: obj = env.ref(xmlid, False) elif id and model in env.registry: obj = env[model].browse(int(id)) # obj exists if not obj or not obj.exists() or field not in obj: return (404, [], None) # check read access try: last_update = obj["__last_update"] except openerp.exceptions.AccessError: return (403, [], None) status, headers, content = None, [], None # attachment by url check module_resource_path = None if model == "ir.attachment" and obj.type == "url" and obj.url: url_match = re.match("^/(\w+)/(.+)$", obj.url) if url_match: module = url_match.group(1) module_path = get_module_path(module) module_resource_path = get_resource_path(module, url_match.group(2)) if module_path and module_resource_path: module_path = os.path.join(os.path.normpath(module_path), "") # join ensures the path ends with '/' module_resource_path = os.path.normpath(module_resource_path) if module_resource_path.startswith(module_path): with open(module_resource_path, "r") as f: content = base64.b64encode(f.read()) last_update = str(os.path.getmtime(module_resource_path)) if not module_resource_path: module_resource_path = obj.url if not content: status = 301 content = module_resource_path else: content = obj[field] or "" # filename if not filename: if filename_field in obj: filename = obj[filename_field] elif module_resource_path: filename = os.path.basename(module_resource_path) else: filename = "%s-%s-%s" % (obj._model._name, obj.id, field) # mimetype if not mimetype: if "mimetype" in obj and obj.mimetype and obj.mimetype != "application/octet-stream": mimetype = obj.mimetype elif filename: mimetype = mimetypes.guess_type(filename)[0] if not mimetype: mimetype = default_mimetype headers.append(("Content-Type", mimetype)) # cache etag = hasattr(request, "httprequest") and request.httprequest.headers.get("If-None-Match") retag = hashlib.md5(last_update).hexdigest() status = status or (304 if etag == retag else 200) headers.append(("ETag", retag)) headers.append(("Cache-Control", "max-age=%s" % (STATIC_CACHE if unique else 0))) # content-disposition default name if download: headers.append(("Content-Disposition", self.content_disposition(filename))) return (status, headers, content)
def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None): """ Get file, attachment or downloadable content If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the binary field (via ``default_get``), otherwise fetches the field for that precise record. :param str xmlid: xmlid of the record :param str model: name of the model to fetch the binary from :param int id: id of the record from which to fetch the binary :param str field: binary field :param bool unique: add a max-age for the cache control :param str filename: choose a filename :param str filename_field: if not create an filename with model-id-field :param bool download: apply headers to download the file :param str mimetype: mintype of the field (for headers) :param str default_mimetype: default mintype if no mintype found :param Environment env: by default use request.env :returns: (status, headers, content) """ env = env or request.env # get object and content obj = None if xmlid: obj = env.ref(xmlid, False) elif id and model in env.registry: obj = env[model].browse(int(id)) # obj exists if not obj or not obj.exists() or field not in obj: return (404, [], None) # check read access try: last_update = obj['__last_update'] except openerp.exceptions.AccessError: return (403, [], None) status, headers, content = None, [], None # attachment by url check module_resource_path = None if model == 'ir.attachment' and obj.type == 'url' and obj.url: url_match = re.match("^/(\w+)/(.+)$", obj.url) if url_match: module = url_match.group(1) module_path = get_module_path(module) module_resource_path = get_resource_path(module, url_match.group(2)) if module_path and module_resource_path: module_path = os.path.join(os.path.normpath(module_path), '') # join ensures the path ends with '/' module_resource_path = os.path.normpath(module_resource_path) if module_resource_path.startswith(module_path): with open(module_resource_path, 'r') as f: content = base64.b64encode(f.read()) last_update = str(os.path.getmtime(module_resource_path)) if not module_resource_path: module_resource_path = obj.url if not content: status = 301 content = module_resource_path else: content = obj[field] or '' # filename if not filename: if filename_field in obj: filename = obj[filename_field] elif module_resource_path: filename = os.path.basename(module_resource_path) else: filename = "%s-%s-%s" % (obj._model._name, obj.id, field) # mimetype mimetype = 'mimetype' in obj and obj.mimetype or False if not mimetype: if filename: mimetype = mimetypes.guess_type(filename)[0] if not mimetype and getattr(env[model]._fields[field], 'attachment', False): # for binary fields, fetch the ir_attachement for mimetype check attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1) mimetype = attach_mimetype and attach_mimetype[0]['mimetype'] if not mimetype: mimetype = default_mimetype headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')] # cache etag = hasattr(request, 'httprequest') and request.httprequest.headers.get('If-None-Match') retag = hashlib.md5(last_update).hexdigest() status = status or (304 if etag == retag else 200) headers.append(('ETag', retag)) headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0))) # content-disposition default name if download: headers.append(('Content-Disposition', self.content_disposition(filename))) return (status, headers, content)