Skip to content

Commit 7ce34c3

Browse files
committed
Fix learners events for assignments
1 parent a618256 commit 7ce34c3

5 files changed

Lines changed: 101 additions & 3 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 6.0.4 on 2026-05-05 07:37
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("django_email_learning", "0025_alter_assignmentsubmission_status"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="assignmentsubmission",
15+
name="delivery",
16+
field=models.OneToOneField(
17+
on_delete=django.db.models.deletion.CASCADE,
18+
related_name="assignment_submission",
19+
to="django_email_learning.contentdelivery",
20+
),
21+
),
22+
]

django_email_learning/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,7 @@ class SubmissionStatus(models.TextChoices):
11101110
delivery = models.OneToOneField(
11111111
ContentDelivery,
11121112
on_delete=models.CASCADE,
1113-
related_name="assignment_submissions",
1113+
related_name="assignment_submission",
11141114
unique=True,
11151115
)
11161116
text_submission = models.TextField(null=True, blank=True)

django_email_learning/platform/api/serializers.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from django.urls import reverse
1313
from django_email_learning.models import (
1414
ApiKey,
15+
AssignmentSubmission,
1516
ContentDelivery,
1617
CourseInstructor,
1718
DeliveryStatus,
@@ -792,11 +793,19 @@ class EventType(enum.StrEnum):
792793
VERIFIED = "verified"
793794
DEACTIVATED = "deactivated"
794795
QUIZ_SUBMITED = "quiz_submitted"
796+
ASSIGNMENT_SUBMITTED = "assignment_submitted"
797+
ASSIGNMENT_REVIEWED = "assignment_reviewed"
795798
CONTENT_SENT = "content_sent"
796799
REMINDER_SENT = "reminder_sent"
797800
COURSE_COMPLETED = "course_completed"
798801

799802

803+
class ReviewResult(enum.StrEnum):
804+
APPROVED = "approved"
805+
REJECTED = "rejected"
806+
REQUESTING_CHANGES = "requesting_changes"
807+
808+
800809
class DeactivatedEvent(BaseModel):
801810
type: Literal[EventType.DEACTIVATED] = Field(
802811
default=EventType.DEACTIVATED, exclude=True
@@ -816,6 +825,24 @@ class QuizSubmitedEvent(BaseModel):
816825
is_practice: bool
817826

818827

828+
class AssignmentSubmitedEvent(BaseModel):
829+
type: Literal[EventType.ASSIGNMENT_SUBMITTED] = Field(
830+
default=EventType.ASSIGNMENT_SUBMITTED, exclude=True
831+
)
832+
assignment_id: int
833+
assignment_title: str
834+
835+
836+
class AssignmentReviewdEvent(BaseModel):
837+
type: Literal[EventType.ASSIGNMENT_REVIEWED] = Field(
838+
default=EventType.ASSIGNMENT_REVIEWED, exclude=True
839+
)
840+
assignment_id: int
841+
assignment_title: str
842+
review_result: ReviewResult
843+
reviewed_by: str
844+
845+
819846
class ReminderSentEvent(BaseModel):
820847
type: Literal[EventType.REMINDER_SENT] = Field(
821848
default=EventType.REMINDER_SENT, exclude=True
@@ -836,7 +863,7 @@ class ContentSentEvent(BaseModel):
836863
class Event(BaseModel):
837864
type: EventType
838865
timestamp: datetime
839-
event_data: DeactivatedEvent | QuizSubmitedEvent | ContentSentEvent | ReminderSentEvent | None = Field(
866+
event_data: DeactivatedEvent | QuizSubmitedEvent | ContentSentEvent | AssignmentSubmitedEvent | AssignmentReviewdEvent | ReminderSentEvent | None = Field(
840867
discriminator="type"
841868
) # REGISTERED, VERIFIED, COURSE_COMPLETED have no additional data
842869

@@ -897,6 +924,35 @@ def from_django_model(enrollment: Enrollment) -> "EnrollmentResponse":
897924
),
898925
)
899926
)
927+
submission = delivery.assignment_submission # type: ignore[attr-defined]
928+
if submission:
929+
events.append(
930+
Event(
931+
type=EventType.ASSIGNMENT_SUBMITTED,
932+
timestamp=submission.submitted_at, # type: ignore[arg-type]
933+
event_data=AssignmentSubmitedEvent(
934+
assignment_id=delivery.course_content.assignment.id, # type: ignore[union-attr]
935+
assignment_title=delivery.course_content.assignment.title, # type: ignore[union-attr]
936+
),
937+
)
938+
)
939+
if (
940+
submission.reviewed_at
941+
and submission.status
942+
!= AssignmentSubmission.SubmissionStatus.PENDING_REVIEW
943+
):
944+
events.append(
945+
Event(
946+
type=EventType.ASSIGNMENT_REVIEWED,
947+
timestamp=submission.reviewed_at, # type: ignore[arg-type]
948+
event_data=AssignmentReviewdEvent(
949+
assignment_id=delivery.course_content.assignment.id, # type: ignore[union-attr]
950+
assignment_title=delivery.course_content.assignment.title, # type: ignore[union-attr]
951+
review_result=ReviewResult(submission.status), # type: ignore[union-attr]
952+
reviewed_by=submission.reviewer.display_name, # type: ignore[union-attr, arg-type]
953+
),
954+
)
955+
)
900956
# TODO:events for reminders and submissions for assignments
901957

902958
if delivery.course_content.type == "quiz":

django_email_learning/platform/views.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,15 @@ def get_locale_messages(self) -> Dict[str, str]:
580580
"learner_verified": _("Learner Verified Email"),
581581
"lesson_sent": _("Lesson Sent"),
582582
"quiz_sent": _("Quiz Sent"),
583+
"assignment_sent": _("Assignment Sent"),
583584
"quiz_submitted": _("Quiz Submitted"),
585+
"assignment_submitted": _("Assignment Submitted"),
586+
"assignment_reviewed": _("Assignment Reviewed"),
587+
"reviewed_by": _("Reviewed By"),
588+
"assignment_title": _("Assignment Title"),
589+
"requesting_changes": _("Requesting Changes"),
590+
"approved": _("Approved"),
591+
"rejected": _("Rejected"),
584592
"course_completed": _("Course Completed"),
585593
"learner_deactivated": _("Learner Deactivated"),
586594
"score": _("Score"),

frontend/platform/learners/Learners.jsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import AppRegistrationIcon from '@mui/icons-material/AppRegistration';
66
import HowToRegIcon from '@mui/icons-material/HowToReg';
77
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
88
import BallotIcon from '@mui/icons-material/Ballot';
9+
import AssignmentIcon from '@mui/icons-material/Assignment';
10+
import AssignmentIndIcon from '@mui/icons-material/AssignmentInd';
911
import AssignmentReturnedIcon from '@mui/icons-material/AssignmentReturned';
1012
import NotificationsActiveIcon from '@mui/icons-material/NotificationsActive';
1113
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
@@ -39,10 +41,13 @@ function Learners(initialQs="") {
3941
'verified': {icon: <HowToRegIcon />, color: "#66bb6a", title: localeMessages["learner_verified"]},
4042
'content_sent_lesson': {icon: <LibraryBooksIcon />, color: "#00acc1", title: localeMessages["lesson_sent"]},
4143
'content_sent_quiz': {icon: <BallotIcon />, color: "#26a69a", title: localeMessages["quiz_sent"]},
44+
'content_sent_assignment': {icon: <AssignmentIcon />, color: "#336eb7", title: localeMessages["assignment_sent"]},
4245
'quiz_submitted': {icon: <AssignmentReturnedIcon />, color: "#26a69a", title: localeMessages["quiz_submitted"]},
4346
'course_completed': {icon: <SchoolIcon />, color: "#0097a7", title: localeMessages["course_completed"]},
4447
'deactivated': {icon: <BackspaceIcon />, color: "#b71c1c", title: localeMessages["learner_deactivated"]},
45-
"reminder_sent": {icon: <NotificationsActiveIcon />, color: "#ae4ad6", title: localeMessages["reminder_sent"]},
48+
'reminder_sent': {icon: <NotificationsActiveIcon />, color: "#ae4ad6", title: localeMessages["reminder_sent"]},
49+
'assignment_submitted': {icon: <AssignmentReturnedIcon />, color: "#23bca8", title: localeMessages["assignment_submitted"]},
50+
'assignment_reviewed': {icon: <AssignmentIndIcon />, color: "#336eb7", title: localeMessages["assignment_reviewed"]},
4651
};
4752

4853

@@ -97,6 +102,13 @@ function Learners(initialQs="") {
97102
<Box><Typography>{localeMessages["score"]}: {event.event_data.score}</Typography></Box>
98103
<Box><Typography sx={{ display: 'flex', alignItems: 'center' }}>{ event.event_data.is_practice ? <Chip label={localeMessages["practice_attempt"]} size="small"/> : <>{localeMessages["result"]}: {event.event_data.is_passed ? <>{localeMessages["passed"]}<CheckCircleIcon sx={{color: "#4caf50", marginX: "4px"}} /></> : <> {localeMessages["failed"]}<CancelIcon sx={{color: "#f44336", marginX: "4px"}} /></>}</>}</Typography></Box>
99104
</>}
105+
{ event.type === "assignment_reviewed" && <>
106+
<Box><Typography>{localeMessages["result"]}: {event.event_data.review_result === "approved" ? <><Typography component="span" sx={{color: "#4caf50"}}>{localeMessages["approved"]}</Typography><CheckCircleIcon sx={{color: "#4caf50", marginX: "4px"}} /></> : event.event_data.review_result === "rejected" ? <><Typography component="span" sx={{color: "#f44336"}}>{localeMessages["rejected"]}</Typography><CancelIcon sx={{color: "#f44336", marginX: "4px"}} /></> : <Typography component="span" sx={{color: "#ff9800"}}>{localeMessages["requesting_changes"]}</Typography>}</Typography></Box>
107+
<Box><Typography>{localeMessages["reviewed_by"]}: {event.event_data.reviewed_by}</Typography></Box>
108+
</>}
109+
{ event.type === "assignment_submitted" && <>
110+
<Box><Typography>{localeMessages["assignment_title"]}: {event.event_data.assignment_title}</Typography></Box>
111+
</>}
100112
{ event.type === "content_sent" && <>
101113
<Box><Typography>{event.event_data.course_content_title}</Typography></Box>
102114
</>}

0 commit comments

Comments
 (0)