feat: complete all 12 missing spec features from EnCoach v3.0 audit

- Add student_progress, course_section models and module_resources M2M
- Activate encoach_resources module with security, views, and ielts_certified field
- Add password strength indicator JS on registration page
- Rewrite onboarding wizard step 4 as placement test prompt with skip option
- Dynamic goal list fetched from exam templates in DB with fallback
- B1 default CEFR level assigned when placement test is skipped
- Teacher review dashboard with 2 API endpoints for AI content approval
- IELTS examiner review interface with review_status, examiner_notes fields
- Content source gate: mandatory review for AI, spot-check for certified
- Resource-to-learning-style matching in adaptive engine
- Daily cron job for teacher no-progress alerts via mail.activity
- Entity student placement redirect on dashboard access
- Fix Odoo 19 compat: search view groups, ir.cron fields, OWL xml templates

Made-with: Cursor
This commit is contained in:
Yamen Ahmad
2026-04-08 03:12:00 +04:00
parent e30e52e21e
commit 5ff9f12de7
39 changed files with 1106 additions and 87 deletions

View File

@@ -198,16 +198,39 @@ class EncoachSignupController(http.Controller):
@jwt_required
def onboarding_goals(self, **kw):
try:
goals = [
{'id': 'ielts', 'name': 'IELTS Preparation',
'icon': 'mdi-book-education'},
{'id': 'general_english', 'name': 'General English',
'icon': 'mdi-translate'},
{'id': 'math', 'name': 'Mathematics',
'icon': 'mdi-calculator-variant'},
{'id': 'it', 'name': 'Information Technology',
'icon': 'mdi-laptop'},
]
# Dynamic goals from exam templates in DB
Template = request.env['encoach.exam.template'].sudo()
templates = Template.search([('active', '=', True)])
seen = set()
goals = []
icon_map = {
'ielts': 'fa-language',
'general_english': 'fa-comments',
'general english': 'fa-comments',
'academic': 'fa-graduation-cap',
'math': 'fa-calculator',
'mathematics': 'fa-calculator',
'it': 'fa-laptop',
'information technology': 'fa-laptop',
}
for tpl in templates:
subj = tpl.subject_id
if subj and subj.name and subj.name.lower() not in seen:
seen.add(subj.name.lower())
goal_id = subj.name.lower().replace(' ', '_')
goals.append({
'id': goal_id,
'name': subj.name,
'icon': icon_map.get(goal_id, icon_map.get(subj.name.lower(), 'fa-book')),
})
# Fallback if no templates found
if not goals:
goals = [
{'id': 'ielts', 'name': 'IELTS Preparation', 'icon': 'fa-language'},
{'id': 'general_english', 'name': 'General English', 'icon': 'fa-comments'},
{'id': 'math', 'name': 'Mathematics', 'icon': 'fa-calculator'},
{'id': 'it', 'name': 'Information Technology', 'icon': 'fa-laptop'},
]
return _json_response({'goals': goals})
except Exception as e:
@@ -229,6 +252,8 @@ class EncoachSignupController(http.Controller):
if not learning_goal:
return _error_response('learning_goal is required', 400)
skip_placement = body.get('skip_placement', False)
profile_vals = {
'user_id': user.id,
'learning_goal': learning_goal,
@@ -238,6 +263,10 @@ class EncoachSignupController(http.Controller):
'exam_date': body.get('exam_date'),
}
# Assign B1 default level when placement test is skipped
if skip_placement:
profile_vals['cefr_level'] = 'b1'
Profile = request.env['encoach.student.profile'].sudo()
profile = Profile.search([('user_id', '=', user.id)], limit=1)
if profile:
@@ -253,6 +282,7 @@ class EncoachSignupController(http.Controller):
return _json_response({
'message': 'Onboarding complete',
'profile_id': profile.id,
'skip_placement': skip_placement,
})
except Exception as e: