Skip to content

Commit

Permalink
linting + add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
AaDalal committed Feb 7, 2024
1 parent aba624e commit 730c015
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 19 deletions.
26 changes: 16 additions & 10 deletions backend/degree/admin.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,53 @@
from django.contrib import admin
from django.conf.urls import url
from django.urls import reverse
from django.contrib import admin
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.html import format_html

from degree.models import Degree, DegreePlan, DoubleCountRestriction, Rule, SatisfactionStatus


# Register your models here.
@admin.register(Rule)
class RuleAdmin(admin.ModelAdmin):
search_fields = ["title", "id"]
list_display = ["title", "id", "parent"]
list_select_related = ["parent"]


admin.site.register(DegreePlan)
admin.site.register(SatisfactionStatus)


@admin.register(DoubleCountRestriction)
class DoubleCountRestrictionAdmin(admin.ModelAdmin):
autocomplete_fields = ["rule", "other_rule"]


@admin.register(Degree)
class DegreeAdmin(admin.ModelAdmin):
autocomplete_fields = ["rules"]
list_display = ["program", "degree", "major", "concentration", "year", "view_degree_editor"]

def view_degree_editor(self, obj):
return format_html(
'<a href="{url}?id={id}">View in Degree Editor</a>',
id=obj.id,
url=reverse('admin:degree-editor')
'<a href="{url}?id={id}">View in Degree Editor</a>',
id=obj.id,
url=reverse("admin:degree-editor"),
)

def get_urls(self):
# get the default urls
urls = super().get_urls()
custom_urls = [
url(r'^degree-editor/$', self.admin_site.admin_view(self.degree_editor), name='degree-editor')
url(
r"^degree-editor/$",
self.admin_site.admin_view(self.degree_editor),
name="degree-editor",
)
]
return custom_urls + urls

def degree_editor(self, request):
context = dict(
self.admin_site.each_context(request)
)
return TemplateResponse(request, "degree-editor.html", context)
context = dict(self.admin_site.each_context(request))
return TemplateResponse(request, "degree-editor.html", context)
2 changes: 1 addition & 1 deletion backend/degree/management/commands/deduplicate_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def deduplicate_rules(verbose=False):

class Command(BaseCommand):
help = dedent(
"""
"""
Removes rules that are identical (based on content hash)
"""
)
Expand Down
37 changes: 33 additions & 4 deletions backend/degree/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ def __str__(self) -> str:
class Rule(models.Model):
"""
This model represents a degree requirement rule.
Rules are deduplicated, meaning that
a rule can belong to multiple degrees. In that case, changing a rule on one degree would
also change it on the other degrees.
"""

title = models.CharField(
Expand Down Expand Up @@ -136,7 +140,7 @@ class Rule(models.Model):
help_text=dedent(
"""
String representing a Q() object that returns the set of courses
satisfying this rule. Only non-empty if this is a Rule leaf.
satisfying this rule. Non-empty iff this is a Rule leaf.
This Q object is expected to be normalized before it is serialized
to a string.
"""
Expand Down Expand Up @@ -217,13 +221,13 @@ class DegreePlan(models.Model):

degrees = models.ManyToManyField(
Degree,
help_text="The degree this is associated with.",
help_text="The degrees this degree plan is associated with.",
)

person = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
help_text="The user the schedule belongs to.",
help_text="The user the degree plan belongs to.",
)

created_at = models.DateTimeField(auto_now_add=True)
Expand Down Expand Up @@ -414,11 +418,26 @@ class Meta:


class DoubleCountRestriction(models.Model):
"""
Represents a restriction on the number of courses and credits
that can be double counted between two rules.
Note the following things:
1. this relationship is non-directional: rule and other_rule are interchangeable.
2. the same rule cannot be used for both rule and other_rule.
3. max_courses and max_credits cannot both be null.
4. since rules are can belong to multiple degrees, a double count restriction added
for one degree will affect all other degrees tje rule belongs to.
(2) and (3) are not enforced directly by the database, but are expected to be enforced
in use.
"""

max_courses = models.PositiveSmallIntegerField(
null=True,
help_text=dedent(
"""
The maximum number of courses you can count for both rules.
If null, there is no limit, and max_credits must not be null.
"""
),
)
Expand All @@ -430,11 +449,21 @@ class DoubleCountRestriction(models.Model):
help_text=dedent(
"""
The maximum number of CUs you can count for both rules.
If null, there is no limit, and max_credits must not be null.
"""
),
)

rule = models.ForeignKey(Rule, on_delete=models.CASCADE, related_name="+")
rule = models.ForeignKey(
Rule,
on_delete=models.CASCADE,
related_name="+",
help_text=dedent(
"""
A rule in the double count restriction.
"""
),
)

other_rule = models.ForeignKey(Rule, on_delete=models.CASCADE, related_name="+")

Expand Down
4 changes: 3 additions & 1 deletion backend/degree/utils/parse_degreeworks.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,9 @@ def parse_rulearray(
evaluation = _prompt_for_evaluation(degree, rule_req)
elif evaluation is None:
logging.warn(
f"Evaluation is unknown for `{rule_json['label']}` (nodeId {rule_json['nodeId']} in the degreeworks json). Defaulting to False."
f"Evaluation is unknown for `{rule_json['label']}` "
f"(nodeId {rule_json['nodeId']} in the degreeworks json). "
"Defaulting to False."
)

if evaluation:
Expand Down
7 changes: 4 additions & 3 deletions backend/degree/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
from rest_framework.decorators import api_view
from rest_framework.exceptions import ValidationError
from rest_framework.filters import SearchFilter
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from courses.models import Course
from courses.serializers import CourseListSerializer
from degree.models import Degree, DegreePlan, DoubleCountRestriction, Fulfillment, Rule
from degree.models import Degree, DegreePlan, Fulfillment, Rule
from degree.serializers import (
DegreeDetailSerializer,
DegreeListSerializer,
DegreePlanDetailSerializer,
DegreePlanListSerializer,
DoubleCountRestrictionSerializer,
FulfillmentSerializer,
)


class DegreeViewset(viewsets.ReadOnlyModelViewSet):
"""
Retrieve a list of all Degree objects.
Expand Down Expand Up @@ -86,6 +86,7 @@ def get_queryset(self):
)
return queryset


@api_view(["GET"])
def courses_for_rule(request, rule_id: int):
"""
Expand Down

0 comments on commit 730c015

Please sign in to comment.