Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Chacoon3 committed Nov 28, 2023
1 parent c36bd31 commit aea1770
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 76 deletions.
9 changes: 9 additions & 0 deletions bmgt435_elp/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ class CaseRecordAdmin(admin.ModelAdmin):
list_display = ["id", "group_id", "case_id", "state", "score", "summary_dict"]


class CaseConfigAdmin(admin.ModelAdmin):
fieldsets = [
("None", {"fields": ["case_id", "semester_id", "create_time", "edited_time", "config_json",]}),
]

list_display = ["id", "case_id", "semester_id", "create_time", "edited_time", "config_json",]


class GroupAdmin(admin.ModelAdmin):

list_display = ["id", "create_time", "name"]
Expand All @@ -42,3 +50,4 @@ class SemesterAdmin(admin.ModelAdmin):
admin.site.register(BMGTCaseRecord, CaseRecordAdmin)
admin.site.register(BMGTGroup, GroupAdmin)
admin.site.register(BMGTSemester, SemesterAdmin)
admin.site.register(BMGTCaseConfig, CaseConfigAdmin)
136 changes: 82 additions & 54 deletions bmgt435_elp/apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .simulation import FoodDelivery, SimulationException
from .bmgtModels import *
from .utils.apiUtils import request_error_handler, password_valid, generic_paginated_query, pager_params_from_request, create_pager_params, AppResponse
from .utils.databaseUtils import InMemoryCache

import pandas as pd
import json
Expand All @@ -21,6 +22,7 @@

CASE_RECORD_PATH = bmgt435_file_system.base_location.__str__() + "case_records/"
MAX_GROUP_SIZE = 4
FOOD_DELIVERY_CASE_ID = 1


def _get_session_user(request: HttpRequest) -> BMGTUser:
Expand Down Expand Up @@ -190,21 +192,22 @@ def groups_paginated(request: HttpRequest,) -> HttpResponse:
def join_group(request: HttpRequest) -> HttpResponse:
try:
resp = AppResponse()

user: BMGTUser = _get_session_user(request)
data = json.loads(request.body)
group_id = data['group_id']
if user.group == None:
if user.role == BMGTUser.BMGTUserRole.ADMIN: # admin can join any group of any semester
group = BMGTGroup.objects.get(id=group_id)
else:
group = BMGTGroup.objects.get(id=group_id, semester=user.semester)
if group.users.count() < MAX_GROUP_SIZE:
user.group = group
user.save()
resp.resolve(group)
group = BMGTGroup.objects.get(id=group_id)
if user.role == BMGTUser.BMGTUserRole.USER and user.semester_id != group.semester_id:
resp.reject("You cannot join a group in another semester!")
else:
resp.reject("Group already full!")
if group.users.count() >= MAX_GROUP_SIZE:
resp.reject("Group already full!")
elif group.is_frozen:
resp.reject("Cannot join the group at this time!")
else:
user.group = group
user.save()
resp.resolve(group)
else:
resp.reject("Cannot join another group while you are alreay in a group!")
except BMGTGroup.DoesNotExist:
Expand All @@ -222,9 +225,12 @@ def leave_group(request: HttpRequest) -> HttpResponse:
resp = AppResponse()
user: BMGTUser = _get_session_user(request)
if user.group != None:
user.group = None
user.save()
resp.resolve("Group left!")
if user.group.is_frozen:
resp.reject("Cannot leave the group at this time!")
else:
user.group = None
user.save()
resp.resolve("Group left!")
else:
resp.reject("You are not in a group!")
except BMGTUser.DoesNotExist:
Expand Down Expand Up @@ -275,7 +281,7 @@ def submit(request: HttpRequest) -> HttpResponse:
case_record = None # place holder
user = _get_session_user(request)
data = json.loads(request.body)
case_id = int(data.get('case_id'))
case_id = int(data['case_id'])
case_instance = BMGTCase.objects.get(id=case_id)
if user.group != None:
group = user.group
Expand All @@ -284,6 +290,10 @@ def submit(request: HttpRequest) -> HttpResponse:
match case_id:
case 1: # food center
params = data.get('case_params')
configQuery = BMGTCaseConfig.objects.filter(case_id=case_id,)
if configQuery.exists():
config = json.loads(configQuery.get().config_json)
params['config'] = config
simulation_instance = FoodDelivery(**params)
case _:
resp.reject("Case not found!")
Expand Down Expand Up @@ -446,28 +456,28 @@ def import_users(request: HttpRequest, semester_id) -> HttpResponse:
@request_error_handler
@require_POST
@staticmethod
def config_case(request: HttpRequest) -> HttpResponse:
def update_food_delivery_config(request: HttpRequest) -> HttpResponse:
try:
resp = AppResponse()
data = json.loads(request.body)
case_id = data.get('case_id', None)
semester_id = data.get('semester_id', None)
query = BMGTCaseConfig.objects.filter(case_id=case_id, semester_id=semester_id)
semester_id = data['semester_id']
case_id = FOOD_DELIVERY_CASE_ID
query = BMGTCaseConfig.objects.filter(case_id=case_id, )
if query.exists():
config = query.get()
else:
config = BMGTCaseConfig(case_id=case_id, semester_id=semester_id)

match case_id:
case 1:
# food delivery
params = data.get('case_params')

config.config_json = json.dumps(params)
with transaction.atomic():
config = BMGTCaseConfig(case_id=case_id,)
config.save()
resp.resolve("Case configured!")
case _:
raise BMGTCase.DoesNotExist

params = dict(data['config'])
if FoodDelivery.is_config_valid(params):
config.config_json = json.dumps(params)
config.edited_time = timezone.now()
config.save()
resp.resolve("Case configured!")
else:
resp.reject("Invalid case configuration!")

except BMGTCase.DoesNotExist:
resp.reject("Case not found!")
Expand All @@ -477,8 +487,15 @@ def config_case(request: HttpRequest) -> HttpResponse:
return resp


def view_case(request: HttpRequest) -> HttpResponse:
pass
@request_error_handler
@require_GET
@staticmethod
def view_food_delivery_config(request: HttpRequest) -> HttpResponse:
pager_params = pager_params_from_request(request)
pager_params['case_id'] = FOOD_DELIVERY_CASE_ID
return generic_paginated_query(BMGTCaseConfig, pager_params)



@request_error_handler
@require_GET
Expand All @@ -489,24 +506,32 @@ def view_users(request: HttpRequest) -> HttpResponse:
@request_error_handler
@require_GET
@staticmethod
def system_status(request: HttpRequest) -> HttpResponse:
resp = AppResponse()

count_users = BMGTUser.objects.count()
count_active_users = BMGTUser.objects.filter(activated=True).count()
count_groups = BMGTGroup.objects.count()
count_cases = BMGTCase.objects.count()
count_case_records = BMGTCaseRecord.objects.count()
count_case_records_success = BMGTCaseRecord.objects.filter(state=BMGTCaseRecord.State.SUCCESS).count()

resp.resolve({
"count_users": count_users,
"count_activated_users": count_active_users,
"count_groups": count_groups,
"count_cases": count_cases,
"count_case_records": count_case_records,
"count_case_records_success": count_case_records_success,
})
def view_system_state(request: HttpRequest) -> HttpResponse:
try:
resp = AppResponse()
status = BMGTSystemStatus.objects.get(id=1)
resp.resolve(status)
except BMGTSystemStatus.DoesNotExist:
resp.reject("System not found!")

return resp

@request_error_handler
@require_POST
@staticmethod
def update_system_state(request: HttpRequest) -> HttpResponse:
try:
resp = AppResponse()
data = json.loads(request.body)
system = BMGTSystemStatus.objects.get(id=1)
for key, value in data.items():
system.__setattr__(key, value)
system.save()
resp.resolve("System updated!")
except BMGTSystemStatus.DoesNotExist:
resp.reject("System not found!")
except KeyError:
resp.reject("Invalid data format!")

return resp

Expand Down Expand Up @@ -541,14 +566,17 @@ def delete_semesters(request: HttpRequest) -> HttpResponse:
try:
resp = AppResponse()
data = json.loads(request.body)
arr_semester_id = data.get('semester_id', None)
arr_semester_id = data['arr_semester_id']
semester = BMGTSemester.objects.filter(id__in=arr_semester_id)
semester.delete()
resp.resolve("Semester deleted!")
except BMGTSemester.DoesNotExist:
resp.reject("Semester not found!")
except KeyError:
resp.reject("Invalid data format!")
except IntegrityError:
resp.reject("Semester cannot be deleted. Please delete all the users and groups in the semester first!")

return resp

@request_error_handler
Expand All @@ -568,12 +596,12 @@ def get_semesters(request: HttpRequest) -> HttpResponse:
@request_error_handler
@require_POST
@staticmethod
def batch_create_group(request: HttpRequest) -> HttpResponse:
def create_group(request: HttpRequest) -> HttpResponse:
try:
resp = AppResponse()
data = json.loads(request.body)
semester_id = data.get('semester_id', None)
size = int(data.get('size'))
semester_id = data['semester_id']
size = int(data['size'])
semester = BMGTSemester.objects.get(id=semester_id)
max_group_num = BMGTGroup.objects.aggregate(max_value=Max('number'))['max_value'] or 0
BMGTGroup.objects.bulk_create(
Expand Down Expand Up @@ -602,7 +630,7 @@ def delete_group(request: HttpRequest) -> HttpResponse:
try:
resp = AppResponse()
data = json.loads(request.body)
arr_group_id = data.get('group_id', None)
arr_group_id = data.get('arr_group_id', None)
with transaction.atomic():
groups = BMGTGroup.objects.filter(id__in=arr_group_id)
groups.delete()
Expand Down
19 changes: 16 additions & 3 deletions bmgt435_elp/bmgtModels.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ def as_dictionary(self) -> dict:

class BMGTGroup(BMGTModelBase):

is_frozen = models.BooleanField(default=False, null=False) # if true, no user can join this group
number = models.IntegerField(null=False, unique=False) # group number
semester = models.ForeignKey(BMGTSemester, on_delete=models.CASCADE, null=False)
semester = models.ForeignKey(BMGTSemester, on_delete=models.RESTRICT, null=False)

@property
def users(self) -> QuerySet:
Expand All @@ -91,6 +92,7 @@ def as_dictionary(self) -> dict:
return {
"id": self.id,
"name": self.name,
"is_frozen": self.is_frozen,
"users": [user.as_dictionary() for user in self.users],
"semester_id": self.semester.id if self.semester else None,
"semester_name": self.semester.name if self.semester else None,
Expand Down Expand Up @@ -129,6 +131,7 @@ def as_dictionary(self) -> dict:
id=self.id,
create_time=self.formatted_create_time,
did=self.did,
activated = self.activated,
first_name=self.first_name,
last_name=self.last_name,
role=self.role,
Expand All @@ -147,13 +150,14 @@ class BMGTCase(BMGTModelBase):
visible = models.BooleanField(default=True, null=False)
max_submission = models.IntegerField(default=5, null=False, unique=False)

def as_dictionary(self) -> dict:
def as_dictionary(self,) -> dict:
return dict(
id=self.id,
create_time=self.formatted_create_time,
name=self.name,
)


class BMGTCaseConfig(BMGTModelBase):

class Meta:
Expand All @@ -165,11 +169,13 @@ class Meta:
case = models.ForeignKey(BMGTCase, on_delete=models.CASCADE, null=False)
semester = models.ForeignKey(BMGTSemester, on_delete=models.CASCADE, null=False)
config_json = BMGTJsonField(null=False, default="", unique=False) # editable configuration regarding a case
edited_time = models.DateTimeField(auto_created=True, default=timezone.now, null=False)

def as_dictionary(self) -> dict:
return dict(
id=self.id,
create_time=self.formatted_create_time,
edited_time=timezone.make_naive(self.edited_time).isoformat(sep=' ', timespec='seconds'),
case_id=self.case.id if self.case else None,
case_name=self.case.name if self.case else None,
semester_id=self.semester.id if self.semester else None,
Expand Down Expand Up @@ -271,4 +277,11 @@ def as_dictionary(self) -> dict:
user_id=self.user.id,
user_name=self.user.name,
content=self.content,
)
)


class BMGTSystemStatus(BMGTModelBase):

allow_join_group = models.BooleanField(default=True, null=False)
allow_user_login = models.BooleanField(default=True, null=False)
allow_case_submit = models.BooleanField(default=True, null=False)
19 changes: 19 additions & 0 deletions bmgt435_elp/migrations/0002_bmgtcaseconfig_edited_time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.1 on 2023-11-27 22:56

from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):

dependencies = [
('bmgt435_elp', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='bmgtcaseconfig',
name='edited_time',
field=models.DateTimeField(auto_created=True, default=django.utils.timezone.now),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 4.2.1 on 2023-11-28 18:08

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


class Migration(migrations.Migration):

dependencies = [
('bmgt435_elp', '0002_bmgtcaseconfig_edited_time'),
]

operations = [
migrations.CreateModel(
name='BMGTSystemStatus',
fields=[
('create_time', models.DateTimeField(auto_created=True, default=django.utils.timezone.now)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
('allow_join_group', models.BooleanField(default=True)),
('allow_user_login', models.BooleanField(default=True)),
('allow_case_submit', models.BooleanField(default=True)),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='bmgtgroup',
name='is_frozen',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='bmgtgroup',
name='semester',
field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='bmgt435_elp.bmgtsemester'),
),
]
Loading

0 comments on commit aea1770

Please sign in to comment.