fix(education): harden production readiness and access controls
This commit is contained in:
parent
1277f7af43
commit
e5d3fdcaa8
@ -27,6 +27,6 @@ class TestDemoLogin(HttpCase):
|
|||||||
|
|
||||||
def test_05_demo_login_missing_role(self):
|
def test_05_demo_login_missing_role(self):
|
||||||
""" Test missing role gets rejected """
|
""" Test missing role gets rejected """
|
||||||
# using GET instead of POST causes a 405 Method Not Allowed, or missing role in POST causes 403
|
# Pass empty role in POST body to test missing role validation resulting in 403
|
||||||
response = self.url_open('/demo/login', data={})
|
response = self.url_open('/demo/login', data={'role': ''})
|
||||||
self.assertEqual(response.status_code, 403, "Should be Access Denied")
|
self.assertEqual(response.status_code, 403, "Should be Access Denied")
|
||||||
|
|||||||
@ -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,
|
'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({
|
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({
|
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({
|
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({
|
self.category_1 = self.Category.create({
|
||||||
|
|||||||
@ -431,6 +431,7 @@ class MobileStudent(http.Controller):
|
|||||||
exams = request.env['education.exam'].sudo().search([
|
exams = request.env['education.exam'].sudo().search([
|
||||||
('program_id', '=', student.program_id.id),
|
('program_id', '=', student.program_id.id),
|
||||||
('academic_year_id', '=', student.academic_year_id.id),
|
('academic_year_id', '=', student.academic_year_id.id),
|
||||||
|
('state', 'in', ['scheduled', 'ongoing', 'completed', 'results_published']),
|
||||||
], order='start_date desc')
|
], order='start_date desc')
|
||||||
|
|
||||||
exams_data = [{
|
exams_data = [{
|
||||||
@ -909,7 +910,7 @@ class MobileStudent(http.Controller):
|
|||||||
headers = [
|
headers = [
|
||||||
('Content-Type', mime_type),
|
('Content-Type', mime_type),
|
||||||
('Content-Disposition', f'inline; filename="{filename}"'),
|
('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)
|
return request.make_response(file_data, headers=headers)
|
||||||
except Exception as e:
|
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)
|
return json_response(False, error_code="NOT_ISSUED", error_message="Certificate has not been issued yet.", status=400)
|
||||||
|
|
||||||
if not cert.document_file:
|
if not cert.document_file:
|
||||||
report = None
|
report_ref = None
|
||||||
if cert.certificate_type == 'bonafide':
|
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':
|
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:
|
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:
|
if pdf_content:
|
||||||
cert.sudo().write({
|
cert.sudo().write({
|
||||||
'document_file': base64.b64encode(pdf_content),
|
'document_file': base64.b64encode(pdf_content),
|
||||||
@ -1028,7 +1029,7 @@ class MobileStudent(http.Controller):
|
|||||||
headers = [
|
headers = [
|
||||||
('Content-Type', 'application/pdf'),
|
('Content-Type', 'application/pdf'),
|
||||||
('Content-Disposition', f'inline; filename="{filename}"'),
|
('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)
|
return request.make_response(file_data, headers=headers)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@ -79,15 +79,15 @@ class EducationStudentCertificate(models.Model):
|
|||||||
rec.state = 'issued'
|
rec.state = 'issued'
|
||||||
|
|
||||||
# Generate PDF using existing report if available
|
# Generate PDF using existing report if available
|
||||||
report = None
|
report_ref = None
|
||||||
if rec.certificate_type == 'bonafide':
|
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':
|
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:
|
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:
|
if pdf_content:
|
||||||
rec.document_file = base64.b64encode(pdf_content)
|
rec.document_file = base64.b64encode(pdf_content)
|
||||||
clean_code = (rec.name or 'CERT').replace('/', '_')
|
clean_code = (rec.name or 'CERT').replace('/', '_')
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<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
|
<application
|
||||||
android:label="metatron_student_erp"
|
android:label="metatron_student_erp"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|||||||
@ -26,6 +26,10 @@
|
|||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<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>
|
<key>UIApplicationSceneManifest</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UIApplicationSupportsMultipleScenes</key>
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user