diff --git a/web_attachment_size_limit/__manifest__.py b/web_attachment_size_limit/__manifest__.py index e924e9b..365a972 100644 --- a/web_attachment_size_limit/__manifest__.py +++ b/web_attachment_size_limit/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Web Attachment Size Limit", "summary": "Enforce a global maximum size for file uploads", - "version": "14.0.1.0.0", + "version": "14.0.1.0.1", "category": "Web", "website": "https://numigi.com/r/home", "author": "Numigi", diff --git a/web_attachment_size_limit/tests/test_attachment_limit.py b/web_attachment_size_limit/tests/test_attachment_limit.py index 3ad4c59..ed3a492 100644 --- a/web_attachment_size_limit/tests/test_attachment_limit.py +++ b/web_attachment_size_limit/tests/test_attachment_limit.py @@ -1,106 +1,47 @@ # © Numigi (tm) and all its contributors (https://numigi.com/r/home) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -# import io -# import json -# from odoo.tests.common import HttpCase, tagged -# -# -# @tagged('post_install', '-at_install') -# class TestAttachmentSizeLimit(HttpCase): -# -# def setUp(self): -# super(TestAttachmentSizeLimit, self).setUp() -# # Authenticate as admin to have upload rights and establish session -# self.authenticate('admin', 'admin') -# -# # Force the parameter value for the test context (e.g., 100 bytes) -# self.env['ir.config_parameter'].sudo().set_param( -# 'web.max_file_upload_size', '100' -# ) -# -# def _get_csrf_token(self): -# """ -# Fetch the CSRF token from the session info. -# This is required for controllers protected by -# @http.route(..., csrf=True) -# """ -# # We invoke get_session_info via JSON-RPC to retrieve the token -# # url_open does not support 'json' param in this env, so we serialize manually -# response = self.url_open( -# '/web/session/get_session_info', -# data=json.dumps({}), -# headers={'Content-Type': 'application/json'} -# ) -# return response.json().get('result', {}).get('csrf_token') -# -# def test_01_parameter_exists(self): -# """Check that the system parameter is correctly set.""" -# param = self.env['ir.config_parameter'].sudo().get_param( -# 'web.max_file_upload_size' -# ) -# self.assertEqual( -# param, '100', "The parameter value should be 100 for this test." -# ) -# -# def test_02_upload_too_large(self): -# """Try to upload a file of 200 bytes (limit is 100). Should fail.""" -# -# csrf_token = self._get_csrf_token() -# -# file_content = b'x' * 200 -# files = { -# 'ufile': ('big_file.txt', io.BytesIO(file_content), 'text/plain'), -# } -# # We must send the model/id and CSRF token as data fields -# data = { -# 'model': 'res.users', -# 'id': str(self.env.user.id), -# 'csrf_token': csrf_token -# } -# -# # Note: /web/binary/upload_attachment is the standard upload URL -# # We use relative URL '/web/...' so Odoo uses the correct testing port -# response = self.url_open( -# '/web/binary/upload_attachment', data=data, files=files -# ) -# -# response_content = response.content.decode('utf-8') -# -# self.assertIn( -# "File too large", -# response_content, -# "The upload should have been blocked with an error message. " -# "Response: %s" % response_content -# ) -# -# def test_03_upload_success(self): -# """Try to upload a file of 50 bytes (limit is 100). Should succeed.""" -# -# csrf_token = self._get_csrf_token() -# -# file_content = b'x' * 50 -# files = { -# 'ufile': ( -# 'small_file.txt', io.BytesIO(file_content), 'text/plain' -# ), -# } -# data = { -# 'model': 'res.users', -# 'id': str(self.env.user.id), -# 'csrf_token': csrf_token -# } -# -# response = self.url_open( -# '/web/binary/upload_attachment', data=data, files=files -# ) -# response_content = response.content.decode('utf-8') -# -# self.assertNotIn( -# "error", response_content, -# "Valid upload should not return an error." -# ) -# self.assertIn( -# "small_file.txt", response_content, -# "The filename should be in the response." -# ) +from unittest.mock import MagicMock, patch + +from odoo.tests.common import TransactionCase, tagged +from odoo.addons.web_attachment_size_limit.controllers.main import BinaryUploadLimit + + +@tagged("-at_install", "post_install") +class TestAttachmentSizeLimit(TransactionCase): + + def setUp(self): + super().setUp() + self.env["ir.config_parameter"].sudo().set_param( + "web.max_file_upload_size", "100" + ) + self.controller = BinaryUploadLimit() + + def _test_upload(self, content_length: int): + ufile_mock = MagicMock() + ufile_mock.tell.return_value = content_length + + patch_req = patch("odoo.addons.web_attachment_size_limit.controllers.main.request") + patch_sup = patch("odoo.addons.web.controllers.main.Binary.upload_attachment") + + with patch_req as mock_req, patch_sup as mock_sup: + mock_req.env = self.env + mock_req.httprequest.files.getlist.return_value = [ufile_mock] + mock_sup.return_value = '{"id": 123}' + + res = self.controller.upload_attachment( + model="res.users", + id=self.env.user.id, + ufile=ufile_mock, + ) + return res, mock_sup.called + + def test_02_upload_too_large(self): + response, super_called = self._test_upload(200) + assert "File too large" in response + assert not super_called + + def test_03_upload_success(self): + response, super_called = self._test_upload(50) + assert response == '{"id": 123}' + assert super_called \ No newline at end of file diff --git a/web_visual_company_switcher/controllers/company_switcher.py b/web_visual_company_switcher/controllers/company_switcher.py index 1aca275..ee05ac8 100644 --- a/web_visual_company_switcher/controllers/company_switcher.py +++ b/web_visual_company_switcher/controllers/company_switcher.py @@ -57,8 +57,8 @@ def get_companies_data(self): result = { 'companies': companies_data, - 'current_allowed_companies': [int(x) for x in session_allowed_ids], # Ensure int list - 'current_company_id': int(current_company_id) # Ensure int + 'current_allowed_companies': [int(x) for x in session_allowed_ids], + 'current_company_id': int(current_company_id) } return result @@ -66,7 +66,8 @@ def get_companies_data(self): except Exception as e: return {'error': f'Failed to load companies: {str(e)}'} - @http.route('/web/visual_company_switcher/switch_company', type='json', auth='user', csrf=True) + @http.route('/web/visual_company_switcher/switch_company', + type='json', auth='user', csrf=True) def switch_single_company(self, company_id): """Switch to a single company""" try: @@ -90,7 +91,8 @@ def switch_single_company(self, company_id): except Exception as e: return {'error': f'Failed to switch company: {str(e)}'} - @http.route('/web/visual_company_switcher/switch_companies', type='json', auth='user', csrf=True) + @http.route('/web/visual_company_switcher/switch_companies', + type='json', auth='user', csrf=True) def switch_multiple_companies(self, company_ids): """Switch to multiple companies - mimics native Odoo multi-company behavior""" try: @@ -110,7 +112,8 @@ def switch_multiple_companies(self, company_ids): if company not in user.company_ids: return {'error': f'Access denied to company {company.name}'} - # This is the key: set allowed_company_ids in session to enable multi-company context + # This is the key: set allowed_company_ids in session + # to enable multi-company context # This mimics exactly what Odoo's native company switcher does request.session['allowed_company_ids'] = company_ids