Skip to content

Commit

Permalink
Penn-Wrapped Backend Requests
Browse files Browse the repository at this point in the history
request should look like this format:

/wrapped/generate/?username=zharpaz&semester=2020A
  • Loading branch information
zachHarpaz committed Oct 20, 2024
1 parent 5d725aa commit c65cd62
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 51 deletions.
1 change: 1 addition & 0 deletions backend/pennmobile/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
path("dining/", include("dining.urls")),
path("penndata/", include("penndata.urls")),
path("sublet/", include("sublet.urls")),
path("wrapped/", include("wrapped.urls"))
]

urlpatterns = [
Expand Down
41 changes: 4 additions & 37 deletions backend/wrapped/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.contrib import admin
from django.core.exceptions import ValidationError

from wrapped.models import GlobalStat, IndividualStat, UserStatKey, Template, Page
from wrapped.models import GlobalStat, IndividualStat, UserStatKey, StatLocation, Page


class WrappedIndividualAdmin(admin.ModelAdmin):
Expand All @@ -15,49 +15,16 @@ class WrappedGlobalAdmin(admin.ModelAdmin):
search_fields = ["semester__icontains","stat_key__icontains"]



# class PageAdmin(admin.ModelAdmin):
# # Customize the admin interface for YourModel if needed
# list_display = ['template'] # Example field to display, modify as needed

# def save_related(self, request, form, formsets, change):
# super().save_related(request, form, formsets, change)

# # After saving the many-to-many relations, perform validation
# instance = form.instance

# # Count the IndividualStat and GlobalStat entries
# individual_stat_count = instance.IndividualStat.count()
# global_stat_count = instance.GlobalStat.count()

# print(individual_stat_count)

# total_stat_count = individual_stat_count + global_stat_count

# if total_stat_count != instance.template.num_fields:
# raise ValidationError(
# f"The total number of stats (IndividualStat + GlobalStat) "
# f"must equal the template's num_fields value ({instance.template.num_fields})."
# )

# # Validate that all stats are from the same semester
# individual_semesters = set(instance.IndividualStat.values_list('semester', flat=True))
# global_semesters = set(instance.GlobalStat.values_list('semester', flat=True))

# all_semesters = individual_semesters.union(global_semesters)

# if len(all_semesters) > 1:
# raise ValidationError("All IndividualStat and GlobalStat entries must be from the same semester.")

# Register the model with the custom admin class
class StatLocationAdmin(admin.ModelAdmin):
list_display = ["text_field_name", "IndividualStatKey", "GlobalStatKey"]



# admin.site.register(WrappedIndividualAdmin, WrappedGlobalAdmin)
admin.site.register(IndividualStat, WrappedIndividualAdmin)
admin.site.register(GlobalStat, WrappedGlobalAdmin)
admin.site.register(UserStatKey)
admin.site.register(Template)
admin.site.register(StatLocation, StatLocationAdmin)
# admin.site.register(Page, PageAdmin)
admin.site.register(Page)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 5.0.2 on 2024-10-18 21:11

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


class Migration(migrations.Migration):

dependencies = [
('wrapped', '0002_remove_page_temp_remove_template_background_and_more'),
]

operations = [
migrations.RemoveField(
model_name='page',
name='template',
),
migrations.RemoveField(
model_name='page',
name='GlobalStat',
),
migrations.RemoveField(
model_name='page',
name='IndividualStat',
),
migrations.AddField(
model_name='page',
name='template_path',
field=models.CharField(default='nothing', max_length=50),
preserve_default=False,
),
migrations.CreateModel(
name='StatLocation',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text_field_name', models.CharField(max_length=50)),
('GlobalStatKey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wrapped.globalstat')),
('IndividualStatKey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wrapped.userstatkey')),
],
),
migrations.AddField(
model_name='page',
name='stat_locations',
field=models.ManyToManyField(blank=True, to='wrapped.statlocation'),
),
migrations.DeleteModel(
name='Template',
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.0.2 on 2024-10-18 21:15

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('wrapped', '0003_remove_page_template_remove_page_globalstat_and_more'),
]

operations = [
migrations.AddConstraint(
model_name='statlocation',
constraint=models.CheckConstraint(check=models.Q(models.Q(('GlobalStatKey', False), ('IndividualStatKey', True)), models.Q(('GlobalStatKey', True), ('IndividualStatKey', False)), _connector='OR'), name='one_foreign_key_must_be_null'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 5.0.2 on 2024-10-18 21:31

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


class Migration(migrations.Migration):

dependencies = [
('wrapped', '0004_statlocation_one_foreign_key_must_be_null'),
]

operations = [
migrations.AlterField(
model_name='statlocation',
name='GlobalStatKey',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='wrapped.globalstat'),
),
migrations.AlterField(
model_name='statlocation',
name='IndividualStatKey',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='wrapped.userstatkey'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.0.2 on 2024-10-18 21:32

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('wrapped', '0005_alter_statlocation_globalstatkey_and_more'),
]

operations = [
migrations.RemoveConstraint(
model_name='statlocation',
name='one_foreign_key_must_be_null',
),
]
19 changes: 19 additions & 0 deletions backend/wrapped/migrations/0007_page_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.2 on 2024-10-18 21:42

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('wrapped', '0006_remove_statlocation_one_foreign_key_must_be_null'),
]

operations = [
migrations.AddField(
model_name='page',
name='name',
field=models.CharField(default='old', max_length=50),
preserve_default=False,
),
]
19 changes: 19 additions & 0 deletions backend/wrapped/migrations/0008_page_semester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.2 on 2024-10-20 17:35

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('wrapped', '0007_page_name'),
]

operations = [
migrations.AddField(
model_name='page',
name='semester',
field=models.CharField(default='2020A', max_length=5),
preserve_default=False,
),
]
41 changes: 27 additions & 14 deletions backend/wrapped/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.db import models
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db.models import Q

User = get_user_model()


Expand Down Expand Up @@ -43,21 +45,32 @@ class Meta:
def __str__(self) -> str:
return f"User: {self.user} -- {self.stat_key}-{str(self.semester)} : {self.stat_value}"

class Template(models.Model):

# Some file path
name = models.CharField(max_length=10, null=False, blank=False)
template_path = models.CharField(max_length=50, null=False, blank=False)
num_fields = models.IntegerField()
def __str__(self) -> str:
return f"{self.name}"

class StatLocation(models.Model):
IndividualStatKey = models.ForeignKey(UserStatKey,null=True, blank=True, default=None ,on_delete=models.CASCADE)
GlobalStatKey = models.ForeignKey(GlobalStat, null=True,blank=True,default=None,on_delete=models.CASCADE)

text_field_name = models.CharField(max_length=50, null=False, blank=False)
def save(self, *args, **kwargs):
print(self.GlobalStatKey)
if not self.GlobalStatKey:
self.GlobalStatKey = None
if not self.IndividualStatKey:
self.IndividualStatKey = None
if self.IndividualStatKey != None and self.GlobalStatKey != None:
raise Exception("Gave two stat values")


super(StatLocation, self).save(*args, **kwargs)
def __str__(self):
return f"{self.text_field_name} -> {self.IndividualStatKey} --> {self.GlobalStatKey}"

# Why do we want time? Ask Vincent
class Page(models.Model):

# How to do this, using individual vs stat_key ?

template = models.ForeignKey(Template, on_delete=models.CASCADE, null=False, blank=False)
IndividualStat = models.ManyToManyField(IndividualStat, blank=True)
GlobalStat = models.ManyToManyField(GlobalStat, blank=True)

name = models.CharField(max_length=50, null=False, blank=False)
template_path = models.CharField(max_length=50, null=False, blank=False)
stat_locations = models.ManyToManyField(StatLocation, blank=True)
semester = models.CharField(max_length=5, null=False, blank=False)
def __str__(self):
return f"{self.name}"
65 changes: 65 additions & 0 deletions backend/wrapped/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers

from wrapped.models import GlobalStat, IndividualStat, UserStatKey, StatLocation, Page

User = get_user_model()

class MiniUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["username", "first_name", "last_name"]


class StatLocationSerializer(serializers.ModelSerializer):
class Meta:
model = StatLocation
fields = ["IndividualStatKey", "GlobalStatKey", "text_field_name"]

class IndividualStatSerializer(serializers.ModelSerializer):
class Meta:
model = IndividualStat
fields = ["user", "stat_key", "stat_value", "semester"]

class GlobalStatSerializer(serializers.ModelSerializer):
class Meta:
model = GlobalStat
fields = ["stat_key", "stat_value", "semester"]

class UserStatKeySerializer(serializers.ModelSerializer):
class Meta:
model = UserStatKey
fields = ["stat_key"]

class PageSerializer(serializers.ModelSerializer):
stat_location_data = serializers.SerializerMethodField()

class Meta:
model = Page
fields = ["name", "template_path", "stat_location_data"]

def get_stat_location_data(self, obj):
location_stat_dict = {}
for stat_location in obj.stat_locations.all():
individual_stat_data = None
if stat_location.IndividualStatKey:
individual_stats = IndividualStat.objects.filter(stat_key=stat_location.IndividualStatKey).filter(semester=obj.semester)
individual_stat_data = IndividualStatSerializer(individual_stats, many=True).data

global_stat_data = None
if stat_location.GlobalStatKey:
global_stat_data = GlobalStatSerializer(stat_location.GlobalStatKey, many=False).data

if global_stat_data == None:

location_stat_dict[stat_location.text_field_name] = individual_stat_data[0]["stat_value"]
else:
location_stat_dict[stat_location.text_field_name] = global_stat_data["stat_value"]


return location_stat_dict





7 changes: 7 additions & 0 deletions backend/wrapped/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib import admin
from django.urls import path
from .views import GeneratePage
urlpatterns = [
path('generate/', GeneratePage.as_view({"get" : "user_generation"}), name='user_generation'),
]

30 changes: 30 additions & 0 deletions backend/wrapped/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,33 @@
from django.db import transaction
from wrapped.models import Page, IndividualStat, GlobalStat
from django.core.exceptions import ValidationError
from django.http import HttpResponse
from django.contrib.auth import get_user_model
from rest_framework import generics, viewsets
from rest_framework.decorators import action
from django.shortcuts import get_object_or_404
from .serializers import PageSerializer

User = get_user_model()


class GeneratePage(viewsets.ModelViewSet):
queryset = User.objects.all()

@action(detail=False, methods=["get"])
def user_generation(self, request):
username = request.GET.get('username')
semester = request.GET.get("semester")
if not username:
return Response({"error": "Username parameter is required"}, status=400)

# Find the user
user = get_object_or_404(User, username=username)

# Filter pages by this user
# pages = Page.objects.filter(user=user)
pages = Page.objects.filter(semester=semester)

# Serialize the data
serializer = PageSerializer(pages, many=True)
return Response(serializer.data, status=200)

0 comments on commit c65cd62

Please sign in to comment.