feat: initial backend codebase — EnCoach v3

Complete Odoo 19 backend with 25 custom addons:
- encoach_core: user/entity/role management
- encoach_api: REST API + JWT auth
- encoach_ai: OpenAI integration, AI settings, generation
- encoach_ai_course: AI-powered English & IELTS course generation
- encoach_exam_template/session: exam creation, structures, sessions
- encoach_scoring: AI auto-grading + manual approval
- encoach_vector: pgvector RAG integration
- encoach_adaptive: adaptive learning engine
- encoach_placement: placement testing
- encoach_taxonomy/resources: content taxonomy & resource management
- Plus 14 more modules for courses, branding, portal, etc.

Includes docs: user guide, generation report, developer workflow.

Made-with: Cursor
This commit is contained in:
Yamen Ahmad
2026-04-11 15:44:20 +04:00
commit 982d4bca30
371 changed files with 35211 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import exam_session

View File

@@ -0,0 +1,43 @@
import logging
import time
import jwt as pyjwt
from odoo import http
from odoo.http import request
_logger = logging.getLogger(__name__)
class ExamSessionController(http.Controller):
def _generate_exam_jwt(self, user_id):
secret = request.env['ir.config_parameter'].sudo().get_param('encoach.jwt_secret')
if not secret:
return ''
return pyjwt.encode(
{'user_id': user_id, 'exp': int(time.time()) + 7200},
secret, algorithm='HS256',
)
@http.route('/exam/session/<int:attempt_id>', type='http',
auth='user', website=False)
def exam_session(self, attempt_id, **kw):
attempt = request.env['encoach.student.attempt'].sudo().browse(attempt_id)
if not attempt.exists() or attempt.student_id.id != request.env.user.id:
return request.not_found()
token = self._generate_exam_jwt(request.env.user.id)
return request.render('encoach_exam_session.exam_session_page', {
'attempt': attempt,
'session_token': token,
})
@http.route('/placement/test/<int:session_id>', type='http',
auth='user', website=True)
def placement_test(self, session_id, **kw):
session = request.env['encoach.cat.session'].sudo().browse(session_id)
if not session.exists() or session.student_id.id != request.env.user.id:
return request.not_found()
return request.render('encoach_exam_session.placement_session_page', {
'cat_session': session,
})