fix(education): harden production readiness and access controls

This commit is contained in:
Vidhya 2026-10-15 21:06:32 +05:30
parent 1277f7af43
commit e5d3fdcaa8
6 changed files with 24 additions and 17 deletions

View File

@ -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")

View File

@ -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({

View File

@ -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:

View File

@ -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('/', '_')

View File

@ -1,4 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:label="metatron_student_erp"
android:name="${applicationName}"

View File

@ -26,6 +26,10 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSPhotoLibraryUsageDescription</key>
<string>Metatron Student ERP requires access to your photo library to allow uploading student profile photos and verification documents.</string>
<key>NSCameraUsageDescription</key>
<string>Metatron Student ERP requires camera access to allow capturing photos for identity and document submission.</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>