Skip to content

Commit

Permalink
feat: add engines model (#219)
Browse files Browse the repository at this point in the history
* feat: add engines model

feat: add test utils

feat: add tests

* chore: apply suggestions from code review

Co-authored-by: Andrey Cañon <[email protected]>

* fix: unify ead and rti courses count

* fix: one to one correct relationship reference

* chore: pr recommendation
  • Loading branch information
johanseto authored Oct 28, 2024
1 parent de65141 commit ddf0d26
Show file tree
Hide file tree
Showing 6 changed files with 524 additions and 2 deletions.
29 changes: 29 additions & 0 deletions eox_nelp/migrations/0012_add_pearson_engines_register.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 3.2.25 on 2024-09-30 18:02

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('eox_nelp', '0011_pearsonrtenevent_course'),
]

operations = [
migrations.CreateModel(
name='PearsonEngine',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('rti_triggers', models.PositiveIntegerField(default=0)),
('cdd_triggers', models.PositiveIntegerField(default=0)),
('ead_triggers', models.PositiveIntegerField(default=0)),
('courses', models.JSONField(default=dict)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
35 changes: 34 additions & 1 deletion eox_nelp/pearson_vue/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.contrib import admin
from django.contrib.auth import get_user_model

from eox_nelp.pearson_vue.models import PearsonRTENEvent
from eox_nelp.pearson_vue.models import PearsonEngine, PearsonRTENEvent

User = get_user_model()

Expand All @@ -27,4 +27,37 @@ class PearsonRTENEventAdmin(admin.ModelAdmin):
list_filter = ["event_type"]


class PearsonEngineAdmin(admin.ModelAdmin):
"""Admin class for PearsonEngineAdmin.
attributes:
list_display: Fields to be shown in admin interface.
search_fields: fields that use to search and find matches.
"""
@admin.display(ordering="user__username", description="User")
def get_user_username(self, obj) -> str:
"""Return username from User instance"""
return obj.user.username

list_display = (
"get_user_username",
"rti_triggers",
"cdd_triggers",
"ead_triggers",
"courses",
"created_at",
"updated_at",
)
search_fields = ("user__username",)
raw_id_fields = ("user",)
ordering = ("-updated_at",)
readonly_fields = (
"rti_triggers",
"cdd_triggers",
"ead_triggers",
"courses",
)


admin.site.register(PearsonRTENEvent, PearsonRTENEventAdmin)
admin.site.register(PearsonEngine, PearsonEngineAdmin)
175 changes: 175 additions & 0 deletions eox_nelp/pearson_vue/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Classes:
PearsonRTENEvent: A model representing an event for the Pearson VUE RTEN service.
PearsonEngine: A model representing the send to the PearsonEngine service per user.
Constants:
EVENT_TYPE_CHOICES: A list of tuples representing the possible choices
Expand Down Expand Up @@ -52,3 +53,177 @@ class PearsonRTENEvent(models.Model):
event_type = models.CharField(max_length=20, choices=EVENT_TYPE_CHOICES)
candidate = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
course = models.ForeignKey(CourseOverview, null=True, on_delete=models.DO_NOTHING)


class PearsonEngine(models.Model):
"""
This model contains data related to user and the integration with PearsonVue engine service.
Attributes:
user (User): OneToOne relationship with User model.
rti_triggers (int): Number of RTI triggers.
cdd_triggers (int): Number of CDD triggers.
ead_triggers (int): Number of EAD triggers.
courses (dict): JSON field storing EAD course data.
created_at (datetime): Timestamp of model instance creation.
updated_at (datetime): Timestamp of last model instance update.
"""

user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
rti_triggers = models.PositiveIntegerField(default=0)
cdd_triggers = models.PositiveIntegerField(default=0)
ead_triggers = models.PositiveIntegerField(default=0)
courses = models.JSONField(default=dict)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def get_triggers(self, trigger_type):
"""
Get the number of triggers for a specific type.
Args:
trigger_type (str): The type of trigger ('rti', 'cdd', or 'ead').
Returns:
int: The number of triggers for the specified type.
Raises:
ValueError: If an invalid trigger type is provided.
"""
trigger_name = f"{trigger_type}_triggers"

if not hasattr(self, trigger_name):
raise ValueError(f"Invalid trigger name: {trigger_name}")

return getattr(self, trigger_name, None)

def set_triggers(self, trigger_type, value):
"""
Set the number of triggers for a specific type.
Args:
trigger_type (str): The type of trigger ('rti', 'cdd', or 'ead').
value (int): The new value for the trigger count.
Raises:
ValueError: If the value is not a non-negative integer or if an invalid trigger type is provided.
"""
trigger_name = f"{trigger_type}_triggers"

if not isinstance(value, int) or value < 0:
raise ValueError("Trigger value must be a non-negative integer")

if not hasattr(self, trigger_name):
raise ValueError(f"Invalid trigger name: {trigger_name}")

setattr(self, trigger_name, value)
self.save()

def increment_trigger(self, trigger_type, increment=1):
"""
Increment the number of triggers for a specific type.
Args:
trigger_type (str): The type of trigger ('rti', 'cdd', or 'ead').
increment (int, optional): The amount to increment. Defaults to 1.
"""
current_value = self.get_triggers(trigger_type)
self.set_triggers(trigger_type, current_value + increment)

def get_courses(self):
"""
Get the courses for a specific action type.
Returns:
dict: The courses for the specified action type.
"""
return self.courses

def get_course_value(self, course_id):
"""
Get the value of a specific course.
Args:
course_id (str): The ID of the course.
Returns:
int: The value of the specified course, or 0 if not found.
"""
courses = self.get_courses()
return courses.get(course_id, 0)

def set_course_value(self, course_id, value):
"""
Set the value of a specific course.
Args:
course_id (str): The ID of the course.
value (int or float): The new value for the course.
Raises:
ValueError: If the value is not a non-negative number.
"""
if not isinstance(value, (int, float)) or value < 0:
raise ValueError("Course value must be a non-negative number")
courses = self.get_courses()
courses[course_id] = value
self.courses = courses
self.save()

def increment_course_value(self, course_id, increment=1):
"""
Increment the value of a specific course.
Args:
course_id (str): The ID of the course.
increment (int or float, optional): The amount to increment. Defaults to 1.
"""
current_value = self.get_course_value(course_id)
self.set_course_value(course_id, current_value + increment)

def remove_course(self, course_id):
"""
Remove a course from the specified action type.
Args:
course_id (str): The ID of the course to remove.
Raises:
ValueError: If the course is not found in the specified action type.
"""
courses = self.get_courses()
if course_id in courses:
del courses[course_id]
self.courses = courses
self.save()
else:
raise ValueError(f"Course {course_id} not found in courses")

def get_course_ids(self):
"""
Get all course IDs for a specific action type.
Returns:
list: A list of all course IDs for the specified action type.
"""
return list(self.get_courses().keys())

def get_total_course_value(self):
"""
Get the total value of all courses for a specific action type.
Returns:
float: The sum of all course values for the specified action type.
"""
return sum(self.get_courses().values())

@property
def total_triggers(self):
"""
Get the total number of triggers across all types.
Returns:
int: The sum of RTI, CDD, and EAD triggers.
"""
return self.rti_triggers + self.cdd_triggers + self.ead_triggers
Loading

0 comments on commit ddf0d26

Please sign in to comment.