From e5d3fdcaa855986e6319835bff32ac5a5dd8b4bc Mon Sep 17 00:00:00 2001 From: vidhya Date: Thu, 15 Oct 2026 21:06:32 +0530 Subject: [PATCH] fix(education): harden production readiness and access controls --- .../education_demo_data/tests/test_demo_login.py | 4 ++-- .../education_library/tests/test_library_core.py | 6 +++--- .../education_mobile_api/controllers/student.py | 15 ++++++++------- .../models/student_certificate.py | 10 +++++----- .../android/app/src/main/AndroidManifest.xml | 2 ++ flutter_app/ios/Runner/Info.plist | 4 ++++ 6 files changed, 24 insertions(+), 17 deletions(-) diff --git a/addons/education_demo_data/tests/test_demo_login.py b/addons/education_demo_data/tests/test_demo_login.py index 1b8cc5b..905369f 100644 --- a/addons/education_demo_data/tests/test_demo_login.py +++ b/addons/education_demo_data/tests/test_demo_login.py @@ -27,6 +27,6 @@ class TestDemoLogin(HttpCase): def test_05_demo_login_missing_role(self): """ Test missing role gets rejected """ - # using GET instead of POST causes a 405 Method Not Allowed, or missing role in POST causes 403 - response = self.url_open('/demo/login', data={}) + # Pass empty role in POST body to test missing role validation resulting in 403 + response = self.url_open('/demo/login', data={'role': ''}) self.assertEqual(response.status_code, 403, "Should be Access Denied") diff --git a/addons/education_library/tests/test_library_core.py b/addons/education_library/tests/test_library_core.py index 4f1f82f..c5a1f42 100644 --- a/addons/education_library/tests/test_library_core.py +++ b/addons/education_library/tests/test_library_core.py @@ -41,13 +41,13 @@ class TestLibraryCore(TransactionCase): 'name': 'BTech CS', 'code': 'BTECH-CS', 'level_id': self.level.id, 'department_id': self.department.id, 'duration': 4, 'duration_unit': 'years', 'company_id': self.company.id, }) self.batch = self.env['education.batch'].create({ - 'name': 'Batch 2025', 'code': 'B2025', + 'name': 'Batch Library Test', 'code': 'B_LIB_25', 'company_id': self.company.id, }) self.semester = self.env['education.semester'].create({ - 'name': 'Semester 1', 'code': 'SEM1', + 'name': 'Semester Library Test', 'code': 'SEM_LIB_1', 'company_id': self.company.id, }) self.section = self.env['education.section'].create({ - 'name': 'Section A', 'code': 'SEC-A', + 'name': 'Section Library Test', 'code': 'SEC_LIB_A', 'company_id': self.company.id, }) self.category_1 = self.Category.create({ diff --git a/addons/education_mobile_api/controllers/student.py b/addons/education_mobile_api/controllers/student.py index cc84bd8..f22c9e8 100644 --- a/addons/education_mobile_api/controllers/student.py +++ b/addons/education_mobile_api/controllers/student.py @@ -431,6 +431,7 @@ class MobileStudent(http.Controller): exams = request.env['education.exam'].sudo().search([ ('program_id', '=', student.program_id.id), ('academic_year_id', '=', student.academic_year_id.id), + ('state', 'in', ['scheduled', 'ongoing', 'completed', 'results_published']), ], order='start_date desc') exams_data = [{ @@ -909,7 +910,7 @@ class MobileStudent(http.Controller): headers = [ ('Content-Type', mime_type), ('Content-Disposition', f'inline; filename="{filename}"'), - ('Content-Length', len(file_data)), + ('Content-Length', str(len(file_data))), ] return request.make_response(file_data, headers=headers) except Exception as e: @@ -1003,15 +1004,15 @@ class MobileStudent(http.Controller): return json_response(False, error_code="NOT_ISSUED", error_message="Certificate has not been issued yet.", status=400) if not cert.document_file: - report = None + report_ref = None if cert.certificate_type == 'bonafide': - report = request.env.ref('education_reports.action_report_bonafide_certificate', raise_if_not_found=False) + report_ref = 'education_reports.action_report_bonafide_certificate' elif cert.certificate_type == 'id_card': - report = request.env.ref('education_reports.action_report_student_id_card', raise_if_not_found=False) + report_ref = 'education_reports.action_report_student_id_card' - if report: + if report_ref and request.env.ref(report_ref, raise_if_not_found=False): try: - pdf_content, _ = report.sudo()._render_qweb_pdf(student.ids) + pdf_content, _ = request.env['ir.actions.report'].sudo()._render_qweb_pdf(report_ref, student.ids) if pdf_content: cert.sudo().write({ 'document_file': base64.b64encode(pdf_content), @@ -1028,7 +1029,7 @@ class MobileStudent(http.Controller): headers = [ ('Content-Type', 'application/pdf'), ('Content-Disposition', f'inline; filename="{filename}"'), - ('Content-Length', len(file_data)), + ('Content-Length', str(len(file_data))), ] return request.make_response(file_data, headers=headers) except Exception as e: diff --git a/addons/education_student/models/student_certificate.py b/addons/education_student/models/student_certificate.py index eda8012..04f1119 100644 --- a/addons/education_student/models/student_certificate.py +++ b/addons/education_student/models/student_certificate.py @@ -79,15 +79,15 @@ class EducationStudentCertificate(models.Model): rec.state = 'issued' # Generate PDF using existing report if available - report = None + report_ref = None if rec.certificate_type == 'bonafide': - report = self.env.ref('education_reports.action_report_bonafide_certificate', raise_if_not_found=False) + report_ref = 'education_reports.action_report_bonafide_certificate' elif rec.certificate_type == 'id_card': - report = self.env.ref('education_reports.action_report_student_id_card', raise_if_not_found=False) + report_ref = 'education_reports.action_report_student_id_card' - if report: + if report_ref and self.env.ref(report_ref, raise_if_not_found=False): try: - pdf_content, _ = report.sudo()._render_qweb_pdf(rec.student_id.ids) + pdf_content, _ = self.env['ir.actions.report'].sudo()._render_qweb_pdf(report_ref, rec.student_id.ids) if pdf_content: rec.document_file = base64.b64encode(pdf_content) clean_code = (rec.name or 'CERT').replace('/', '_') diff --git a/flutter_app/android/app/src/main/AndroidManifest.xml b/flutter_app/android/app/src/main/AndroidManifest.xml index 4ce23a3..dde934f 100644 --- a/flutter_app/android/app/src/main/AndroidManifest.xml +++ b/flutter_app/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,6 @@ + + $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + NSPhotoLibraryUsageDescription + Metatron Student ERP requires access to your photo library to allow uploading student profile photos and verification documents. + NSCameraUsageDescription + Metatron Student ERP requires camera access to allow capturing photos for identity and document submission. UIApplicationSceneManifest UIApplicationSupportsMultipleScenes