selvi 40f4b9dc81
Some checks failed
CI / Brand-leak check (push) Has been cancelled
CI / flake8 / pylint-odoo / manifest completeness (push) Has been cancelled
CI / Install all modules with --test-enable (push) Has been cancelled
assignment submission updated
2026-10-06 20:36:21 +05:30

245 lines
11 KiB
Python

import base64
import logging
from odoo import fields, http
from odoo.http import request
_logger = logging.getLogger(__name__)
def _require_login(path):
"""Redirect to login if visitor is not authenticated."""
if request.env.user._is_public():
return request.redirect(f'/web/login?redirect={path}')
return None
class SchoolAssignmentController(http.Controller):
def _get_student_for_user(self):
"""Return the community.school.student record linked to the current portal user."""
partner = request.env.user.partner_id
return request.env['community.school.student'].sudo().search(
[('partner_id', '=', partner.id)], limit=1
)
def _get_teacher_classes(self):
partner = request.env.user.partner_id
return request.env['community.school.class'].sudo().search(
[('teacher_id', '=', partner.id)]
)
# ─────────────────────────────────────────────────────────────
# TEACHER: Create / manage assignments
# ─────────────────────────────────────────────────────────────
@http.route('/school/assignments/teacher', type='http', auth='public', website=True)
def teacher_assignment_list(self, **kwargs):
redirect = _require_login('/school/assignments/teacher')
if redirect:
return redirect
classes = self._get_teacher_classes()
if not classes:
return request.render('community_school.portal_no_classes', {})
assignments = request.env['community.school.assignment'].sudo().search(
[('class_id', 'in', classes.ids)], order='due_date asc'
)
return request.render('community_school.portal_teacher_assignment_list', {
'assignments': assignments,
'classes': classes,
})
@http.route('/school/assignments/teacher/new', type='http', auth='public', website=True)
def teacher_assignment_new(self, **kwargs):
redirect = _require_login('/school/assignments/teacher/new')
if redirect:
return redirect
classes = self._get_teacher_classes()
if not classes:
return request.render('community_school.portal_no_classes', {})
if request.httprequest.method == 'POST':
class_id = int(kwargs.get('class_id', 0))
klass = classes.filtered(lambda c: c.id == class_id)
if not klass:
return request.redirect('/school/assignments/teacher')
vals = {
'name': kwargs.get('title', '').strip(),
'class_id': class_id,
'description': kwargs.get('description', '').strip() or False,
'due_date': kwargs.get('due_date') or False,
'max_score': int(kwargs.get('max_score') or 100),
'state': 'published',
}
request.env['community.school.assignment'].sudo().create(vals)
return request.redirect('/school/assignments/teacher')
return request.render('community_school.portal_teacher_assignment_form', {
'classes': classes,
'assignment': None,
})
@http.route('/school/assignments/teacher/<int:assignment_id>/edit',
type='http', auth='public', website=True)
def teacher_assignment_edit(self, assignment_id, **kwargs):
redirect = _require_login(f'/school/assignments/teacher/{assignment_id}/edit')
if redirect:
return redirect
classes = self._get_teacher_classes()
assignment = request.env['community.school.assignment'].sudo().browse(assignment_id)
if not assignment.exists() or assignment.class_id not in classes:
return request.redirect('/school/assignments/teacher')
if request.httprequest.method == 'POST':
vals = {
'name': kwargs.get('title', '').strip(),
'class_id': int(kwargs.get('class_id', assignment.class_id.id)),
'description': kwargs.get('description', '').strip() or False,
'due_date': kwargs.get('due_date') or False,
'max_score': int(kwargs.get('max_score') or 100),
}
action = kwargs.get('action_state')
if action == 'publish':
vals['state'] = 'published'
elif action == 'close':
vals['state'] = 'closed'
elif action == 'draft':
vals['state'] = 'draft'
assignment.write(vals)
return request.redirect('/school/assignments/teacher')
return request.render('community_school.portal_teacher_assignment_form', {
'classes': classes,
'assignment': assignment,
})
@http.route('/school/assignments/teacher/<int:assignment_id>/submissions',
type='http', auth='public', website=True)
def teacher_view_submissions(self, assignment_id, **kwargs):
redirect = _require_login(f'/school/assignments/teacher/{assignment_id}/submissions')
if redirect:
return redirect
classes = self._get_teacher_classes()
assignment = request.env['community.school.assignment'].sudo().browse(assignment_id)
if not assignment.exists() or assignment.class_id not in classes:
return request.redirect('/school/assignments/teacher')
submissions = request.env['community.school.submission'].sudo().search(
[('assignment_id', '=', assignment_id)]
)
return request.render('community_school.portal_teacher_submissions', {
'assignment': assignment,
'submissions': submissions,
})
@http.route('/school/assignments/teacher/submission/<int:submission_id>/grade',
type='http', auth='public', website=True, methods=['POST'])
def teacher_grade_submission(self, submission_id, **kwargs):
redirect = _require_login(f'/school/assignments/teacher/submission/{submission_id}/grade')
if redirect:
return redirect
classes = self._get_teacher_classes()
submission = request.env['community.school.submission'].sudo().browse(submission_id)
if not submission.exists() or submission.assignment_id.class_id not in classes:
return request.redirect('/school/assignments/teacher')
score = kwargs.get('score', '').strip()
feedback = kwargs.get('feedback', '').strip()
vals = {'feedback': feedback or False, 'state': 'graded'}
if score.isdigit():
vals['score'] = int(score)
submission.write(vals)
return request.redirect(
f'/school/assignments/teacher/{submission.assignment_id.id}/submissions'
)
# ─────────────────────────────────────────────────────────────
# STUDENT: View assignments & upload submissions
# ─────────────────────────────────────────────────────────────
@http.route('/school/assignments/student', type='http', auth='public', website=True)
def student_assignment_list(self, **kwargs):
redirect = _require_login('/school/assignments/student')
if redirect:
return redirect
student = self._get_student_for_user()
if not student:
return request.render('community_school.portal_no_student', {})
enrolled_class_ids = student.enrollment_ids.filtered(
lambda e: e.state == 'enrolled'
).mapped('class_id').ids
assignments = request.env['community.school.assignment'].sudo().search(
[('class_id', 'in', enrolled_class_ids), ('state', '=', 'published')],
order='due_date asc',
)
# Build map of existing submissions for this student
my_submissions = request.env['community.school.submission'].sudo().search(
[('student_id', '=', student.id), ('assignment_id', 'in', assignments.ids)]
)
submission_by_assignment = {s.assignment_id.id: s for s in my_submissions}
return request.render('community_school.portal_student_assignment_list', {
'assignments': assignments,
'submission_by_assignment': submission_by_assignment,
'student': student,
})
@http.route('/school/assignments/student/<int:assignment_id>',
type='http', auth='public', website=True)
def student_assignment_detail(self, assignment_id, **kwargs):
redirect = _require_login(f'/school/assignments/student/{assignment_id}')
if redirect:
return redirect
student = self._get_student_for_user()
if not student:
return request.render('community_school.portal_no_student', {})
assignment = request.env['community.school.assignment'].sudo().browse(assignment_id)
if not assignment.exists() or assignment.state != 'published':
return request.redirect('/school/assignments/student')
# Verify student is enrolled in this class
enrollment = student.enrollment_ids.filtered(
lambda e: e.class_id.id == assignment.class_id.id and e.state == 'enrolled'
)
if not enrollment:
return request.redirect('/school/assignments/student')
existing_submission = request.env['community.school.submission'].sudo().search(
[('assignment_id', '=', assignment_id), ('student_id', '=', student.id)], limit=1
)
if request.httprequest.method == 'POST':
if existing_submission:
return request.redirect(f'/school/assignments/student/{assignment_id}')
notes = kwargs.get('notes', '').strip()
file_upload = request.httprequest.files.get('submission_file')
attachment_data = False
attachment_name = False
if file_upload and file_upload.filename:
try:
attachment_data = base64.b64encode(file_upload.read())
attachment_name = file_upload.filename
except Exception:
_logger.warning('Failed to read uploaded submission file')
request.env['community.school.submission'].sudo().create({
'assignment_id': assignment_id,
'enrollment_id': enrollment[0].id,
'notes': notes or False,
'attachment_data': attachment_data,
'attachment_name': attachment_name,
'submitted_on': fields.Datetime.now(),
'state': 'submitted',
})
return request.redirect(f'/school/assignments/student/{assignment_id}')
return request.render('community_school.portal_student_assignment_detail', {
'assignment': assignment,
'submission': existing_submission,
'student': student,
})