From e611c747a1271b9af079edfcbfaebff119d77b82 Mon Sep 17 00:00:00 2001 From: Chacoon3 Date: Tue, 28 Nov 2023 16:11:43 -0500 Subject: [PATCH] upd --- Dockerfile | 3 +- bmgt435_elp/admin.py | 6 +- bmgt435_elp/apis.py | 18 ++-- bmgt435_elp/bmgtModels.py | 5 +- ...tcaseconfig_unique_case_config_and_more.py | 25 ++++++ bmgt435_elp/simulation/FoodDelivery.py | 4 +- bmgt435_elp/test.py | 82 +++++++++++++++++- bmgt435_elp/utils/apiUtils.py | 6 +- db.sqlite3 | Bin 241664 -> 245760 bytes .../__pycache__/settings.cpython-310.pyc | Bin 3025 -> 3090 bytes sim_server_django/settings.py | 2 + 11 files changed, 129 insertions(+), 22 deletions(-) create mode 100644 bmgt435_elp/migrations/0004_remove_bmgtcaseconfig_unique_case_config_and_more.py diff --git a/Dockerfile b/Dockerfile index 0c8b000..174e70e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,5 +33,6 @@ EXPOSE 8000 # CMD python manage.py makemigrations && python manage.py migrate && gunicorn -b 0.0.0.0:8000 sim_server_django.wsgi:application CMD python manage.py makemigrations bmgt435_elp && \ python manage.py migrate && \ - daphne -b 0.0.0.0 -p 8000 sim_server_django.asgi:application + # daphne -b 0.0.0.0 -p 8000 sim_server_django.asgi:application + gunicorn -b 0.0.0.0:8000 sim_server_django.wsgi:application -w 4 # CMD python manage.py makemigrations && python manage.py migrate && python manage.py runserver diff --git a/bmgt435_elp/admin.py b/bmgt435_elp/admin.py index 4821f45..3516c57 100644 --- a/bmgt435_elp/admin.py +++ b/bmgt435_elp/admin.py @@ -13,7 +13,7 @@ class BMGTUserAdmin(admin.ModelAdmin): class CaseAdmin(admin.ModelAdmin): fieldsets = [ - ("None", {"fields": ["name", "max_submission",]}), + ("None", {"fields": ["id", "name", "max_submission",]}), ] list_display = ["id", "name", "create_time", "max_submission", "visible",] @@ -29,10 +29,10 @@ class CaseRecordAdmin(admin.ModelAdmin): class CaseConfigAdmin(admin.ModelAdmin): fieldsets = [ - ("None", {"fields": ["case_id", "semester_id", "create_time", "edited_time", "config_json",]}), + ("None", {"fields": ["case_id", "create_time", "edited_time", "config_json",]}), ] - list_display = ["id", "case_id", "semester_id", "create_time", "edited_time", "config_json",] + list_display = ["id", "case_id", "create_time", "edited_time", "config_json",] class GroupAdmin(admin.ModelAdmin): diff --git a/bmgt435_elp/apis.py b/bmgt435_elp/apis.py index b4f3344..85a8c46 100644 --- a/bmgt435_elp/apis.py +++ b/bmgt435_elp/apis.py @@ -8,7 +8,6 @@ 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 @@ -37,9 +36,14 @@ def _get_session_user(request: HttpRequest) -> BMGTUser: class AuthApi: + MAX_AGE_REMEMBER = 60 * 60 * 24 * 7 # 7 days + @staticmethod - def __set_auth_cookie(response: HttpResponse, user: BMGTUser) -> None: - response.set_cookie('id', str(user.id), samesite='strict', secure=True, httponly=True) + def __set_auth_cookie(response: HttpResponse, user: BMGTUser, remember: bool) -> None: + if remember: + response.set_cookie('id', str(user.id), samesite='strict', secure=True, httponly=True, max_age=AuthApi.MAX_AGE_REMEMBER) + else: + response.set_cookie('id', str(user.id), samesite='strict', secure=True, httponly=True) @staticmethod def __clear_auth_cookie(response: HttpResponse) -> None: @@ -54,9 +58,10 @@ def sign_in(request: HttpRequest) -> AppResponse: data = json.loads(request.body) did = data['did'] password = data['password'] + remember = data['remember'] user = BMGTUser.objects.get(did=did, activated=True,) if check_password(password, user.password): - AuthApi.__set_auth_cookie(resp, user) + AuthApi.__set_auth_cookie(resp, user, remember) resp.resolve(user) else: resp.reject("Sign in failed. Please check your directory ID and password!") @@ -289,7 +294,7 @@ def submit(request: HttpRequest) -> HttpResponse: # id to simulation case mapping match case_id: case 1: # food center - params = data.get('case_params') + params = data['case_params'] configQuery = BMGTCaseConfig.objects.filter(case_id=case_id,) if configQuery.exists(): config = json.loads(configQuery.get().config_json) @@ -460,7 +465,6 @@ def update_food_delivery_config(request: HttpRequest) -> HttpResponse: try: resp = AppResponse() data = json.loads(request.body) - semester_id = data['semester_id'] case_id = FOOD_DELIVERY_CASE_ID query = BMGTCaseConfig.objects.filter(case_id=case_id, ) if query.exists(): @@ -495,8 +499,6 @@ def view_food_delivery_config(request: HttpRequest) -> HttpResponse: pager_params['case_id'] = FOOD_DELIVERY_CASE_ID return generic_paginated_query(BMGTCaseConfig, pager_params) - - @request_error_handler @require_GET @staticmethod diff --git a/bmgt435_elp/bmgtModels.py b/bmgt435_elp/bmgtModels.py index 3358571..aac248c 100644 --- a/bmgt435_elp/bmgtModels.py +++ b/bmgt435_elp/bmgtModels.py @@ -163,11 +163,10 @@ class BMGTCaseConfig(BMGTModelBase): class Meta: app_label = APP_LABEL constraints = [ - models.UniqueConstraint(fields=('case_id', 'semester_id'), name='unique_case_config'), + models.UniqueConstraint(fields=('case_id',), name='unique_case_config'), ] 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) @@ -178,8 +177,6 @@ def as_dictionary(self) -> dict: 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, - semester_name=self.semester.name if self.semester else None, config_json=self.config_json, ) diff --git a/bmgt435_elp/migrations/0004_remove_bmgtcaseconfig_unique_case_config_and_more.py b/bmgt435_elp/migrations/0004_remove_bmgtcaseconfig_unique_case_config_and_more.py new file mode 100644 index 0000000..3c0ab7f --- /dev/null +++ b/bmgt435_elp/migrations/0004_remove_bmgtcaseconfig_unique_case_config_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.1 on 2023-11-28 20:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bmgt435_elp', '0003_bmgtsystemstatus_bmgtgroup_is_frozen_and_more'), + ] + + operations = [ + migrations.RemoveConstraint( + model_name='bmgtcaseconfig', + name='unique_case_config', + ), + migrations.RemoveField( + model_name='bmgtcaseconfig', + name='semester', + ), + migrations.AddConstraint( + model_name='bmgtcaseconfig', + constraint=models.UniqueConstraint(fields=('case_id',), name='unique_case_config'), + ), + ] diff --git a/bmgt435_elp/simulation/FoodDelivery.py b/bmgt435_elp/simulation/FoodDelivery.py index b766b85..754dfdd 100644 --- a/bmgt435_elp/simulation/FoodDelivery.py +++ b/bmgt435_elp/simulation/FoodDelivery.py @@ -358,13 +358,13 @@ def run(self): ] for centerwise_df, c_name in zip(arr_df_per_center_statistics, history.keys()): # add center name and week index columns - centerwise_df['center'] = c_name + centerwise_df['hub'] = c_name centerwise_df['week'] = range(1, FoodDelivery.__num_weeks + 1) df_per_center_statistics = pd.concat(arr_df_per_center_statistics, axis=0) if self.__config is not None: - df_per_center_statistics['center'] = df_per_center_statistics['center'].map( + df_per_center_statistics['hub'] = df_per_center_statistics['hub'].map( {v: k for k, v in self.__config.items()} ) diff --git a/bmgt435_elp/test.py b/bmgt435_elp/test.py index 51d3c71..d8b2ae7 100644 --- a/bmgt435_elp/test.py +++ b/bmgt435_elp/test.py @@ -26,10 +26,10 @@ def _signUp(did:str, password:str): return resp -def _signIn(did:str, password:str): +def _signIn(did:str, password:str, remember:bool = False): req = RequestFactory().post( '/bmgt435-service/api/auth/sign-in', - json.dumps({'did':did, 'password':password}), + json.dumps({'did':did, 'password':password, 'remember':remember}), 'application/json' ) resp = AuthApi.sign_in(req) @@ -492,4 +492,80 @@ def testCreateSemesterNegative(self): c.cookies = SimpleCookie(negCookies) resp = c.post('/bmgt435-service/api/manage/semester/create', json.dumps({'year':2021, 'season':'fall'}), content_type='application/json') self.assertRejected(resp) - self.assertEqual(BMGTSemester.objects.count(), 1) \ No newline at end of file + self.assertEqual(BMGTSemester.objects.count(), 1) + + +def testFoodDeliveryConfigPositive(self): + config= { + 'config_json':[ + [1, 2], + [2, 1], + [3, 4], + [4, 3], + [5, 6], + [6, 5], + ] + } + c = Client() + c.cookies = SimpleCookie({'id':1}) + resp = c.post('api/manage/food-delivery-config/update', json.dumps(config), content_type='application/json') + self.assertResolved(resp) + + +def testFoodDeliveryConfigNegative(self): + config= { + 'config_json':[ + [1, 2], + [2, 1], + [3, 4], + [4, 3], + [5, 6], + [6, 5], + ] + } + c = Client() + c.cookies = SimpleCookie({'id':2}) + resp = c.post('api/manage/food-delivery-config/update', json.dumps(config), content_type='application/json') + self.assertRejected(resp) + + c.cookies = SimpleCookie({'id':-1}) + resp = c.post('api/manage/food-delivery-config/update', json.dumps(config), content_type='application/json') + self.assertRejected(resp) + + badConfig = { + 'config_json':[ + [1, 2], + [2, 1], + [3, 4], + [4, 3], + [5, 6], + [6, 5], + [7, 8], + ] + } + + c.cookies = SimpleCookie({'id':1}) + resp = c.post('api/manage/food-delivery-config/update', json.dumps(badConfig), content_type='application/json') + self.assertRejected(resp) + + badConfig2 = { + 'config_json':[ + [1, 2], + [2, 1], + [3, 4], + [4, 3], + [5, 6], + [6, 1], + ] + } + resp = c.post('api/manage/food-delivery-config/update', json.dumps(badConfig2), content_type='application/json') + self.assertRejected(resp) + + +def testCaseConfigIntegrity(self): + try: + BMGTCaseConfig(case_id=1).save() + BMGTCaseConfig(case_id=1).save() + self.fail() + except IntegrityError: + return \ No newline at end of file diff --git a/bmgt435_elp/utils/apiUtils.py b/bmgt435_elp/utils/apiUtils.py index d6ec8e6..647d976 100644 --- a/bmgt435_elp/utils/apiUtils.py +++ b/bmgt435_elp/utils/apiUtils.py @@ -1,5 +1,5 @@ from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError -from django.db import IntegrityError +from django.db import IntegrityError, OperationalError from django.core.paginator import Paginator, EmptyPage from django.http import HttpRequest, HttpResponse from http import HTTPStatus @@ -62,6 +62,10 @@ def wrapped(request, *args, **kwargs) -> HttpResponse: except ValueError as e: resp = AppResponse() resp.reject(e.args[0]) + + except OperationalError as e: + resp = AppResponse() + resp.reject(e.args[0]) except Exception as e: # resp = HttpResponse() diff --git a/db.sqlite3 b/db.sqlite3 index 40f0a4539317072b9f3f509ebcbccf5a3af251cc..98d2c1db55fcc7bf2f5c5f3b3bf2401f7aa24c63 100644 GIT binary patch delta 1132 zcmbVLPi)&%9DaXdJ5CzEcqpx`|0`n zK0o_?e!uE{sahpVZSoEP;1GkwfEZRj>@ncZX6_2X3GQA^i1#DzUVSjW#1(Q04s@Qe z3u7Y{(?~h)XjxTN)0uF`#!tIWKo8|7-J$W)aB;+$Dize2#QZL%{~N$BBP`uVH14 zOtR0?P2Hrc^Z4axI?NH0AbG+n$dV^i%Aq!RwKf=EJb2Is z;g}(!-3#m4l$uQUr8BCk8JZIeRm-GwH90dnIRnmnb8-4>0k!)=9zB!@Tev44VO5qq zAbEbcjHV^}=^Tnh8&AnTBTi|4D2JYsPpXLb`7N~5i)FG-h3l}BZFPar^&im*MqTrEcS!Lz((N!QH(4NPec zLSh$W$S?$(iqz%mFNB0bqA11!jf4RS`;jHQBaL`daunEtxG?$eF}`-}_V&*?`-8LH zWp`rO8FMQW#i8!3!tzOJW?wR`^(fty@k)M_oyOB{Y070{O4m(I3q(3Ngj#9tB(gYN z(^ZRZ7TEnp2}RX^`aiMAHV6yLfNV%#iI>BJ!g8#m>28zUWN_cGPFUfZBir!%mcxhP zVs|B97s8VcQe6+fbtYgj}3 z_xsB$SjQ|(Xt$iQp;x4zuVIBgUd6+E`1g1gDgfRaXM|niJoYkk^lKL?w7Q0Qy0wOD z+&R8w#HJlZ_yR4j<8<`U`8~5ji*3UTy>xROTg>d`U@P4|fkHL4H`4eJ|I2Im2)wbh VNa*4`evYu#{m&L^4`D2de*h$NI<)`* delta 1636 zcmbW%%TE(Q90%~(neAiSGP6}4(gNKUd?Z3?yU@}aF~mPWK#d`4z!;3iAVf4=4BPdA z@djyd#6uxLX=0*)jW)(axv25xm6#xUBbspW1S#Uu=r<1InIp`9N)3dhO z|GQu<3{t6#EbomkJ0i zH_Toj9}1A1r~&cVP*j7sWhi_g&TSUjmi2mp9NA2^2n9r?q3|F?Rt-fJi1~j)EA+=# z0?8EYBn+>n0>r4HaD(VK6fO-&n;|I&QEw>rfG9E)Ww4*V?B%ACT$t6jO&Niq^DpGWs7afXTlo#!a zZpnMrr0C|nC@Q)s7n8Yh#Jro>qZ5dd#9=%3- zN~uu`$yPMRCm1pFr;MC}@-(-|q>8*@-{9U|mYMdDldWcf4IwrJl^cu?y(J|q*c1yz zV`|vn7;R7^P5jB4aL}&$Y89XAiz&V^UtAMv;IUQ2R@2V-GJ{tqijpM3F`NAf2u|8z z@`on6xwbfV-_bfXkf^r93~1f!Hv^rMth*%zoRWLTiOkRioDoFPgrm8)nu&}_q0wPs!> zpz%gg>M6#-44NjJ%NRvjMMXl3GxO3Fd@F+keH2m>OA?b3i&H0ev6+Zhi9)1+5}75b paJkL<*!o!*TPFK)dkV4q=i*~xW@2PxWckPPpM#BsWAajN9RS(eMi>A9 delta 198 zcmbOvaZ#K%pO=@50SH#S_fD;t$Scd}Hc@*SWBSBP8ufXcDdH)zsq86o(hMo`bC@z2 zqoh+5QWP^8QKrDZh#HWkkfNT+n9dR z6Q!6U7^Re=8>O7ezCdLm!vfWX3@Liz3{h&STt)L!xl{C0)tZ?Y8Bz?Q)Kd(D88nSv vGB9lJWE5hZyphd#^KZ6(7RH9j-Q1phZ2y@Am>Ag@S^ly7XW^avj9Ui)hdniJ diff --git a/sim_server_django/settings.py b/sim_server_django/settings.py index 0b8fde3..a38e090 100644 --- a/sim_server_django/settings.py +++ b/sim_server_django/settings.py @@ -87,6 +87,7 @@ }, }, } + print('Using MySQL database') else: DATABASES = { 'default': { @@ -94,6 +95,7 @@ 'NAME': BASE_DIR / 'db.sqlite3', } } + print('Using SQLite database') # Password validation