From 3c285dbd2dfea56c27a93a0240c28f93597ffb5c Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 13 Nov 2023 16:47:39 +0700 Subject: [PATCH 01/61] MOD-59 Improved GradingResult + RuntimeResult --- api/sandbox/grader.py | 85 +++++++++++++++++------------------------ api/views/problem.py | 24 ++++++++---- api/views/submission.py | 20 ++++------ 3 files changed, 59 insertions(+), 70 deletions(-) diff --git a/api/sandbox/grader.py b/api/sandbox/grader.py index c46c5f3..8f5d55d 100644 --- a/api/sandbox/grader.py +++ b/api/sandbox/grader.py @@ -1,52 +1,17 @@ import subprocess +""" +Usecases: +- Create problem +- Update code +- Update testcases +- Submit problem +""" + def forgiveableFormat(string:str)->str: return string.replace('\r','') # return string -# def checker(section:int,code:str,testcases:list,timeout=1.5)->dict: -# result = [] -# hasError = False -# hasTimeout = False -# for i in range(len(testcases)): -# with open(f'./api/sandbox/section{section}/testcases/{i}.txt','w') as f: -# f.write(testcases[i]) - -# with open(f'./api/sandbox/section{section}/runner.py','w') as f: -# f.write(code) - -# for i in range(len(testcases)): -# try: -# runner = subprocess.check_output(['python',f'./api/sandbox/section{section}/runner.py'],stdin=open(f'./api/sandbox/section{section}/testcases/{i}.txt','r'),stderr=subprocess.DEVNULL,timeout=float(timeout)) -# result.append({'input':testcases[i],'output':runner.decode(),'runtime_status':'OK'}) -# except subprocess.CalledProcessError: -# hasError = True -# result.append({'input':testcases[i],'output':None,'runtime_status':'ERROR'}) -# except subprocess.TimeoutExpired: -# hasTimeout = True -# result.append({'input':testcases[i],'output':None,'runtime_status':'TIMEOUT'}) - -# return {'result':result,'has_error':hasError,'has_timeout':hasTimeout} - -# def grading(section:int,code:str,input:list,output:list,timeout=1.5)->str: -# score = '' -# graded = checker(section,code,input,timeout) -# graded_result = graded['result'] - -# for i in range(len(output)): -# if graded_result[i]['runtime_status'] == 'OK': -# if forgiveableFormat(graded_result[i]['output']) == forgiveableFormat(output[i]): -# score += 'P' -# else: -# score += '-' -# elif graded_result[i]['runtime_status'] == 'TIMEOUT': -# score += 'T' -# else: -# score += 'E' - -# return score - - class RuntimeResult: RUNTIME_STATUS = [ @@ -87,6 +52,28 @@ def __str__(self) -> str: return str(dict(self)) +class RuntimeResultList: + def __init__(self,runtimeResult:list[RuntimeResult]) -> None: + self.data = runtimeResult + self.has_error = len([res for res in runtimeResult if res.runtime_status == "ERROR"]) > 0 + self.has_timeout = len([res for res in runtimeResult if res.runtime_status == "TIMEOUT"]) > 0 + self.runnable = not (self.has_error or self.has_timeout) + + def getResult(self) -> list[dict]: + return [dict(i) for i in self.data] + +class GradingResultList: + def __init__(self,gradingResult:list[GradingResult]) -> None: + self.data = gradingResult + self.has_error = len([res for res in gradingResult if res.runtime_status == "ERROR"]) > 0 + self.has_timeout = len([res for res in gradingResult if res.runtime_status == "TIMEOUT"]) > 0 + self.runnable = not (self.has_error or self.has_timeout) + self.is_passed = len([res for res in gradingResult if res.is_passed]) == len(gradingResult) + + def getResult(self) -> list[dict]: + return [dict(i) for i in self.data] + + class ProgramGrader: def __init__(self,code:str,testcases:list[str],section:int,timeout:float) -> None: self.code = code @@ -112,12 +99,12 @@ def compile(self) -> None: def runtime(self) -> list[RuntimeResult]: pass - def generate_output(self) -> list[RuntimeResult]: + def generate_output(self) -> RuntimeResultList: self.setup() self.compile() - return self.runtime() + return RuntimeResultList(self.runtime()) - def grading(self,expected_output:list[str]) -> list[GradingResult]: + def grading(self,expected_output:list[str]) -> GradingResultList: self.setup() self.compile() runtime_result = self.runtime() @@ -134,6 +121,7 @@ def grading(self,expected_output:list[str]) -> list[GradingResult]: if runtime_result[i].runtime_status == "OK": output = runtime_result[i].output + print({"act":runtime_result[i].output,"exp":expected_output[i]}) if forgiveableFormat(runtime_result[i].output) == forgiveableFormat(expected_output[i]): is_passed = True @@ -145,8 +133,7 @@ def grading(self,expected_output:list[str]) -> list[GradingResult]: is_passed )) - return grading_result - + return GradingResultList(grading_result) class PythonGrader(ProgramGrader): @@ -283,4 +270,4 @@ def runtime(self) -> list[RuntimeResult]: grader = Grader['python'] result = grader(adder,test,1,1.5).grading(pyresult) -print(result) \ No newline at end of file +print(result.getResult()) \ No newline at end of file diff --git a/api/views/problem.py b/api/views/problem.py index 382ca88..257b724 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -13,10 +13,11 @@ def create_problem(request,account_id): account = Account.objects.get(account_id=account_id) - program_output = PythonGrader(request.data['solution'],request.data['testcases'],1,1.5).generate_output() - for result in program_output: - if result.runtime_status != "OK": - return Response({'detail': 'Error during creating. Your code may has an error/timeout!','output': [dict(i) for i in program_output]},status=status.HTTP_406_NOT_ACCEPTABLE) + running_result = PythonGrader(request.data['solution'],request.data['testcases'],1,1.5).generate_output() + print(running_result.has_error,running_result.has_timeout,running_result.runnable) + + if not running_result.runnable: + return Response({'detail': 'Error during creating. Your code may has an error/timeout!','output': running_result.getResult()},status=status.HTTP_406_NOT_ACCEPTABLE) problem = Problem( language = request.data['language'], @@ -29,7 +30,7 @@ def create_problem(request,account_id): problem.save() testcases_result = [] - for unit in program_output: + for unit in running_result.data: testcases_result.append( Testcase( problem = problem, @@ -100,14 +101,14 @@ def one_problem(request,problem_id: int): problem.is_private = request.data.get("is_private",problem.is_private) if 'testcases' in request.data: - program_output = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() + running_result = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() - if sum([1 for i in program_output if i.runtime_status != "OK"]) > 0: + if not running_result.runnable: return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) testcases.delete() testcase_result = [] - for unit in program_output: + for unit in running_result.data: testcase = Testcase( problem = problem, input = unit.input, @@ -121,6 +122,13 @@ def one_problem(request,problem_id: int): testcases_serialize = TestcaseSerializer(testcase_result,many=True) return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_201_CREATED) + + elif 'solution' in request.data: + program_input = [i.input for i in testcases] + running_result = PythonGrader(problem.solution,program_input,1,1.5).generate_output() + + if not running_result.runnable: + return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) problem.save() problem_serialize = ProblemSerializer(problem) diff --git a/api/views/submission.py b/api/views/submission.py index 576b745..b97ed94 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -43,20 +43,14 @@ def submit_problem(request,problem_id,account_id): grading_result = PythonGrader(submission_code,solution_input,empty_queue+1,1.5).grading(solution_output) QUEUE[empty_queue] = 0 - is_passed = True - for result in grading_result: - if not result.is_passed: - is_passed = False - break - - total_score = sum([i.is_passed for i in grading_result if i.is_passed]) - max_score = len(grading_result) + total_score = sum([i.is_passed for i in grading_result.data if i.is_passed]) + max_score = len(grading_result.data) submission = Submission( problem = problem, account = Account.objects.get(account_id=account_id), submission_code = request.data['submission_code'], - is_passed = is_passed, + is_passed = grading_result.is_passed, score = total_score, max_score = max_score, passed_ratio = total_score/max_score @@ -64,13 +58,13 @@ def submit_problem(request,problem_id,account_id): submission.save() submission_testcases = [] - for i in range(len(grading_result)): + for i in range(len(grading_result.data)): submission_testcases.append(SubmissionTestcase( submission = submission, testcase = testcases[i], - output = grading_result[i].output, - is_passed = grading_result[i].is_passed, - runtime_status = grading_result[i].runtime_status + output = grading_result.data[i].output, + is_passed = grading_result.data[i].is_passed, + runtime_status = grading_result.data[i].runtime_status )) SubmissionTestcase.objects.bulk_create(submission_testcases) From 6cc40a7c580672ada93da9e67fa3d427b8074795 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 13 Nov 2023 18:43:19 +0700 Subject: [PATCH 02/61] Removed print --- api/views/problem.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/views/problem.py b/api/views/problem.py index 257b724..6273076 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -14,7 +14,6 @@ def create_problem(request,account_id): account = Account.objects.get(account_id=account_id) running_result = PythonGrader(request.data['solution'],request.data['testcases'],1,1.5).generate_output() - print(running_result.has_error,running_result.has_timeout,running_result.runnable) if not running_result.runnable: return Response({'detail': 'Error during creating. Your code may has an error/timeout!','output': running_result.getResult()},status=status.HTTP_406_NOT_ACCEPTABLE) From dc7ce2f1f8c3908865ff2007b6ca435acd710252 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Fri, 24 Nov 2023 15:05:38 +0700 Subject: [PATCH 03/61] MOD-54,55: Removed is_admin and creator field --- .gitignore | 4 +- api/admin.py | 4 +- ..._admin_remove_collection_owner_and_more.py | 48 +++++++++++++++++++ api/models.py | 8 ++-- api/sandbox/grader.py | 2 +- api/views/auth.py | 6 +-- api/views/collection.py | 2 +- api/views/problem.py | 7 +-- api/views/topic.py | 4 +- 9 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py diff --git a/.gitignore b/.gitignore index cc669d7..6aebf24 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ __pycache__ api/sandbox/testcases/*.txt runner.py +@/* env/ .env @@ -20,5 +21,4 @@ media/resource tempCodeRunnerFile.py *.sqlite3 -*.exe - +*.exe \ No newline at end of file diff --git a/api/admin.py b/api/admin.py index a26be80..7edf398 100644 --- a/api/admin.py +++ b/api/admin.py @@ -16,8 +16,8 @@ class ProblemAdmin(admin.ModelAdmin): list_filter = ['language'] class AccountAdmin(admin.ModelAdmin): - list_display = ['account_id','username','email','is_admin','is_active'] - list_filter = ['is_admin','is_active'] + list_display = ['account_id','username','email','is_active'] + list_filter = ['is_active'] admin.site.register(Problem,ProblemAdmin) admin.site.register(Account,AccountAdmin) \ No newline at end of file diff --git a/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py b/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py new file mode 100644 index 0000000..94d36f3 --- /dev/null +++ b/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 4.1.2 on 2023-11-24 05:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0028_alter_problem_language'), + ] + + operations = [ + migrations.RemoveField( + model_name='account', + name='is_admin', + ), + migrations.RemoveField( + model_name='collection', + name='owner', + ), + migrations.RemoveField( + model_name='problem', + name='account', + ), + migrations.RemoveField( + model_name='topic', + name='account', + ), + migrations.AddField( + model_name='collection', + name='creator', + field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + preserve_default=False, + ), + migrations.AddField( + model_name='problem', + name='creator', + field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + preserve_default=False, + ), + migrations.AddField( + model_name='topic', + name='creator', + field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + preserve_default=False, + ), + ] diff --git a/api/models.py b/api/models.py index 7baa5b4..0bb1ab1 100644 --- a/api/models.py +++ b/api/models.py @@ -21,13 +21,13 @@ class Account(models.Model): password = models.CharField(max_length=128) token = models.CharField(max_length=256,null=True,default=None) token_expire = models.IntegerField(null=True,default=None) - is_admin = models.BooleanField(default=False) + # is_admin = models.BooleanField(default=False) is_active = models.BooleanField(default=True) is_private = models.BooleanField(default=True) class Problem(models.Model): problem_id = models.AutoField(primary_key=True) - account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") + creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") language = models.CharField(max_length=15) # ,choices=ProgrammingLanguage.choices,default=ProgrammingLanguage.PYTHON) title = models.CharField(max_length=50) description = models.CharField(max_length=10000) @@ -56,7 +56,7 @@ class Submission(models.Model): class Collection(models.Model): collection_id = models.AutoField(primary_key=True) - owner = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="owner_id") + creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) description = models.CharField(max_length=1000,null=True,blank=True,default=None) is_active = models.BooleanField(default=True,blank=True) @@ -64,7 +64,7 @@ class Collection(models.Model): class Topic(models.Model): topic_id = models.AutoField(primary_key=True) - account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") + creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) description = models.CharField(max_length=1000,null=True,blank=True,default=None) image_url = models.ImageField(upload_to='topic/',null=True,blank=True,default=None) diff --git a/api/sandbox/grader.py b/api/sandbox/grader.py index 8f5d55d..26be175 100644 --- a/api/sandbox/grader.py +++ b/api/sandbox/grader.py @@ -270,4 +270,4 @@ def runtime(self) -> list[RuntimeResult]: grader = Grader['python'] result = grader(adder,test,1,1.5).grading(pyresult) -print(result.getResult()) \ No newline at end of file +# print(result.getResult()) \ No newline at end of file diff --git a/api/views/auth.py b/api/views/auth.py index 150631d..ccb02c3 100644 --- a/api/views/auth.py +++ b/api/views/auth.py @@ -47,10 +47,10 @@ def get_authorization(request): account = Account.objects.get(account_id=request.data['account_id']) account_dict = model_to_dict(account) if account_dict['token_expire'] >= time() and account_dict['token'] == request.data['token']: - return Response({'result':True,'is_admin':account.is_admin},status=status.HTTP_200_OK) - return Response({'result':False,'is_admin':False},status=status.HTTP_200_OK) + return Response({'result':True},status=status.HTTP_200_OK) + return Response({'result':False},status=status.HTTP_200_OK) except Account.DoesNotExist: - return Response({'result':False,'is_admin':False},status=status.HTTP_200_OK) + return Response({'result':False},status=status.HTTP_200_OK) # return Response({'detail':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) # @api_view([GET]) diff --git a/api/views/collection.py b/api/views/collection.py index bac5146..521e81d 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -27,7 +27,7 @@ def all_collections(request): account_id = request.query_params.get('account_id',0) if account_id: - collections = collections.filter(owner_id=account_id) + collections = collections.filter(creator_id=account_id) populated_collections = [] for collection in collections: diff --git a/api/views/problem.py b/api/views/problem.py index 6273076..773a6fe 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -59,17 +59,12 @@ def all_problem(request): if not get_deactive: problem = problem.filter(is_active=True) if account_id != 0: - problem = problem.filter(account_id=account_id) + problem = problem.filter(creator_id=account_id) problem = problem.order_by('-problem_id') serialize = ProblemPopulateAccountSerializer(problem,many=True) - result = [model_to_dict(i) for i in problem] - - for i in result: - i['creator'] = model_to_dict(Account.objects.get(account_id=i['account'])) - return Response({'problems':serialize.data},status=status.HTTP_200_OK) elif request.method == DELETE: target = request.data.get("problem",[]) diff --git a/api/views/topic.py b/api/views/topic.py index 1d25201..69147ff 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -12,7 +12,7 @@ @parser_classes([MultiPartParser,FormParser]) def create_topic(request,account_id :int): request.data._mutable=True - request.data['account'] = account_id + request.data['creator'] = account_id serializer = TopicSerializer(data=request.data) if serializer.is_valid(): @@ -27,7 +27,7 @@ def all_topic(request): account_id = request.query_params.get('account_id',0) if account_id: - topics = topics.filter(account_id=account_id) + topics = topics.filter(creator_id=account_id) serializer = TopicSerializer(topics,many=True) From 34ec6a03a2023f09ead388417bb82d52ec7505e4 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Fri, 24 Nov 2023 15:23:39 +0700 Subject: [PATCH 04/61] MOD-56: Secure subission serializer --- api/serializers.py | 21 +++++++++++++++++++-- api/views/submission.py | 4 ++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/api/serializers.py b/api/serializers.py index 4f847b0..ce60c2f 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -44,7 +44,7 @@ class Meta: fields = "__all__" class ProblemPopulateAccountSerializer(serializers.ModelSerializer): - account = AccountSecureSerializer() + creator = AccountSecureSerializer() class Meta: model = Problem fields = "__all__" @@ -95,4 +95,21 @@ class Meta: class TestcaseSerializer(serializers.ModelSerializer): class Meta: model = Testcase - fields = "__all__" \ No newline at end of file + fields = "__all__" + +class ProblemPopulateAccountSecureSerializer(serializers.ModelSerializer): + creator = AccountSecureSerializer() + class Meta: + model = Problem + fields = ['problem_id','title','description','creator'] + +class SubmissionPoplulateProblemSecureSerializer(serializers.ModelSerializer): + problem = ProblemPopulateAccountSecureSerializer() + class Meta: + model = Submission + fields = "__all__" + +class SubmissionTestcaseSecureSerializer(serializers.ModelSerializer): + class Meta: + model = SubmissionTestcase + fields = ['is_passed','runtime_status'] \ No newline at end of file diff --git a/api/views/submission.py b/api/views/submission.py index b97ed94..31140b6 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -69,8 +69,8 @@ def submit_problem(request,problem_id,account_id): SubmissionTestcase.objects.bulk_create(submission_testcases) - submission_serialize = SubmissionPoplulateProblemSerializer(submission) - testcases_serialize = SubmissionTestcaseSerializer(submission_testcases,many=True) + submission_serialize = SubmissionPoplulateProblemSecureSerializer(submission) + testcases_serialize = SubmissionTestcaseSecureSerializer(submission_testcases,many=True) return Response({ **submission_serialize.data, From d5a1f92eba6f85943dcdd3da9dadf25130bf9fd9 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 25 Nov 2023 01:25:39 +0700 Subject: [PATCH 05/61] detail -> message --- api/views/auth.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/api/views/auth.py b/api/views/auth.py index ccb02c3..5d66bee 100644 --- a/api/views/auth.py +++ b/api/views/auth.py @@ -24,9 +24,9 @@ def login(request): account.save() return Response(model_to_dict(account),status=status.HTTP_202_ACCEPTED) else: - return Response({'detail':"Incorrect password!"},status=status.HTTP_406_NOT_ACCEPTABLE) + return Response({'message':"Incorrect password!"},status=status.HTTP_406_NOT_ACCEPTABLE) except Account.DoesNotExist: - return Response({'detail':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) + return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) @api_view([POST]) def logout(request): @@ -37,9 +37,9 @@ def logout(request): account.save() return Response(model_to_dict(account),status=status.HTTP_200_OK) else: - return Response({'detail':"Invalid token!"},status=status.HTTP_200_OK) + return Response({'message':"Invalid token!"},status=status.HTTP_200_OK) except Account.DoesNotExist: - return Response({'detail':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) + return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) @api_view([PUT]) def get_authorization(request): @@ -51,7 +51,7 @@ def get_authorization(request): return Response({'result':False},status=status.HTTP_200_OK) except Account.DoesNotExist: return Response({'result':False},status=status.HTTP_200_OK) - # return Response({'detail':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) + # return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) # @api_view([GET]) # def get_token(request): @@ -60,7 +60,7 @@ def get_authorization(request): # account_dict = model_to_dict(account) # if account_dict['token_expire'] < time(): -# return Response({'detail':"Login timeout!"},status=status.HTTP_200_OK) +# return Response({'message':"Login timeout!"},status=status.HTTP_200_OK) # elif account_dict['token'] == request.data['token'] # if passwordEncryption(request.data['password']) == account_dict['password']: @@ -69,6 +69,6 @@ def get_authorization(request): # account.save() # return Response(model_to_dict(account),status=status.HTTP_202_ACCEPTED) # else: -# return Response({'detail':"Incorrect password!"},status=status.HTTP_200_OK) +# return Response({'message':"Incorrect password!"},status=status.HTTP_200_OK) # except Account.DoesNotExist: -# return Response({'detail':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) \ No newline at end of file +# return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) \ No newline at end of file From 7722a96a6c52382ce7a9215c784c28b80483ced0 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 26 Nov 2023 17:35:17 +0700 Subject: [PATCH 06/61] Minor fixed --- Backend/settings.py | 2 ++ ...ove_account_is_admin_remove_collection_owner_and_more.py | 6 +++--- api/views/problem.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Backend/settings.py b/Backend/settings.py index e9cf8a6..3a7ee8e 100644 --- a/Backend/settings.py +++ b/Backend/settings.py @@ -40,6 +40,8 @@ CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", + "http://localhost:4000", + "http://localhost:5173", "http://localhost:3001", "http://192.168.216.250:3000", "http://192.168.0.2:3000", diff --git a/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py b/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py index 94d36f3..2638044 100644 --- a/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py +++ b/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py @@ -30,19 +30,19 @@ class Migration(migrations.Migration): migrations.AddField( model_name='collection', name='creator', - field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + field=models.ForeignKey(db_column='creator_id', default=1, on_delete=django.db.models.deletion.CASCADE, to='api.account'), preserve_default=False, ), migrations.AddField( model_name='problem', name='creator', - field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + field=models.ForeignKey(db_column='creator_id', default=1, on_delete=django.db.models.deletion.CASCADE, to='api.account'), preserve_default=False, ), migrations.AddField( model_name='topic', name='creator', - field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + field=models.ForeignKey(db_column='creator_id', default=1, on_delete=django.db.models.deletion.CASCADE, to='api.account'), preserve_default=False, ), ] diff --git a/api/views/problem.py b/api/views/problem.py index 773a6fe..d154a6b 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -20,7 +20,7 @@ def create_problem(request,account_id): problem = Problem( language = request.data['language'], - account = account, + creator = account, title = request.data['title'], description = request.data['description'], solution = request.data['solution'], From 11d7b8a0c45986014d70db3450480e10a1356c30 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 27 Nov 2023 19:24:50 +0700 Subject: [PATCH 07/61] Removed print --- api/sandbox/grader.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/sandbox/grader.py b/api/sandbox/grader.py index 26be175..b620c21 100644 --- a/api/sandbox/grader.py +++ b/api/sandbox/grader.py @@ -121,7 +121,6 @@ def grading(self,expected_output:list[str]) -> GradingResultList: if runtime_result[i].runtime_status == "OK": output = runtime_result[i].output - print({"act":runtime_result[i].output,"exp":expected_output[i]}) if forgiveableFormat(runtime_result[i].output) == forgiveableFormat(expected_output[i]): is_passed = True From bbf04e3393221e5d9b865be14fa59f4ffb098381 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Tue, 28 Nov 2023 14:54:53 +0700 Subject: [PATCH 08/61] Controller (Usecases) --- api/controllers/account/create_account.py | 18 +++++ api/controllers/account/get_account.py | 17 +++++ api/controllers/account/get_all_accounts.py | 16 ++++ api/controllers/auth/authorization.py | 21 +++++ api/controllers/auth/login.py | 29 +++++++ api/controllers/auth/logout.py | 24 ++++++ .../collection/add_problems_to_collection.py | 38 ++++++++++ .../collection/create_collection.py | 20 +++++ .../collection/delete_collection.py | 13 ++++ .../collection/get_all_collections.py | 37 +++++++++ api/controllers/collection/get_collection.py | 27 +++++++ .../remove_problems_from_collection.py | 13 ++++ .../collection/update_collection.py | 18 +++++ api/controllers/copypasta.py | 9 +++ api/controllers/problem/create_problem.py | 43 +++++++++++ api/controllers/problem/delete_problem.py | 20 +++++ api/controllers/problem/get_all_problems.py | 30 ++++++++ api/controllers/problem/get_problem.py | 20 +++++ .../problem/remove_bulk_problems.py | 16 ++++ api/controllers/problem/update_problem.py | 57 ++++++++++++++ .../submission/get_submission_by_quries.py | 45 +++++++++++ api/controllers/submission/submit_problem.py | 76 +++++++++++++++++++ .../topic/add_collections_to_topic.py | 36 +++++++++ api/controllers/topic/create_topic.py | 19 +++++ api/controllers/topic/delete_topic.py | 14 ++++ api/controllers/topic/get_all_topics.py | 23 ++++++ api/controllers/topic/get_topic.py | 40 ++++++++++ .../topic/remove_collections_from_topic.py | 16 ++++ api/controllers/topic/update_topic.py | 19 +++++ api/views/submission.py | 2 +- 30 files changed, 775 insertions(+), 1 deletion(-) create mode 100644 api/controllers/account/create_account.py create mode 100644 api/controllers/account/get_account.py create mode 100644 api/controllers/account/get_all_accounts.py create mode 100644 api/controllers/auth/authorization.py create mode 100644 api/controllers/auth/login.py create mode 100644 api/controllers/auth/logout.py create mode 100644 api/controllers/collection/add_problems_to_collection.py create mode 100644 api/controllers/collection/create_collection.py create mode 100644 api/controllers/collection/delete_collection.py create mode 100644 api/controllers/collection/get_all_collections.py create mode 100644 api/controllers/collection/get_collection.py create mode 100644 api/controllers/collection/remove_problems_from_collection.py create mode 100644 api/controllers/collection/update_collection.py create mode 100644 api/controllers/copypasta.py create mode 100644 api/controllers/problem/create_problem.py create mode 100644 api/controllers/problem/delete_problem.py create mode 100644 api/controllers/problem/get_all_problems.py create mode 100644 api/controllers/problem/get_problem.py create mode 100644 api/controllers/problem/remove_bulk_problems.py create mode 100644 api/controllers/problem/update_problem.py create mode 100644 api/controllers/submission/get_submission_by_quries.py create mode 100644 api/controllers/submission/submit_problem.py create mode 100644 api/controllers/topic/add_collections_to_topic.py create mode 100644 api/controllers/topic/create_topic.py create mode 100644 api/controllers/topic/delete_topic.py create mode 100644 api/controllers/topic/get_all_topics.py create mode 100644 api/controllers/topic/get_topic.py create mode 100644 api/controllers/topic/remove_collections_from_topic.py create mode 100644 api/controllers/topic/update_topic.py diff --git a/api/controllers/account/create_account.py b/api/controllers/account/create_account.py new file mode 100644 index 0000000..c35521c --- /dev/null +++ b/api/controllers/account/create_account.py @@ -0,0 +1,18 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def create_account(request): + request.data['password'] = passwordEncryption(request.data['password']) + try: + account = Account.objects.create(**request.data) + except Exception as e: + return Response({'message':str(e)},status=status.HTTP_400_BAD_REQUEST) + serialize = AccountSerializer(account) + return Response(serialize.data,status=status.HTTP_201_CREATED) diff --git a/api/controllers/account/get_account.py b/api/controllers/account/get_account.py new file mode 100644 index 0000000..68485ff --- /dev/null +++ b/api/controllers/account/get_account.py @@ -0,0 +1,17 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_account(account_id:int): + try: + account = Account.objects.get(account_id=account_id) + serialize = AccountSerializer(account) + return Response(serialize.data,status=status.HTTP_200_OK) + except: + return Response({'message':'Account not found!'},status=status.HTTP_404_NOT_FOUND) diff --git a/api/controllers/account/get_all_accounts.py b/api/controllers/account/get_all_accounts.py new file mode 100644 index 0000000..2b74578 --- /dev/null +++ b/api/controllers/account/get_all_accounts.py @@ -0,0 +1,16 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_accounts(): + accounts = Account.objects.all() + serialize = AccountSecureSerializer(accounts,many=True) + return Response({ + "accounts": serialize.data + },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/auth/authorization.py b/api/controllers/auth/authorization.py new file mode 100644 index 0000000..0434dae --- /dev/null +++ b/api/controllers/auth/authorization.py @@ -0,0 +1,21 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * +from time import time + +def authorization(request): + try: + account = Account.objects.get(account_id=request.data['account_id']) + account_dict = model_to_dict(account) + if account_dict['token_expire'] >= time() and account_dict['token'] == request.data['token']: + return Response({'result':True},status=status.HTTP_200_OK) + return Response({'result':False},status=status.HTTP_200_OK) + except Account.DoesNotExist: + return Response({'result':False},status=status.HTTP_200_OK) + # return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) diff --git a/api/controllers/auth/login.py b/api/controllers/auth/login.py new file mode 100644 index 0000000..502a855 --- /dev/null +++ b/api/controllers/auth/login.py @@ -0,0 +1,29 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * +from decouple import config +from uuid import uuid4 +from time import time + +TOKEN_LIFETIME = int(config('TOKEN_LIFETIME_SECOND')) # (Second) + +def login(request): + try: + account = Account.objects.get(username=request.data['username']) + account_dict = model_to_dict(account) + + if passwordEncryption(request.data['password']) == account_dict['password']: + account.token = uuid4().hex + account.token_expire = int(time()+TOKEN_LIFETIME) + account.save() + return Response(model_to_dict(account),status=status.HTTP_202_ACCEPTED) + else: + return Response({'message':"Incorrect password!"},status=status.HTTP_406_NOT_ACCEPTABLE) + except Account.DoesNotExist: + return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) diff --git a/api/controllers/auth/logout.py b/api/controllers/auth/logout.py new file mode 100644 index 0000000..9bbd0fa --- /dev/null +++ b/api/controllers/auth/logout.py @@ -0,0 +1,24 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * +from decouple import config +from uuid import uuid4 +from time import time + +def logout(request): + try: + account = Account.objects.get(account_id=request.data['account_id']) + if account.token == request.data['token']: + account.token = None + account.save() + return Response(model_to_dict(account),status=status.HTTP_200_OK) + else: + return Response({'message':"Invalid token!"},status=status.HTTP_200_OK) + except Account.DoesNotExist: + return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) diff --git a/api/controllers/collection/add_problems_to_collection.py b/api/controllers/collection/add_problems_to_collection.py new file mode 100644 index 0000000..1bf6eb6 --- /dev/null +++ b/api/controllers/collection/add_problems_to_collection.py @@ -0,0 +1,38 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def add_problems_to_collection(collection:Collection,request): + populated_problems = [] + + index = 0 + for problem_id in request.data['problem_ids']: + + problem = Problem.objects.get(problem_id=problem_id) + + alreadyExist = CollectionProblem.objects.filter(problem=problem,collection=collection) + if alreadyExist: + alreadyExist.delete() + + collection_problem = CollectionProblem( + problem=problem, + collection=collection, + order=index + ) + collection_problem.save() + index += 1 + cp_serialize = CollectionProblemSerializer(collection_problem) + populated_problems.append(cp_serialize.data) + + collection_serialize = CollectionSerializer(collection) + + return Response({ + **collection_serialize.data, + 'problems': populated_problems + },status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/controllers/collection/create_collection.py b/api/controllers/collection/create_collection.py new file mode 100644 index 0000000..96da548 --- /dev/null +++ b/api/controllers/collection/create_collection.py @@ -0,0 +1,20 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def create_collection(account_id:int,request): + request.data['owner'] = account_id + + serialize = CollectionSerializer(data=request.data) + + if serialize.is_valid(): + serialize.save() + return Response(serialize.data,status=status.HTTP_201_CREATED) + else: + return Response(serialize.errors,status=status.HTTP_400_BAD_REQUEST) diff --git a/api/controllers/collection/delete_collection.py b/api/controllers/collection/delete_collection.py new file mode 100644 index 0000000..67cba72 --- /dev/null +++ b/api/controllers/collection/delete_collection.py @@ -0,0 +1,13 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def delete_collection(collection:Collection): + collection.delete() + return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/api/controllers/collection/get_all_collections.py b/api/controllers/collection/get_all_collections.py new file mode 100644 index 0000000..ff1a53f --- /dev/null +++ b/api/controllers/collection/get_all_collections.py @@ -0,0 +1,37 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_collections(request): + collections = Collection.objects.all() + + account_id = request.query_params.get('account_id',0) + + if account_id: + collections = collections.filter(creator_id=account_id) + + populated_collections = [] + for collection in collections: + con_probs = CollectionProblem.objects.filter(collection=collection) + + populated_cp = [] + for cp in con_probs: + prob_serialize = ProblemSerializer(cp.problem) + cp_serialize = CollectionProblemSerializer(cp) + populated_cp.append({**cp_serialize.data,**prob_serialize.data}) + + serialize = CollectionSerializer(collection) + collection_data = serialize.data + collection_data['problems'] = populated_cp + + populated_collections.append(collection_data) + + return Response({ + 'collections': populated_collections + },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/collection/get_collection.py b/api/controllers/collection/get_collection.py new file mode 100644 index 0000000..34f639b --- /dev/null +++ b/api/controllers/collection/get_collection.py @@ -0,0 +1,27 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_collection(collection_id:int): + + collection = Collection.objects.get(collection_id=collection_id) + # problems = Problem.objects.filter(collectionproblem__collection_id=collection_id) + collectionProblems = CollectionProblem.objects.filter(collection=collection) + + collection_ser = CollectionSerializer(collection) + populated_problems = [] + for col_prob in collectionProblems: + col_prob_serialize = CollectionProblemSerializer(col_prob) + prob_serialize = ProblemSerializer(col_prob.problem) + populated_problems.append({**col_prob_serialize.data,**prob_serialize.data}) + + return Response({ + **collection_ser.data, + 'problems': sorted(populated_problems,key=lambda problem: problem['order']) + } ,status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/collection/remove_problems_from_collection.py b/api/controllers/collection/remove_problems_from_collection.py new file mode 100644 index 0000000..fbb39c7 --- /dev/null +++ b/api/controllers/collection/remove_problems_from_collection.py @@ -0,0 +1,13 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def remove_problems_from_collection(collection:Collection,request): + CollectionProblem.objects.filter(collection=collection,problem_id__in=request.data['problem_ids']).delete() + return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file diff --git a/api/controllers/collection/update_collection.py b/api/controllers/collection/update_collection.py new file mode 100644 index 0000000..626d671 --- /dev/null +++ b/api/controllers/collection/update_collection.py @@ -0,0 +1,18 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_collection(collection_id:int,request): + collection = Collection.objects.get(collection_id=collection_id) + collection_ser = CollectionSerializer(collection,data=request.data,partial=True) + if collection_ser.is_valid(): + collection_ser.save() + return Response(collection_ser.data,status=status.HTTP_200_OK) + else: + return Response(collection_ser.errors,status=status.HTTP_400_BAD_REQUEST) diff --git a/api/controllers/copypasta.py b/api/controllers/copypasta.py new file mode 100644 index 0000000..b625536 --- /dev/null +++ b/api/controllers/copypasta.py @@ -0,0 +1,9 @@ +# from api.utility import passwordEncryption +# from rest_framework.response import Response +# from rest_framework.decorators import api_view +# from api.sandbox.grader import PythonGrader +# from ...constant import GET,POST,PUT,DELETE +# from ...models import * +# from rest_framework import status +# from django.forms.models import model_to_dict +# from ...serializers import * \ No newline at end of file diff --git a/api/controllers/problem/create_problem.py b/api/controllers/problem/create_problem.py new file mode 100644 index 0000000..d3c2839 --- /dev/null +++ b/api/controllers/problem/create_problem.py @@ -0,0 +1,43 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def create_problem(account_id:int,request): + account = Account.objects.get(account_id=account_id) + + running_result = PythonGrader(request.data['solution'],request.data['testcases'],1,1.5).generate_output() + + if not running_result.runnable: + return Response({'detail': 'Error during creating. Your code may has an error/timeout!','output': running_result.getResult()},status=status.HTTP_406_NOT_ACCEPTABLE) + + problem = Problem( + language = request.data['language'], + creator = account, + title = request.data['title'], + description = request.data['description'], + solution = request.data['solution'], + time_limit = request.data['time_limit'] + ) + problem.save() + + testcases_result = [] + for unit in running_result.data: + testcases_result.append( + Testcase( + problem = problem, + input = unit.input, + output = unit.output + )) + + Testcase.objects.bulk_create(testcases_result) + + problem_serialize = ProblemSerializer(problem) + testcases_serialize = TestcaseSerializer(testcases_result,many=True) + + return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_201_CREATED) diff --git a/api/controllers/problem/delete_problem.py b/api/controllers/problem/delete_problem.py new file mode 100644 index 0000000..4140824 --- /dev/null +++ b/api/controllers/problem/delete_problem.py @@ -0,0 +1,20 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def delete_problem(problem_id:int): + try: + problem = Problem.objects.get(problem_id=problem_id) + except Problem.DoesNotExist: + return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) + testcases = Testcase.objects.filter(problem_id=problem_id) + + problem.delete() + testcases.delete() + return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file diff --git a/api/controllers/problem/get_all_problems.py b/api/controllers/problem/get_all_problems.py new file mode 100644 index 0000000..58a0a98 --- /dev/null +++ b/api/controllers/problem/get_all_problems.py @@ -0,0 +1,30 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_problems(request): + problem = Problem.objects.all() + + get_private = int(request.query_params.get("private",0)) + get_deactive = int(request.query_params.get("deactive",0)) + account_id = int(request.query_params.get("account_id",0)) + + if not get_private: + problem = problem.filter(is_private=False) + if not get_deactive: + problem = problem.filter(is_active=True) + if account_id != 0: + problem = problem.filter(creator_id=account_id) + + problem = problem.order_by('-problem_id') + + serialize = ProblemPopulateAccountSerializer(problem,many=True) + + return Response({'problems':serialize.data},status=status.HTTP_200_OK) + \ No newline at end of file diff --git a/api/controllers/problem/get_problem.py b/api/controllers/problem/get_problem.py new file mode 100644 index 0000000..7a70541 --- /dev/null +++ b/api/controllers/problem/get_problem.py @@ -0,0 +1,20 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_problem(problem_id:int): + try: + problem = Problem.objects.get(problem_id=problem_id) + except Problem.DoesNotExist: + return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) + testcases = Testcase.objects.filter(problem_id=problem_id) + problem_serialize = ProblemPopulateAccountSerializer(problem) + testcases_serialize = TestcaseSerializer(testcases,many=True) + return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_200_OK) + \ No newline at end of file diff --git a/api/controllers/problem/remove_bulk_problems.py b/api/controllers/problem/remove_bulk_problems.py new file mode 100644 index 0000000..a116836 --- /dev/null +++ b/api/controllers/problem/remove_bulk_problems.py @@ -0,0 +1,16 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def remove_bulk_problems(request): + target = request.data.get("problem",[]) + problems = Problem.objects.filter(problem_id__in=target) + problems.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + \ No newline at end of file diff --git a/api/controllers/problem/update_problem.py b/api/controllers/problem/update_problem.py new file mode 100644 index 0000000..203ae2a --- /dev/null +++ b/api/controllers/problem/update_problem.py @@ -0,0 +1,57 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_problem(problem_id:int,request): + try: + problem = Problem.objects.get(problem_id=problem_id) + except Problem.DoesNotExist: + return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) + testcases = Testcase.objects.filter(problem_id=problem_id) + + problem.title = request.data.get("title",problem.title) + problem.language = request.data.get("language",problem.language) + problem.description = request.data.get("description",problem.description) + problem.solution = request.data.get("solution",problem.solution) + problem.time_limit = request.data.get("time_limit",problem.time_limit) + problem.is_private = request.data.get("is_private",problem.is_private) + + if 'testcases' in request.data: + running_result = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() + + if not running_result.runnable: + return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) + + testcases.delete() + testcase_result = [] + for unit in running_result.data: + testcase = Testcase( + problem = problem, + input = unit.input, + output = unit.output + ) + testcase.save() + testcase_result.append(testcase) + problem.save() + + problem_serialize = ProblemSerializer(problem) + testcases_serialize = TestcaseSerializer(testcase_result,many=True) + + return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_201_CREATED) + + elif 'solution' in request.data: + program_input = [i.input for i in testcases] + running_result = PythonGrader(problem.solution,program_input,1,1.5).generate_output() + + if not running_result.runnable: + return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) + + problem.save() + problem_serialize = ProblemSerializer(problem) + return Response(problem_serialize.data,status=status.HTTP_201_CREATED) diff --git a/api/controllers/submission/get_submission_by_quries.py b/api/controllers/submission/get_submission_by_quries.py new file mode 100644 index 0000000..99a0a62 --- /dev/null +++ b/api/controllers/submission/get_submission_by_quries.py @@ -0,0 +1,45 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_submission_by_quries(request): + submission = Submission.objects.all() + + # Query params + problem_id = int(request.query_params.get("problem_id", 0)) + account_id = int(request.query_params.get("account_id", 0)) + topic_id = int(request.query_params.get("topic_id", 0)) + passed = int(request.query_params.get("passed", -1)) + sort_score = int(request.query_params.get("sort_score", 0)) + sort_date = int(request.query_params.get("sort_date", 0)) + + if problem_id != 0: + submission = submission.filter(problem_id=problem_id) + if account_id != 0: + submission = submission.filter(account_id=account_id) + if topic_id != 0: + submission = submission.filter(problem__topic_id=topic_id) + + if passed == 0: + submission = submission.filter(is_passed=False) + elif passed == 1: + submission = submission.filter(is_passed=True) + + if sort_score == -1: + submission = submission.order_by('passed_ratio') + elif sort_score == 1: + submission = submission.order_by('-passed_ratio') + + if sort_date == -1: + submission = submission.order_by('date') + elif sort_date == 1: + submission = submission.order_by('-date') + + serialize = SubmissionPoplulateProblemSerializer(submission,many=True) + return Response({"submissions": serialize.data},status=status.HTTP_200_OK) diff --git a/api/controllers/submission/submit_problem.py b/api/controllers/submission/submit_problem.py new file mode 100644 index 0000000..8252e0b --- /dev/null +++ b/api/controllers/submission/submit_problem.py @@ -0,0 +1,76 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * +from ...utility import regexMatching +from time import sleep + +QUEUE = [0,0,0,0,0,0,0,0,0,0] + +def avaliableQueue(): + global QUEUE + for i in range(len(QUEUE)): + if QUEUE[i] == 0: + return i + return -1 + +def submit_problem(problem_id:int,account_id:int,request): + global QUEUE + problem = Problem.objects.get(problem_id=problem_id) + testcases = Testcase.objects.filter(problem=problem) + + submission_code = request.data['submission_code'] + solution_input = [model_to_dict(i)['input'] for i in testcases] + solution_output = [model_to_dict(i)['output'] for i in testcases] + + if not regexMatching(problem.submission_regex,submission_code): + grading_result = '-'*len(solution_input) + else: + empty_queue = avaliableQueue() + while empty_queue == -1: + empty_queue = avaliableQueue() + sleep(5) + + QUEUE[empty_queue] = 1 + # grading_result = grader.grading(empty_queue+1,submission_code,solution_input,solution_output) + grading_result = PythonGrader(submission_code,solution_input,empty_queue+1,1.5).grading(solution_output) + QUEUE[empty_queue] = 0 + + total_score = sum([i.is_passed for i in grading_result.data if i.is_passed]) + max_score = len(grading_result.data) + + submission = Submission( + problem = problem, + account = Account.objects.get(account_id=account_id), + submission_code = request.data['submission_code'], + is_passed = grading_result.is_passed, + score = total_score, + max_score = max_score, + passed_ratio = total_score/max_score + ) + submission.save() + + submission_testcases = [] + for i in range(len(grading_result.data)): + submission_testcases.append(SubmissionTestcase( + submission = submission, + testcase = testcases[i], + output = grading_result.data[i].output, + is_passed = grading_result.data[i].is_passed, + runtime_status = grading_result.data[i].runtime_status + )) + + SubmissionTestcase.objects.bulk_create(submission_testcases) + + submission_serialize = SubmissionPoplulateProblemSecureSerializer(submission) + testcases_serialize = SubmissionTestcaseSecureSerializer(submission_testcases,many=True) + + return Response({ + **submission_serialize.data, + "runtime_output": testcases_serialize.data + },status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/controllers/topic/add_collections_to_topic.py b/api/controllers/topic/add_collections_to_topic.py new file mode 100644 index 0000000..14c85c7 --- /dev/null +++ b/api/controllers/topic/add_collections_to_topic.py @@ -0,0 +1,36 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def add_collections_to_topic(topic_id:int,request): + topic = Topic.objects.get(topic_id=topic_id) + populated_collections = [] + + index = 0 + for collection_id in request.data['collection_ids']: + collection = Collection.objects.get(collection_id=collection_id) + + alreadyExist = TopicCollection.objects.filter(topic_id=topic.topic_id,collection_id=collection.collection_id) + if alreadyExist: + alreadyExist.delete() + + topicCollection = TopicCollection( + topic=topic, + collection=collection, + order=index + ) + topicCollection.save() + index += 1 + tc_serialize = TopicCollectionSerializer(topicCollection) + populated_collections.append(tc_serialize.data) + + return Response({ + **TopicSerializer(topic).data, + "collections": populated_collections + },status=status.HTTP_201_CREATED) diff --git a/api/controllers/topic/create_topic.py b/api/controllers/topic/create_topic.py new file mode 100644 index 0000000..aa9d678 --- /dev/null +++ b/api/controllers/topic/create_topic.py @@ -0,0 +1,19 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def create_topic(account_id:int,request): + request.data._mutable=True + request.data['creator'] = account_id + serializer = TopicSerializer(data=request.data) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data,status=status.HTTP_201_CREATED) + return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST) diff --git a/api/controllers/topic/delete_topic.py b/api/controllers/topic/delete_topic.py new file mode 100644 index 0000000..67cb6c2 --- /dev/null +++ b/api/controllers/topic/delete_topic.py @@ -0,0 +1,14 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def delete_topic(topic_id:int): + topic = Topic.objects.get(topic_id=topic_id) + topic.delete() + return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/api/controllers/topic/get_all_topics.py b/api/controllers/topic/get_all_topics.py new file mode 100644 index 0000000..9c149f5 --- /dev/null +++ b/api/controllers/topic/get_all_topics.py @@ -0,0 +1,23 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_topics(request): + topics = Topic.objects.all() + + account_id = request.query_params.get('account_id',0) + + if account_id: + topics = topics.filter(creator_id=account_id) + + serializer = TopicSerializer(topics,many=True) + + return Response({ + 'topics': serializer.data + },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py new file mode 100644 index 0000000..33c55ce --- /dev/null +++ b/api/controllers/topic/get_topic.py @@ -0,0 +1,40 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_topic(topic_id:int): + topic = Topic.objects.get(topic_id=topic_id) + topicCollections = TopicCollection.objects.filter(topic_id=topic_id) + accessedAccounts = Account.objects.filter(topicaccountaccess__topic_id=topic_id) + + topic_ser = TopicSerializer(topic) + populate_collections = [] + + for top_col in topicCollections: + collection_serialize = CollectionSerializer(top_col.collection) + collection_data = collection_serialize.data + + populate_problems = [] + collection_problems = CollectionProblem.objects.filter(collection=top_col.collection) + for col_prob in collection_problems: + prob_serialize = ProblemSerializer(col_prob.problem) + col_prob_serialize = CollectionProblemSerializer(col_prob) + populate_problems.append({**col_prob_serialize.data,**prob_serialize.data}) + + collection_data['problems'] = populate_problems + top_col_serialize = TopicCollectionSerializer(top_col) + populate_collections.append({**top_col_serialize.data,**collection_data}) + + accessedAccountsSerialize = AccountSecureSerializer(accessedAccounts,many=True) + + return Response({ + **topic_ser.data, + "collections": sorted(populate_collections,key=lambda collection: collection['order']), + "accessed_accounts": accessedAccountsSerialize.data + },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/topic/remove_collections_from_topic.py b/api/controllers/topic/remove_collections_from_topic.py new file mode 100644 index 0000000..1275956 --- /dev/null +++ b/api/controllers/topic/remove_collections_from_topic.py @@ -0,0 +1,16 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def remove_collections_from_topic(topic_id:int,request): + TopicCollection.objects.filter(topic_id=topic_id,collection_id__in=request.data['collection_ids']).delete() + # collections = Collection.objects.filter(collection_id__in=request.data['collection_ids']) + # problems = Problem.objects.filter(problem_id__in=request.data['problems_id']) + # TopicProblem.objects.filter(topic_id=topic,problem_id__in=problems).delete() + return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/api/controllers/topic/update_topic.py b/api/controllers/topic/update_topic.py new file mode 100644 index 0000000..7223acb --- /dev/null +++ b/api/controllers/topic/update_topic.py @@ -0,0 +1,19 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_topic(topic_id:int,request): + topic = Topic.objects.get(topic_id=topic_id) + + topic_ser = TopicSerializer(topic,data=request.data,partial=True) + if topic_ser.is_valid(): + topic_ser.save() + return Response(topic_ser.data,status=status.HTTP_200_OK) + return Response(topic_ser.errors,status=status.HTTP_400_BAD_REQUEST) + \ No newline at end of file diff --git a/api/views/submission.py b/api/views/submission.py index 31140b6..ff3817f 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -112,4 +112,4 @@ def view_all_submission(request): submission = submission.order_by('-date') serialize = SubmissionPoplulateProblemSerializer(submission,many=True) - return Response({"submissions": serialize.data},status=status.HTTP_200_OK) \ No newline at end of file + return Response({"submissions": serialize.data},status=status.HTTP_200_OK) From 65167a49145e2d750d24e13aac2cc139d1c6527e Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 29 Nov 2023 18:14:20 +0700 Subject: [PATCH 09/61] Update to new api model --- api/urls.py | 4 ++-- api/views/account.py | 28 ++++++++-------------------- api/views/auth.py | 20 ++++++-------------- api/views/topic.py | 1 + 4 files changed, 17 insertions(+), 36 deletions(-) diff --git a/api/urls.py b/api/urls.py index 286bf15..e7fd0a5 100644 --- a/api/urls.py +++ b/api/urls.py @@ -7,8 +7,8 @@ path("logout",auth.logout), path('token',auth.get_authorization), - path("accounts",account.account_collection), - path("accounts/",account.get_account), + path("accounts",account.all_accounts), + path("accounts/",account.one_account), path("accounts//daily-submissions",account.get_daily_submission), path("accounts//password",account.change_password), diff --git a/api/views/account.py b/api/views/account.py index 85b688c..0d1e940 100644 --- a/api/views/account.py +++ b/api/views/account.py @@ -7,33 +7,21 @@ from rest_framework import status from django.forms.models import model_to_dict from ..serializers import * +from ..controllers.account.create_account import * +from ..controllers.account.get_account import * +from ..controllers.account.get_all_accounts import * @api_view([GET,POST]) -def account_collection(request): +def all_accounts(request): if request.method == GET: - accounts = Account.objects.all() - serialize = AccountSecureSerializer(accounts,many=True) - return Response({ - "accounts": serialize.data - },status=status.HTTP_200_OK) + return get_all_accounts() elif request.method == POST: - request.data['password'] = passwordEncryption(request.data['password']) - try: - account = Account.objects.create(**request.data) - except Exception as e: - return Response({'message':str(e)},status=status.HTTP_400_BAD_REQUEST) - serialize = AccountSerializer(account) - return Response(serialize.data,status=status.HTTP_201_CREATED) + return create_account(request) @api_view([GET]) -def get_account(request,account_id): - try: - account = Account.objects.get(account_id=account_id) - serialize = AccountSerializer(account) - return Response(serialize.data,status=status.HTTP_200_OK) - except: - return Response({'message':'Account not found!'},status=status.HTTP_404_NOT_FOUND) +def one_account(request,account_id): + return get_account(account_id) @api_view([PUT]) def change_password(request,account_id): diff --git a/api/views/auth.py b/api/views/auth.py index 5d66bee..2c4baf0 100644 --- a/api/views/auth.py +++ b/api/views/auth.py @@ -10,23 +10,15 @@ from time import time from decouple import config +from ..controllers.auth.authorization import * +from ..controllers.auth.login import * +from ..controllers.auth.logout import * + TOKEN_LIFETIME = int(config('TOKEN_LIFETIME_SECOND')) # (Second) @api_view([POST]) -def login(request): - try: - account = Account.objects.get(username=request.data['username']) - account_dict = model_to_dict(account) - - if passwordEncryption(request.data['password']) == account_dict['password']: - account.token = uuid4().hex - account.token_expire = int(time()+TOKEN_LIFETIME) - account.save() - return Response(model_to_dict(account),status=status.HTTP_202_ACCEPTED) - else: - return Response({'message':"Incorrect password!"},status=status.HTTP_406_NOT_ACCEPTABLE) - except Account.DoesNotExist: - return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) +def login_account(request): + return login(request) @api_view([POST]) def logout(request): diff --git a/api/views/topic.py b/api/views/topic.py index 69147ff..3962206 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -7,6 +7,7 @@ from rest_framework import status from django.forms.models import model_to_dict from ..serializers import * +from ..controllers import * @api_view([POST]) @parser_classes([MultiPartParser,FormParser]) From d2fd708260b9312aa44a8d07347f7b779059b898 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 29 Nov 2023 22:06:33 +0700 Subject: [PATCH 10/61] Change to view-controller model --- api/urls.py | 36 +++++------ api/views/account.py | 10 +--- api/views/auth.py | 47 ++------------- api/views/collection.py | 115 ++++++----------------------------- api/views/problem.py | 129 +++++----------------------------------- api/views/submission.py | 104 ++------------------------------ api/views/topic.py | 112 ++++++---------------------------- tests/tst.py | 20 ++++--- 8 files changed, 96 insertions(+), 477 deletions(-) diff --git a/api/urls.py b/api/urls.py index e7fd0a5..2e46c15 100644 --- a/api/urls.py +++ b/api/urls.py @@ -3,32 +3,32 @@ urlpatterns = [ - path("login",auth.login), - path("logout",auth.logout), - path('token',auth.get_authorization), + path("login",auth.login_view), + path("logout",auth.logout_view), + path('token',auth.authorization_view), - path("accounts",account.all_accounts), - path("accounts/",account.one_account), + path("accounts",account.all_accounts_view), + path("accounts/",account.one_account_view), path("accounts//daily-submissions",account.get_daily_submission), path("accounts//password",account.change_password), - path('accounts//problems',problem.create_problem), - path('problems',problem.all_problem), - path('problems/',problem.one_problem), + path('accounts//problems',problem.create_problem_view), + path('problems',problem.all_problems_view), + path('problems/',problem.one_problem_view), - path('problems//',submission.submit_problem), - path('submissions',submission.view_all_submission), + path('problems//',submission.submit_problem_view), + path('submissions',submission.all_submission_view), - path('accounts//topics',topic.create_topic), - path('topics',topic.all_topic), - path('topics/',topic.one_topic), + path('accounts//topics',topic.create_topic_view), + path('topics',topic.all_topics_view), + path('topics/',topic.one_topic_view), path('topics//access',topic.account_access), - path('topics//collections/',topic.topic_collection), + path('topics//collections/',topic.topic_collections_view), - path('accounts//collections',collection.create_collections), - path('collections',collection.all_collections), - path('collections/',collection.one_collection), - path('collections//problems/',collection.collection_problems), + path('accounts//collections',collection.create_collection_view), + path('collections',collection.all_collections_view), + path('collections/',collection.one_collection_view), + path('collections//problems/',collection.collection_problems_view), path('script',script.run_script), ] \ No newline at end of file diff --git a/api/views/account.py b/api/views/account.py index 0d1e940..8d7549f 100644 --- a/api/views/account.py +++ b/api/views/account.py @@ -12,15 +12,14 @@ from ..controllers.account.get_all_accounts import * @api_view([GET,POST]) -def all_accounts(request): +def all_accounts_view(request): if request.method == GET: return get_all_accounts() - elif request.method == POST: return create_account(request) @api_view([GET]) -def one_account(request,account_id): +def one_account_view(request,account_id): return get_account(account_id) @api_view([PUT]) @@ -48,8 +47,3 @@ def get_daily_submission(request,account_id:int): return Response({"submissions_by_date": submission_by_date}) -# @api_view([GET]) -# def get_passed_submission(request,account_id:int): -# submissions = Submission.objects.filter(account_id=account_id,is_passed=True) - -# serialize = SubmissionSerializer(submissions,many=True) diff --git a/api/views/auth.py b/api/views/auth.py index 2c4baf0..ed93aa8 100644 --- a/api/views/auth.py +++ b/api/views/auth.py @@ -17,50 +17,13 @@ TOKEN_LIFETIME = int(config('TOKEN_LIFETIME_SECOND')) # (Second) @api_view([POST]) -def login_account(request): +def login_view(request): return login(request) @api_view([POST]) -def logout(request): - try: - account = Account.objects.get(account_id=request.data['account_id']) - if account.token == request.data['token']: - account.token = None - account.save() - return Response(model_to_dict(account),status=status.HTTP_200_OK) - else: - return Response({'message':"Invalid token!"},status=status.HTTP_200_OK) - except Account.DoesNotExist: - return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) +def logout_view(request): + return logout(request) @api_view([PUT]) -def get_authorization(request): - try: - account = Account.objects.get(account_id=request.data['account_id']) - account_dict = model_to_dict(account) - if account_dict['token_expire'] >= time() and account_dict['token'] == request.data['token']: - return Response({'result':True},status=status.HTTP_200_OK) - return Response({'result':False},status=status.HTTP_200_OK) - except Account.DoesNotExist: - return Response({'result':False},status=status.HTTP_200_OK) - # return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) - -# @api_view([GET]) -# def get_token(request): -# try: -# account = Account.objects.get(username=request.data['username']) -# account_dict = model_to_dict(account) - -# if account_dict['token_expire'] < time(): -# return Response({'message':"Login timeout!"},status=status.HTTP_200_OK) -# elif account_dict['token'] == request.data['token'] - -# if passwordEncryption(request.data['password']) == account_dict['password']: -# account.token = uuid4().hex -# account.token_expire = int(time()+60) -# account.save() -# return Response(model_to_dict(account),status=status.HTTP_202_ACCEPTED) -# else: -# return Response({'message':"Incorrect password!"},status=status.HTTP_200_OK) -# except Account.DoesNotExist: -# return Response({'message':"User doesn't exists!"},status=status.HTTP_404_NOT_FOUND) \ No newline at end of file +def authorization_view(request): + return authorization(request) \ No newline at end of file diff --git a/api/views/collection.py b/api/views/collection.py index 521e81d..b8cdbf4 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -8,112 +8,35 @@ from django.forms.models import model_to_dict from ..serializers import * -@api_view([POST]) -def create_collections(request,account_id:int): - request.data['owner'] = account_id +from ..controllers.collection.create_collection import * +from ..controllers.collection.get_collection import * +from ..controllers.collection.get_all_collections import * +from ..controllers.collection.update_collection import * +from ..controllers.collection.delete_collection import * +from ..controllers.collection.add_problems_to_collection import * +from ..controllers.collection.remove_problems_from_collection import * - serialize = CollectionSerializer(data=request.data) - if serialize.is_valid(): - serialize.save() - return Response(serialize.data,status=status.HTTP_201_CREATED) - else: - return Response(serialize.errors,status=status.HTTP_400_BAD_REQUEST) +@api_view([POST]) +def create_collection_view(request,account_id:int): + return create_collection(account_id,request) @api_view([GET]) -def all_collections(request): - collections = Collection.objects.all() - - account_id = request.query_params.get('account_id',0) - - if account_id: - collections = collections.filter(creator_id=account_id) - - populated_collections = [] - for collection in collections: - con_probs = CollectionProblem.objects.filter(collection=collection) - - populated_cp = [] - for cp in con_probs: - prob_serialize = ProblemSerializer(cp.problem) - cp_serialize = CollectionProblemSerializer(cp) - populated_cp.append({**cp_serialize.data,**prob_serialize.data}) - - serialize = CollectionSerializer(collection) - collection_data = serialize.data - collection_data['problems'] = populated_cp - - populated_collections.append(collection_data) - - return Response({ - 'collections': populated_collections - },status=status.HTTP_200_OK) +def all_collections_view(request): + return get_all_collections(request) @api_view([GET,PUT,DELETE]) -def one_collection(request,collection_id:int): - collection = Collection.objects.get(collection_id=collection_id) - problems = Problem.objects.filter(collectionproblem__collection_id=collection_id) - collectionProblems = CollectionProblem.objects.filter(collection=collection) - +def one_collection_view(request,collection_id:int): if request.method == GET: - collection_ser = CollectionSerializer(collection) - - populated_problems = [] - for col_prob in collectionProblems: - col_prob_serialize = CollectionProblemSerializer(col_prob) - prob_serialize = ProblemSerializer(col_prob.problem) - populated_problems.append({**col_prob_serialize.data,**prob_serialize.data}) - - return Response({ - **collection_ser.data, - 'problems': sorted(populated_problems,key=lambda problem: problem['order']) - } ,status=status.HTTP_200_OK) - + return get_collection(collection_id) if request.method == PUT: - collection_ser = CollectionSerializer(collection,data=request.data,partial=True) - if collection_ser.is_valid(): - collection_ser.save() - return Response(collection_ser.data,status=status.HTTP_200_OK) - else: - return Response(collection_ser.errors,status=status.HTTP_400_BAD_REQUEST) - + return update_collection(collection_id,request) if request.method == DELETE: - collection.delete() - return Response(status=status.HTTP_204_NO_CONTENT) + return delete_collection(collection_id) @api_view([PUT]) -def collection_problems(request,collection_id:int,method:str): - collection = Collection.objects.get(collection_id=collection_id) - +def collection_problems_view(request,collection_id:int,method:str): if method == "add": - populated_problems = [] - - index = 0 - for problem_id in request.data['problem_ids']: - - problem = Problem.objects.get(problem_id=problem_id) - - alreadyExist = CollectionProblem.objects.filter(problem=problem,collection=collection) - if alreadyExist: - alreadyExist.delete() - - collection_problem = CollectionProblem( - problem=problem, - collection=collection, - order=index - ) - collection_problem.save() - index += 1 - cp_serialize = CollectionProblemSerializer(collection_problem) - populated_problems.append(cp_serialize.data) - - collection_serialize = CollectionSerializer(collection) - - return Response({ - **collection_serialize.data, - 'problems': populated_problems - },status=status.HTTP_201_CREATED) - + return add_problems_to_collection(collection_id,request) if method == "remove": - CollectionProblem.objects.filter(collection=collection,problem_id__in=request.data['problem_ids']).delete() - return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file + return remove_problems_from_collection(collection_id,request) \ No newline at end of file diff --git a/api/views/problem.py b/api/views/problem.py index d154a6b..092045b 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -8,127 +8,30 @@ from django.forms.models import model_to_dict from ..serializers import * +from ..controllers.problem.create_problem import * +from ..controllers.problem.update_problem import * +from ..controllers.problem.delete_problem import * +from ..controllers.problem.get_problem import * +from ..controllers.problem.get_all_problems import * +from ..controllers.problem.remove_bulk_problems import * + # Create your views here. @api_view([POST]) -def create_problem(request,account_id): - account = Account.objects.get(account_id=account_id) - - running_result = PythonGrader(request.data['solution'],request.data['testcases'],1,1.5).generate_output() - - if not running_result.runnable: - return Response({'detail': 'Error during creating. Your code may has an error/timeout!','output': running_result.getResult()},status=status.HTTP_406_NOT_ACCEPTABLE) - - problem = Problem( - language = request.data['language'], - creator = account, - title = request.data['title'], - description = request.data['description'], - solution = request.data['solution'], - time_limit = request.data['time_limit'] - ) - problem.save() - - testcases_result = [] - for unit in running_result.data: - testcases_result.append( - Testcase( - problem = problem, - input = unit.input, - output = unit.output - )) - - Testcase.objects.bulk_create(testcases_result) - - problem_serialize = ProblemSerializer(problem) - testcases_serialize = TestcaseSerializer(testcases_result,many=True) - - return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_201_CREATED) +def create_problem_view(request,account_id): + return create_problem(account_id,request) @api_view([GET,DELETE]) -def all_problem(request): +def all_problems_view(request): if request.method == GET: - - problem = Problem.objects.all() - - get_private = int(request.query_params.get("private",0)) - get_deactive = int(request.query_params.get("deactive",0)) - account_id = int(request.query_params.get("account_id",0)) - - if not get_private: - problem = problem.filter(is_private=False) - if not get_deactive: - problem = problem.filter(is_active=True) - if account_id != 0: - problem = problem.filter(creator_id=account_id) - - problem = problem.order_by('-problem_id') - - serialize = ProblemPopulateAccountSerializer(problem,many=True) - - return Response({'problems':serialize.data},status=status.HTTP_200_OK) + return get_all_problems(request) elif request.method == DELETE: - target = request.data.get("problem",[]) - problems = Problem.objects.filter(problem_id__in=target) - problems.delete() - return Response(status=status.HTTP_204_NO_CONTENT) + return remove_bulk_problems(request) - @api_view([GET,PUT,DELETE]) -def one_problem(request,problem_id: int): - try: - problem = Problem.objects.get(problem_id=problem_id) - except Problem.DoesNotExist: - return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) - testcases = Testcase.objects.filter(problem_id=problem_id) - +def one_problem_view(request,problem_id: int): if request.method == GET: - problem_serialize = ProblemPopulateAccountSerializer(problem) - testcases_serialize = TestcaseSerializer(testcases,many=True) - return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_200_OK) + return get_problem(problem_id) elif request.method == PUT: - - problem.title = request.data.get("title",problem.title) - problem.language = request.data.get("language",problem.language) - problem.description = request.data.get("description",problem.description) - problem.solution = request.data.get("solution",problem.solution) - problem.time_limit = request.data.get("time_limit",problem.time_limit) - problem.is_private = request.data.get("is_private",problem.is_private) - - if 'testcases' in request.data: - running_result = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() - - if not running_result.runnable: - return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) - - testcases.delete() - testcase_result = [] - for unit in running_result.data: - testcase = Testcase( - problem = problem, - input = unit.input, - output = unit.output - ) - testcase.save() - testcase_result.append(testcase) - problem.save() - - problem_serialize = ProblemSerializer(problem) - testcases_serialize = TestcaseSerializer(testcase_result,many=True) - - return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_201_CREATED) - - elif 'solution' in request.data: - program_input = [i.input for i in testcases] - running_result = PythonGrader(problem.solution,program_input,1,1.5).generate_output() - - if not running_result.runnable: - return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) - - problem.save() - problem_serialize = ProblemSerializer(problem) - return Response(problem_serialize.data,status=status.HTTP_201_CREATED) - + return update_problem(problem_id,request) elif request.method == DELETE: - problem.delete() - testcases.delete() - return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file + return delete_problem(problem_id) \ No newline at end of file diff --git a/api/views/submission.py b/api/views/submission.py index ff3817f..4d834e3 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -11,105 +11,13 @@ from time import sleep from ..utility import regexMatching -QUEUE = [0,0,0,0,0,0,0,0,0,0] - -def avaliableQueue(): - global QUEUE - for i in range(len(QUEUE)): - if QUEUE[i] == 0: - return i - return -1 +from ..controllers.submission.submit_problem import * +from ..controllers.submission.get_submission_by_quries import * @api_view([POST]) -def submit_problem(request,problem_id,account_id): - global QUEUE - problem = Problem.objects.get(problem_id=problem_id) - testcases = Testcase.objects.filter(problem=problem) - - submission_code = request.data['submission_code'] - solution_input = [model_to_dict(i)['input'] for i in testcases] - solution_output = [model_to_dict(i)['output'] for i in testcases] - - if not regexMatching(problem.submission_regex,submission_code): - grading_result = '-'*len(solution_input) - else: - empty_queue = avaliableQueue() - while empty_queue == -1: - empty_queue = avaliableQueue() - sleep(5) - - QUEUE[empty_queue] = 1 - # grading_result = grader.grading(empty_queue+1,submission_code,solution_input,solution_output) - grading_result = PythonGrader(submission_code,solution_input,empty_queue+1,1.5).grading(solution_output) - QUEUE[empty_queue] = 0 - - total_score = sum([i.is_passed for i in grading_result.data if i.is_passed]) - max_score = len(grading_result.data) - - submission = Submission( - problem = problem, - account = Account.objects.get(account_id=account_id), - submission_code = request.data['submission_code'], - is_passed = grading_result.is_passed, - score = total_score, - max_score = max_score, - passed_ratio = total_score/max_score - ) - submission.save() - - submission_testcases = [] - for i in range(len(grading_result.data)): - submission_testcases.append(SubmissionTestcase( - submission = submission, - testcase = testcases[i], - output = grading_result.data[i].output, - is_passed = grading_result.data[i].is_passed, - runtime_status = grading_result.data[i].runtime_status - )) - - SubmissionTestcase.objects.bulk_create(submission_testcases) - - submission_serialize = SubmissionPoplulateProblemSecureSerializer(submission) - testcases_serialize = SubmissionTestcaseSecureSerializer(submission_testcases,many=True) - - return Response({ - **submission_serialize.data, - "runtime_output": testcases_serialize.data - },status=status.HTTP_201_CREATED) +def submit_problem_view(request,problem_id,account_id): + return submit_problem(problem_id,account_id,request) @api_view([GET]) -def view_all_submission(request): - submission = Submission.objects.all() - - # Query params - problem_id = int(request.query_params.get("problem_id", 0)) - account_id = int(request.query_params.get("account_id", 0)) - topic_id = int(request.query_params.get("topic_id", 0)) - passed = int(request.query_params.get("passed", -1)) - sort_score = int(request.query_params.get("sort_score", 0)) - sort_date = int(request.query_params.get("sort_date", 0)) - - if problem_id != 0: - submission = submission.filter(problem_id=problem_id) - if account_id != 0: - submission = submission.filter(account_id=account_id) - if topic_id != 0: - submission = submission.filter(problem__topic_id=topic_id) - - if passed == 0: - submission = submission.filter(is_passed=False) - elif passed == 1: - submission = submission.filter(is_passed=True) - - if sort_score == -1: - submission = submission.order_by('passed_ratio') - elif sort_score == 1: - submission = submission.order_by('-passed_ratio') - - if sort_date == -1: - submission = submission.order_by('date') - elif sort_date == 1: - submission = submission.order_by('-date') - - serialize = SubmissionPoplulateProblemSerializer(submission,many=True) - return Response({"submissions": serialize.data},status=status.HTTP_200_OK) +def all_submission_view(request): + return get_submission_by_quries(request) diff --git a/api/views/topic.py b/api/views/topic.py index 3962206..4aa8a9b 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -7,113 +7,39 @@ from rest_framework import status from django.forms.models import model_to_dict from ..serializers import * -from ..controllers import * + +from ..controllers.topic.create_topic import * +from ..controllers.topic.get_topic import * +from ..controllers.topic.get_all_topics import * +from ..controllers.topic.update_topic import * +from ..controllers.topic.delete_topic import * +from ..controllers.topic.add_collections_to_topic import * +from ..controllers.topic.remove_collections_from_topic import * @api_view([POST]) @parser_classes([MultiPartParser,FormParser]) -def create_topic(request,account_id :int): - request.data._mutable=True - request.data['creator'] = account_id - serializer = TopicSerializer(data=request.data) - - if serializer.is_valid(): - serializer.save() - return Response(serializer.data,status=status.HTTP_201_CREATED) - return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST) +def create_topic_view(request,account_id :int): + return create_topic(account_id,request) @api_view([GET]) -def all_topic(request): - topics = Topic.objects.all() - - account_id = request.query_params.get('account_id',0) - - if account_id: - topics = topics.filter(creator_id=account_id) - - serializer = TopicSerializer(topics,many=True) - - return Response({ - 'topics': serializer.data - },status=status.HTTP_200_OK) +def all_topics_view(request): + return get_all_topics(request) @api_view([GET,PUT,DELETE]) -def one_topic(request,topic_id:int): - topic = Topic.objects.get(topic_id=topic_id) - topicCollections = TopicCollection.objects.filter(topic_id=topic_id) - accessedAccounts = Account.objects.filter(topicaccountaccess__topic_id=topic_id) - +def one_topic_view(request,topic_id:int): if request.method == GET: - topic_ser = TopicSerializer(topic) - populate_collections = [] - - for top_col in topicCollections: - collection_serialize = CollectionSerializer(top_col.collection) - collection_data = collection_serialize.data - - populate_problems = [] - collection_problems = CollectionProblem.objects.filter(collection=top_col.collection) - for col_prob in collection_problems: - prob_serialize = ProblemSerializer(col_prob.problem) - col_prob_serialize = CollectionProblemSerializer(col_prob) - populate_problems.append({**col_prob_serialize.data,**prob_serialize.data}) - - collection_data['problems'] = populate_problems - top_col_serialize = TopicCollectionSerializer(top_col) - populate_collections.append({**top_col_serialize.data,**collection_data}) - - accessedAccountsSerialize = AccountSecureSerializer(accessedAccounts,many=True) - - return Response({ - **topic_ser.data, - "collections": sorted(populate_collections,key=lambda collection: collection['order']), - "accessed_accounts": accessedAccountsSerialize.data - },status=status.HTTP_200_OK) + return get_topic(topic_id) elif request.method == PUT: - topic_ser = TopicSerializer(topic,data=request.data,partial=True) - if topic_ser.is_valid(): - topic_ser.save() - return Response(topic_ser.data,status=status.HTTP_200_OK) - return Response(topic_ser.errors,status=status.HTTP_400_BAD_REQUEST) + return update_topic(topic_id,request) elif request.method == DELETE: - topic.delete() - return Response(status=status.HTTP_204_NO_CONTENT) + return delete_topic(topic_id) @api_view([PUT]) -def topic_collection(request,topic_id:int,method:str): - topic = Topic.objects.get(topic_id=topic_id) - +def topic_collections_view(request,topic_id:int,method:str): if method == "add": - populated_collections = [] - - index = 0 - for collection_id in request.data['collection_ids']: - collection = Collection.objects.get(collection_id=collection_id) - - alreadyExist = TopicCollection.objects.filter(topic_id=topic.topic_id,collection_id=collection.collection_id) - if alreadyExist: - alreadyExist.delete() - - topicCollection = TopicCollection( - topic=topic, - collection=collection, - order=index - ) - topicCollection.save() - index += 1 - tc_serialize = TopicCollectionSerializer(topicCollection) - populated_collections.append(tc_serialize.data) - - return Response({ - **TopicSerializer(topic).data, - "collections": populated_collections - },status=status.HTTP_201_CREATED) - + return add_collections_to_topic(topic_id,request) elif method == "remove": - TopicCollection.objects.filter(topic_id=topic_id,collection_id__in=request.data['collection_ids']).delete() - # collections = Collection.objects.filter(collection_id__in=request.data['collection_ids']) - # problems = Problem.objects.filter(problem_id__in=request.data['problems_id']) - # TopicProblem.objects.filter(topic_id=topic,problem_id__in=problems).delete() - return Response(status=status.HTTP_204_NO_CONTENT) + return remove_collections_from_topic(topic_id,request) @api_view([POST,PUT]) def account_access(request,topic_id:int): diff --git a/tests/tst.py b/tests/tst.py index a66cad1..9cc5be1 100644 --- a/tests/tst.py +++ b/tests/tst.py @@ -1,11 +1,13 @@ -n = int(input("n: ")) +x,y,z = 0 -if n == 1: - print("1 is not a Prime Number") +if x > 0: + i = 2 + if y > 1: + k = 2 else: - for i in range(2,n): - if n % i == 0: - print(f"{n} is not a Prime Number") - break - else: - print(f"{n} is a Prime Number") + if z < 10: + k = 5 + if y > 5: + k = x+y + else: + k = x-y From 85ea632c7ecc043c05f7a1f3a586dac6b90980ce Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 29 Nov 2023 22:31:54 +0700 Subject: [PATCH 11/61] API: Get All Submissions from Account for one Problem --- .../get_submissions_by_account_problem.py | 23 +++++++++++++++++++ api/serializers.py | 9 +++++++- api/urls.py | 1 + api/views/submission.py | 6 +++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 api/controllers/submission/get_submissions_by_account_problem.py diff --git a/api/controllers/submission/get_submissions_by_account_problem.py b/api/controllers/submission/get_submissions_by_account_problem.py new file mode 100644 index 0000000..cd2d968 --- /dev/null +++ b/api/controllers/submission/get_submissions_by_account_problem.py @@ -0,0 +1,23 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_submissions_by_account_problem(account_id:int,problem_id:int): + submissions = Submission.objects.filter(account=account_id,problem=problem_id) + + result = [] + for submission in submissions: + submission_testcases = SubmissionTestcase.objects.filter(submission=submission) + + serializer = SubmissionSerializer(submission) + submission_testcases_serializer = SubmissionTestcaseSecureSerializer(submission_testcases,many=True) + + result.append({**serializer.data,"testcases":submission_testcases_serializer.data}) + + return Response({"submissions": result},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index ce60c2f..657b892 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -112,4 +112,11 @@ class Meta: class SubmissionTestcaseSecureSerializer(serializers.ModelSerializer): class Meta: model = SubmissionTestcase - fields = ['is_passed','runtime_status'] \ No newline at end of file + fields = ['is_passed','runtime_status'] + +class SubmissionPopulateSubmissionTestcaseSecureSerializer(serializers.ModelSerializer): + # Add testcases field + testcases = SubmissionTestcaseSecureSerializer(many=True) + class Meta: + model = Submission + fields = ['submission_id','problem','submission_code','is_passed','date','score','max_score','passed_ratio','testcases'] \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index 2e46c15..589b51e 100644 --- a/api/urls.py +++ b/api/urls.py @@ -18,6 +18,7 @@ path('problems//',submission.submit_problem_view), path('submissions',submission.all_submission_view), + path("accounts//problems//submissions",submission.submission_account_problem_view), path('accounts//topics',topic.create_topic_view), path('topics',topic.all_topics_view), diff --git a/api/views/submission.py b/api/views/submission.py index 4d834e3..93471fa 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -13,6 +13,8 @@ from ..controllers.submission.submit_problem import * from ..controllers.submission.get_submission_by_quries import * +from ..controllers.submission.get_submissions_by_account_problem import * + @api_view([POST]) def submit_problem_view(request,problem_id,account_id): @@ -21,3 +23,7 @@ def submit_problem_view(request,problem_id,account_id): @api_view([GET]) def all_submission_view(request): return get_submission_by_quries(request) + +@api_view([GET]) +def submission_account_problem_view(request,account_id:int,problem_id:int): + return get_submissions_by_account_problem(account_id,problem_id) \ No newline at end of file From e4ea13b8e7c0de05b310fa1a5af4197c6cc4e84d Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 30 Nov 2023 00:19:01 +0700 Subject: [PATCH 12/61] Submission and get are same path --- .../get_submissions_by_account_problem.py | 11 +++++++++-- api/controllers/submission/submit_problem.py | 2 +- api/urls.py | 4 ++-- api/views/submission.py | 13 ++++++++----- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/api/controllers/submission/get_submissions_by_account_problem.py b/api/controllers/submission/get_submissions_by_account_problem.py index cd2d968..8b51371 100644 --- a/api/controllers/submission/get_submissions_by_account_problem.py +++ b/api/controllers/submission/get_submissions_by_account_problem.py @@ -10,7 +10,11 @@ def get_submissions_by_account_problem(account_id:int,problem_id:int): submissions = Submission.objects.filter(account=account_id,problem=problem_id) + submissions = submissions.order_by('-submission_id') + + best_submission_id = submissions.order_by('-passed_ratio').first().submission_id + best_submission = None result = [] for submission in submissions: submission_testcases = SubmissionTestcase.objects.filter(submission=submission) @@ -18,6 +22,9 @@ def get_submissions_by_account_problem(account_id:int,problem_id:int): serializer = SubmissionSerializer(submission) submission_testcases_serializer = SubmissionTestcaseSecureSerializer(submission_testcases,many=True) - result.append({**serializer.data,"testcases":submission_testcases_serializer.data}) + result.append({**serializer.data,"runtime_output":submission_testcases_serializer.data}) - return Response({"submissions": result},status=status.HTTP_200_OK) \ No newline at end of file + if submission.submission_id == best_submission_id: + best_submission = {**serializer.data,"runtime_output":submission_testcases_serializer.data} + + return Response({"best_submission": best_submission,"submissions": result},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/submission/submit_problem.py b/api/controllers/submission/submit_problem.py index 8252e0b..8afd987 100644 --- a/api/controllers/submission/submit_problem.py +++ b/api/controllers/submission/submit_problem.py @@ -19,7 +19,7 @@ def avaliableQueue(): return i return -1 -def submit_problem(problem_id:int,account_id:int,request): +def submit_problem(account_id:int,problem_id:int,request): global QUEUE problem = Problem.objects.get(problem_id=problem_id) testcases = Testcase.objects.filter(problem=problem) diff --git a/api/urls.py b/api/urls.py index 589b51e..a4643f4 100644 --- a/api/urls.py +++ b/api/urls.py @@ -16,9 +16,9 @@ path('problems',problem.all_problems_view), path('problems/',problem.one_problem_view), - path('problems//',submission.submit_problem_view), + # path('problems//',submission.submit_problem_view), path('submissions',submission.all_submission_view), - path("accounts//problems//submissions",submission.submission_account_problem_view), + path("accounts//problems//submissions",submission.account_problem_submission_view), path('accounts//topics',topic.create_topic_view), path('topics',topic.all_topics_view), diff --git a/api/views/submission.py b/api/views/submission.py index 93471fa..d273292 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -17,13 +17,16 @@ @api_view([POST]) -def submit_problem_view(request,problem_id,account_id): - return submit_problem(problem_id,account_id,request) +def account_problem_submission_view(request,problem_id,account_id): + if request.method == POST: + return submit_problem(account_id,problem_id,request) + if request.method == GET: + return get_submissions_by_account_problem(account_id,problem_id) @api_view([GET]) def all_submission_view(request): return get_submission_by_quries(request) -@api_view([GET]) -def submission_account_problem_view(request,account_id:int,problem_id:int): - return get_submissions_by_account_problem(account_id,problem_id) \ No newline at end of file +# @api_view([GET]) +# def submission_account_problem_view(request,account_id:int,problem_id:int): +# return get_submissions_by_account_problem(account_id,problem_id) \ No newline at end of file From 0c49fb2b453a510caf63e1a1e9753566c5db5fcc Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 30 Nov 2023 17:00:27 +0700 Subject: [PATCH 13/61] Fail on grading (Wrong answer) + GET method for submission --- api/sandbox/grader.py | 2 ++ api/views/submission.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/api/sandbox/grader.py b/api/sandbox/grader.py index b620c21..c06f1e8 100644 --- a/api/sandbox/grader.py +++ b/api/sandbox/grader.py @@ -123,6 +123,8 @@ def grading(self,expected_output:list[str]) -> GradingResultList: output = runtime_result[i].output if forgiveableFormat(runtime_result[i].output) == forgiveableFormat(expected_output[i]): is_passed = True + else: + runtime_result[i].runtime_status = "FAILED" grading_result.append(GradingResult( runtime_result[i].input, diff --git a/api/views/submission.py b/api/views/submission.py index d273292..bc9b52b 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -16,7 +16,7 @@ from ..controllers.submission.get_submissions_by_account_problem import * -@api_view([POST]) +@api_view([POST,GET]) def account_problem_submission_view(request,problem_id,account_id): if request.method == POST: return submit_problem(account_id,problem_id,request) From f0cbe25d2a1a612a9b0c1f4c107a6d74c16de0af Mon Sep 17 00:00:00 2001 From: KanonKC Date: Fri, 1 Dec 2023 15:35:46 +0700 Subject: [PATCH 14/61] Better submission --- .../get_submissions_by_account_problem.py | 21 ++++++++----- api/controllers/submission/submit_problem.py | 9 ++---- api/serializers.py | 4 +-- api/views/script.py | 31 ++++++++++++++----- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/api/controllers/submission/get_submissions_by_account_problem.py b/api/controllers/submission/get_submissions_by_account_problem.py index 8b51371..5c5ff9c 100644 --- a/api/controllers/submission/get_submissions_by_account_problem.py +++ b/api/controllers/submission/get_submissions_by_account_problem.py @@ -10,21 +10,26 @@ def get_submissions_by_account_problem(account_id:int,problem_id:int): submissions = Submission.objects.filter(account=account_id,problem=problem_id) + + if submissions.count() == 0: + return Response({"best_submission": None,"submissions": []},status=status.HTTP_204_NO_CONTENT) + submissions = submissions.order_by('-submission_id') - best_submission_id = submissions.order_by('-passed_ratio').first().submission_id + best_submission_id = submissions.order_by('-passed_ratio','-submission_id').first().submission_id best_submission = None result = [] + for submission in submissions: submission_testcases = SubmissionTestcase.objects.filter(submission=submission) - - serializer = SubmissionSerializer(submission) - submission_testcases_serializer = SubmissionTestcaseSecureSerializer(submission_testcases,many=True) - - result.append({**serializer.data,"runtime_output":submission_testcases_serializer.data}) + submission.runtime_output = submission_testcases + result.append(submission) if submission.submission_id == best_submission_id: - best_submission = {**serializer.data,"runtime_output":submission_testcases_serializer.data} + best_submission = submission + + best_submission_serializer = SubmissionPopulateSubmissionTestcaseSecureSerializer(best_submission) + submissions_serializer = SubmissionPopulateSubmissionTestcaseSecureSerializer(result,many=True) - return Response({"best_submission": best_submission,"submissions": result},status=status.HTTP_200_OK) \ No newline at end of file + return Response({"best_submission": best_submission_serializer.data,"submissions": submissions_serializer.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/submission/submit_problem.py b/api/controllers/submission/submit_problem.py index 8afd987..07437a4 100644 --- a/api/controllers/submission/submit_problem.py +++ b/api/controllers/submission/submit_problem.py @@ -67,10 +67,7 @@ def submit_problem(account_id:int,problem_id:int,request): SubmissionTestcase.objects.bulk_create(submission_testcases) - submission_serialize = SubmissionPoplulateProblemSecureSerializer(submission) - testcases_serialize = SubmissionTestcaseSecureSerializer(submission_testcases,many=True) + submission.runtime_output = submission_testcases + testser = SubmissionPopulateSubmissionTestcaseSecureSerializer(submission) - return Response({ - **submission_serialize.data, - "runtime_output": testcases_serialize.data - },status=status.HTTP_201_CREATED) \ No newline at end of file + return Response(testser.data,status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 657b892..e333d49 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -116,7 +116,7 @@ class Meta: class SubmissionPopulateSubmissionTestcaseSecureSerializer(serializers.ModelSerializer): # Add testcases field - testcases = SubmissionTestcaseSecureSerializer(many=True) + runtime_output = SubmissionTestcaseSecureSerializer(many=True) class Meta: model = Submission - fields = ['submission_id','problem','submission_code','is_passed','date','score','max_score','passed_ratio','testcases'] \ No newline at end of file + fields = ['submission_id','problem','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] \ No newline at end of file diff --git a/api/views/script.py b/api/views/script.py index 50c338b..cd335f8 100644 --- a/api/views/script.py +++ b/api/views/script.py @@ -8,16 +8,31 @@ from ..serializers import * +# @api_view([POST]) +# def run_script(request): +# submissions = Submission.objects.all() +# total = len(submissions) +# count = 0 +# for submission in submissions: +# submission.score = submission.result.count('P') +# submission.max_score = len(submission.result) +# submission.passed_ratio = submission.score/submission.max_score +# submission.save() +# count += 1 +# print(f"({count}/{total})") +# return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) + @api_view([POST]) def run_script(request): - submissions = Submission.objects.all() - total = len(submissions) + submissionTestcases = SubmissionTestcase.objects.all() + + total = len(submissionTestcases) count = 0 - for submission in submissions: - submission.score = submission.result.count('P') - submission.max_score = len(submission.result) - submission.passed_ratio = submission.score/submission.max_score - submission.save() + for testcase in submissionTestcases: + if testcase.runtime_status == "OK" and (not testcase.is_passed): + testcase.runtime_status = "FAILED" + testcase.save() count += 1 + print(f"({count}/{total})") - return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) \ No newline at end of file + return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) From 78affbda97eef0bc415f95900301127be078fe49 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 2 Dec 2023 01:09:54 +0700 Subject: [PATCH 15/61] Fix: submission type + test program files --- .../problem/get_all_problems_by_account.py | 14 +++++++++++ api/controllers/problem/validate_program.py | 23 +++++++++++++++++++ api/models.py | 1 + api/sandbox/section1/runner.c | 9 ++++++++ api/serializers.py | 5 ++++ api/urls.py | 3 ++- api/views/problem.py | 18 +++++++++++---- tests/many_line_program.py | 22 ++++++++++++++++++ tests/one_line.c | 1 + tests/program1.py | 11 +++++++++ tests/tempCodeRunnerFile.c | 1 + 11 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 api/controllers/problem/get_all_problems_by_account.py create mode 100644 api/controllers/problem/validate_program.py create mode 100644 api/sandbox/section1/runner.c create mode 100644 tests/many_line_program.py create mode 100644 tests/one_line.c create mode 100644 tests/program1.py create mode 100644 tests/tempCodeRunnerFile.c diff --git a/api/controllers/problem/get_all_problems_by_account.py b/api/controllers/problem/get_all_problems_by_account.py new file mode 100644 index 0000000..4a2908d --- /dev/null +++ b/api/controllers/problem/get_all_problems_by_account.py @@ -0,0 +1,14 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_problems_by_account(account_id:int): + problems = Problem.objects.filter(creator=account_id) + problem_ser = ProblemSerializer(problems,many=True) + return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/problem/validate_program.py b/api/controllers/problem/validate_program.py new file mode 100644 index 0000000..d8298e8 --- /dev/null +++ b/api/controllers/problem/validate_program.py @@ -0,0 +1,23 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import Grader,ProgramGrader,RuntimeResultList +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def validate_program(request): + grader:ProgramGrader = Grader[request.data['language']] + result:RuntimeResultList = grader(request.data['source_code'],request.data['testcases'],1,request.data['time_limited']).generate_output() + + print(result.getResult()) + print(result.runnable) + + return Response({ + 'runnable': result.runnable, + 'has_error': result.has_error, + 'has_timeout': result.has_timeout, + 'runtime_results': result.getResult(), + },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/models.py b/api/models.py index 0bb1ab1..b9ea17c 100644 --- a/api/models.py +++ b/api/models.py @@ -36,6 +36,7 @@ class Problem(models.Model): is_active = models.BooleanField(default=True,blank=True) is_private = models.BooleanField(default=False,blank=True) submission_regex = models.CharField(max_length=1000,null=True,blank=True,default=".*") + class Testcase(models.Model): testcase_id = models.AutoField(primary_key=True) diff --git a/api/sandbox/section1/runner.c b/api/sandbox/section1/runner.c new file mode 100644 index 0000000..bcaa3db --- /dev/null +++ b/api/sandbox/section1/runner.c @@ -0,0 +1,9 @@ +#include + +int main() { + int x,y; + scanf("%d",&x); + scanf("%d",&y); + printf("%d",x+y); + return 0; +} \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index e333d49..54e98ca 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -43,6 +43,11 @@ class Meta: model = Problem fields = "__all__" +class ProblemSecureSerializer(serializers.ModelSerializer): + class Meta: + model = Problem + fields = ['problem_id','title','description','is_active','is_private'] + class ProblemPopulateAccountSerializer(serializers.ModelSerializer): creator = AccountSecureSerializer() class Meta: diff --git a/api/urls.py b/api/urls.py index a4643f4..d03a5ef 100644 --- a/api/urls.py +++ b/api/urls.py @@ -12,7 +12,7 @@ path("accounts//daily-submissions",account.get_daily_submission), path("accounts//password",account.change_password), - path('accounts//problems',problem.create_problem_view), + path('accounts//problems',problem.all_problems_account_view), path('problems',problem.all_problems_view), path('problems/',problem.one_problem_view), @@ -32,4 +32,5 @@ path('collections//problems/',collection.collection_problems_view), path('script',script.run_script), + path('problems/validate',problem.validation_view), ] \ No newline at end of file diff --git a/api/views/problem.py b/api/views/problem.py index 092045b..ab34ed1 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -14,11 +14,16 @@ from ..controllers.problem.get_problem import * from ..controllers.problem.get_all_problems import * from ..controllers.problem.remove_bulk_problems import * +from ..controllers.problem.get_all_problems_by_account import * +from ..controllers.problem.validate_program import * # Create your views here. -@api_view([POST]) -def create_problem_view(request,account_id): - return create_problem(account_id,request) +@api_view([POST,GET]) +def all_problems_account_view(request,account_id): + if request.method == POST: + return create_problem(account_id,request) + if request.method == GET: + return get_all_problems_by_account(account_id) @api_view([GET,DELETE]) def all_problems_view(request): @@ -34,4 +39,9 @@ def one_problem_view(request,problem_id: int): elif request.method == PUT: return update_problem(problem_id,request) elif request.method == DELETE: - return delete_problem(problem_id) \ No newline at end of file + return delete_problem(problem_id) + +@api_view([POST]) +def validation_view(request): + if request.method == POST: + return validate_program(request) \ No newline at end of file diff --git a/tests/many_line_program.py b/tests/many_line_program.py new file mode 100644 index 0000000..5724282 --- /dev/null +++ b/tests/many_line_program.py @@ -0,0 +1,22 @@ +text = input("Text: ") +h = int(input("Height: ")) + +for i in range(h): + print(f"{' '*i}{text}") + +''' +asdfghjkl +10 +::: +kheeojg +7 +::: +aaaaaaaaaaaa +5 +::: +oiuhnmkij +20 +::: +z +99 +''' diff --git a/tests/one_line.c b/tests/one_line.c new file mode 100644 index 0000000..e1b4f7c --- /dev/null +++ b/tests/one_line.c @@ -0,0 +1 @@ +int main(){int x;scanf("%d", &x);printf("%d\n", x);return 0;} \ No newline at end of file diff --git a/tests/program1.py b/tests/program1.py new file mode 100644 index 0000000..c224d67 --- /dev/null +++ b/tests/program1.py @@ -0,0 +1,11 @@ +x = input() +print(x) + + +''' +1 +::: +2 +::: +3 +''' \ No newline at end of file diff --git a/tests/tempCodeRunnerFile.c b/tests/tempCodeRunnerFile.c new file mode 100644 index 0000000..e1b4f7c --- /dev/null +++ b/tests/tempCodeRunnerFile.c @@ -0,0 +1 @@ +int main(){int x;scanf("%d", &x);printf("%d\n", x);return 0;} \ No newline at end of file From 30217528bd0f1926afa9cca4405cae3e4a679229 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 2 Dec 2023 18:51:12 +0700 Subject: [PATCH 16/61] Add runtime_status to Testcase model --- api/controllers/problem/create_problem.py | 5 +++-- .../0030_testcase_runtime_status.py | 19 +++++++++++++++++++ api/models.py | 1 + api/sandbox/section1/runner.c | 10 +--------- 4 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 api/migrations/0030_testcase_runtime_status.py diff --git a/api/controllers/problem/create_problem.py b/api/controllers/problem/create_problem.py index d3c2839..65e590f 100644 --- a/api/controllers/problem/create_problem.py +++ b/api/controllers/problem/create_problem.py @@ -1,7 +1,7 @@ from api.utility import passwordEncryption from rest_framework.response import Response from rest_framework.decorators import api_view -from api.sandbox.grader import PythonGrader +from api.sandbox.grader import PythonGrader,RuntimeResult from ...constant import GET,POST,PUT,DELETE from ...models import * from rest_framework import status @@ -32,7 +32,8 @@ def create_problem(account_id:int,request): Testcase( problem = problem, input = unit.input, - output = unit.output + output = unit.output, + runtime_status = unit.runtime_status )) Testcase.objects.bulk_create(testcases_result) diff --git a/api/migrations/0030_testcase_runtime_status.py b/api/migrations/0030_testcase_runtime_status.py new file mode 100644 index 0000000..e3f7f56 --- /dev/null +++ b/api/migrations/0030_testcase_runtime_status.py @@ -0,0 +1,19 @@ +# Generated by Django 4.1.2 on 2023-12-02 08:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0029_remove_account_is_admin_remove_collection_owner_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='testcase', + name='runtime_status', + field=models.CharField(default='OK', max_length=10), + preserve_default=False, + ), + ] diff --git a/api/models.py b/api/models.py index b9ea17c..33bf53c 100644 --- a/api/models.py +++ b/api/models.py @@ -43,6 +43,7 @@ class Testcase(models.Model): problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") input = models.CharField(max_length=100000) output = models.CharField(max_length=100000) + runtime_status = models.CharField(max_length=10) class Submission(models.Model): submission_id = models.AutoField(primary_key=True) diff --git a/api/sandbox/section1/runner.c b/api/sandbox/section1/runner.c index bcaa3db..5df7157 100644 --- a/api/sandbox/section1/runner.c +++ b/api/sandbox/section1/runner.c @@ -1,9 +1 @@ -#include - -int main() { - int x,y; - scanf("%d",&x); - scanf("%d",&y); - printf("%d",x+y); - return 0; -} \ No newline at end of file +int main(){int x;scanf("%d", &x);printf("%d\n", x*10);return 0;} \ No newline at end of file From 39197ec0302e195fcbd0a7972fe45d022e28daf4 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 2 Dec 2023 23:39:09 +0700 Subject: [PATCH 17/61] Spare vite origin --- Backend/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Backend/settings.py b/Backend/settings.py index 3a7ee8e..deb18fb 100644 --- a/Backend/settings.py +++ b/Backend/settings.py @@ -42,6 +42,7 @@ "http://localhost:3000", "http://localhost:4000", "http://localhost:5173", + "http://localhost:5174", "http://localhost:3001", "http://192.168.216.250:3000", "http://192.168.0.2:3000", From d5a383400932df33104b0d8009411b862bb82f48 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 3 Dec 2023 00:11:20 +0700 Subject: [PATCH 18/61] Problem -> create/update date and sort all problems by update date --- .../problem/get_all_problems_by_account.py | 4 +++- api/controllers/problem/update_problem.py | 3 +++ ...oblem_created_date_problem_updated_date.py | 24 +++++++++++++++++++ api/models.py | 2 ++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 api/migrations/0031_problem_created_date_problem_updated_date.py diff --git a/api/controllers/problem/get_all_problems_by_account.py b/api/controllers/problem/get_all_problems_by_account.py index 4a2908d..ca2c270 100644 --- a/api/controllers/problem/get_all_problems_by_account.py +++ b/api/controllers/problem/get_all_problems_by_account.py @@ -9,6 +9,8 @@ from ...serializers import * def get_all_problems_by_account(account_id:int): - problems = Problem.objects.filter(creator=account_id) + problems = Problem.objects.filter(creator=account_id).order_by('-updated_date') problem_ser = ProblemSerializer(problems,many=True) + + return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/problem/update_problem.py b/api/controllers/problem/update_problem.py index 203ae2a..f26956d 100644 --- a/api/controllers/problem/update_problem.py +++ b/api/controllers/problem/update_problem.py @@ -7,6 +7,7 @@ from rest_framework import status from django.forms.models import model_to_dict from ...serializers import * +from django.utils import timezone def update_problem(problem_id:int,request): try: @@ -22,6 +23,8 @@ def update_problem(problem_id:int,request): problem.time_limit = request.data.get("time_limit",problem.time_limit) problem.is_private = request.data.get("is_private",problem.is_private) + problem.updated_date = timezone.now() + if 'testcases' in request.data: running_result = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() diff --git a/api/migrations/0031_problem_created_date_problem_updated_date.py b/api/migrations/0031_problem_created_date_problem_updated_date.py new file mode 100644 index 0000000..1e59ee1 --- /dev/null +++ b/api/migrations/0031_problem_created_date_problem_updated_date.py @@ -0,0 +1,24 @@ +# Generated by Django 4.1.2 on 2023-12-02 17:00 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0030_testcase_runtime_status'), + ] + + operations = [ + migrations.AddField( + model_name='problem', + name='created_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AddField( + model_name='problem', + name='updated_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/api/models.py b/api/models.py index 33bf53c..4f124bf 100644 --- a/api/models.py +++ b/api/models.py @@ -36,6 +36,8 @@ class Problem(models.Model): is_active = models.BooleanField(default=True,blank=True) is_private = models.BooleanField(default=False,blank=True) submission_regex = models.CharField(max_length=1000,null=True,blank=True,default=".*") + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) class Testcase(models.Model): From f9f4928f073a6da65334948a4694eb30eac8a06a Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 4 Dec 2023 11:22:52 +0700 Subject: [PATCH 19/61] MOD-67,76: Submission handle many language --- api/controllers/submission/submit_problem.py | 6 ++++-- api/migrations/0032_submission_language.py | 19 +++++++++++++++++++ api/models.py | 1 + api/sandbox/grader.py | 18 ++++++++++++------ api/sandbox/section1/runner.c | 6 +++++- api/sandbox/section1/runner.cpp | 6 ++++++ api/serializers.py | 2 +- 7 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 api/migrations/0032_submission_language.py create mode 100644 api/sandbox/section1/runner.cpp diff --git a/api/controllers/submission/submit_problem.py b/api/controllers/submission/submit_problem.py index 07437a4..cd68273 100644 --- a/api/controllers/submission/submit_problem.py +++ b/api/controllers/submission/submit_problem.py @@ -1,7 +1,7 @@ from api.utility import passwordEncryption from rest_framework.response import Response from rest_framework.decorators import api_view -from api.sandbox.grader import PythonGrader +from api.sandbox.grader import PythonGrader,Grader,ProgramGrader from ...constant import GET,POST,PUT,DELETE from ...models import * from rest_framework import status @@ -38,7 +38,8 @@ def submit_problem(account_id:int,problem_id:int,request): QUEUE[empty_queue] = 1 # grading_result = grader.grading(empty_queue+1,submission_code,solution_input,solution_output) - grading_result = PythonGrader(submission_code,solution_input,empty_queue+1,1.5).grading(solution_output) + grader: ProgramGrader = Grader[request.data['language']] + grading_result = grader(submission_code,solution_input,empty_queue+1,1.5).grading(solution_output) QUEUE[empty_queue] = 0 total_score = sum([i.is_passed for i in grading_result.data if i.is_passed]) @@ -47,6 +48,7 @@ def submit_problem(account_id:int,problem_id:int,request): submission = Submission( problem = problem, account = Account.objects.get(account_id=account_id), + language = request.data['language'], submission_code = request.data['submission_code'], is_passed = grading_result.is_passed, score = total_score, diff --git a/api/migrations/0032_submission_language.py b/api/migrations/0032_submission_language.py new file mode 100644 index 0000000..2b040a3 --- /dev/null +++ b/api/migrations/0032_submission_language.py @@ -0,0 +1,19 @@ +# Generated by Django 4.1.2 on 2023-12-03 13:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0031_problem_created_date_problem_updated_date'), + ] + + operations = [ + migrations.AddField( + model_name='submission', + name='language', + field=models.CharField(default='python', max_length=15), + preserve_default=False, + ), + ] diff --git a/api/models.py b/api/models.py index 4f124bf..35ba146 100644 --- a/api/models.py +++ b/api/models.py @@ -51,6 +51,7 @@ class Submission(models.Model): submission_id = models.AutoField(primary_key=True) problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") + language = models.CharField(max_length=15) submission_code = models.CharField(max_length=20000) is_passed = models.BooleanField() date = models.DateTimeField(default=timezone.now) diff --git a/api/sandbox/grader.py b/api/sandbox/grader.py index c06f1e8..4555f90 100644 --- a/api/sandbox/grader.py +++ b/api/sandbox/grader.py @@ -100,14 +100,20 @@ def runtime(self) -> list[RuntimeResult]: pass def generate_output(self) -> RuntimeResultList: - self.setup() - self.compile() - return RuntimeResultList(self.runtime()) + try: + self.setup() + self.compile() + return RuntimeResultList(self.runtime()) + except Exception as e: + return RuntimeResultList([RuntimeResult(testcase,None,"ERROR") for testcase in self.testcases]) def grading(self,expected_output:list[str]) -> GradingResultList: - self.setup() - self.compile() - runtime_result = self.runtime() + try: + self.setup() + self.compile() + runtime_result = self.runtime() + except: + runtime_result = [RuntimeResult(testcase,None,"ERROR") for testcase in self.testcases] if len(runtime_result) != len(expected_output): raise Exception("Length of expected output and runtime result is not equal") diff --git a/api/sandbox/section1/runner.c b/api/sandbox/section1/runner.c index 5df7157..207357b 100644 --- a/api/sandbox/section1/runner.c +++ b/api/sandbox/section1/runner.c @@ -1 +1,5 @@ -int main(){int x;scanf("%d", &x);printf("%d\n", x*10);return 0;} \ No newline at end of file +#include + +int main() { + printf("Hello World!\n"); +} \ No newline at end of file diff --git a/api/sandbox/section1/runner.cpp b/api/sandbox/section1/runner.cpp new file mode 100644 index 0000000..2999e16 --- /dev/null +++ b/api/sandbox/section1/runner.cpp @@ -0,0 +1,6 @@ +#include +using namespace std; + +int main() { + cout << "Hello World!\n"; +} \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 54e98ca..936a07a 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -124,4 +124,4 @@ class SubmissionPopulateSubmissionTestcaseSecureSerializer(serializers.ModelSeri runtime_output = SubmissionTestcaseSecureSerializer(many=True) class Meta: model = Submission - fields = ['submission_id','problem','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] \ No newline at end of file + fields = ['submission_id','problem','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] \ No newline at end of file From ff6212670fcd2d0fbb80cc2cb8a5f45616b800f1 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 4 Dec 2023 20:07:55 +0700 Subject: [PATCH 20/61] Updated Collection API --- .../collection/add_problems_to_collection.py | 6 ++--- .../collection/create_collection.py | 4 +-- .../get_all_collections_by_account.py | 26 +++++++++++++++++++ api/controllers/collection/get_collection.py | 15 ++++++----- api/serializers.py | 6 +++++ api/urls.py | 2 +- api/views/collection.py | 17 ++++++++---- 7 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 api/controllers/collection/get_all_collections_by_account.py diff --git a/api/controllers/collection/add_problems_to_collection.py b/api/controllers/collection/add_problems_to_collection.py index 1bf6eb6..048edd7 100644 --- a/api/controllers/collection/add_problems_to_collection.py +++ b/api/controllers/collection/add_problems_to_collection.py @@ -27,12 +27,12 @@ def add_problems_to_collection(collection:Collection,request): ) collection_problem.save() index += 1 - cp_serialize = CollectionProblemSerializer(collection_problem) - populated_problems.append(cp_serialize.data) + populated_problems.append(collection_problem) + problem_serialize = CollectionProblemPopulateProblemSecureSerializer(populated_problems,many=True) collection_serialize = CollectionSerializer(collection) return Response({ **collection_serialize.data, - 'problems': populated_problems + 'problems': problem_serialize.data },status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/controllers/collection/create_collection.py b/api/controllers/collection/create_collection.py index 96da548..8894516 100644 --- a/api/controllers/collection/create_collection.py +++ b/api/controllers/collection/create_collection.py @@ -9,8 +9,8 @@ from ...serializers import * def create_collection(account_id:int,request): - request.data['owner'] = account_id - + + request.data['creator'] = account_id serialize = CollectionSerializer(data=request.data) if serialize.is_valid(): diff --git a/api/controllers/collection/get_all_collections_by_account.py b/api/controllers/collection/get_all_collections_by_account.py new file mode 100644 index 0000000..be5d7f9 --- /dev/null +++ b/api/controllers/collection/get_all_collections_by_account.py @@ -0,0 +1,26 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_collections_by_account(account_id:int): + collections = Collection.objects.filter(creator=account_id) + problemCollections = CollectionProblem.objects.filter(collection__in=collections) + + populated_collections = [] + for collection in collections: + con_probs = problemCollections.filter(collection=collection) + serialize = CollectionSerializer(collection) + collection_data = serialize.data + collection_data['problems'] = CollectionProblemPopulateProblemSecureSerializer(con_probs,many=True).data + + populated_collections.append(collection_data) + + return Response({ + 'collections': populated_collections + },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/collection/get_collection.py b/api/controllers/collection/get_collection.py index 34f639b..1814b0c 100644 --- a/api/controllers/collection/get_collection.py +++ b/api/controllers/collection/get_collection.py @@ -12,16 +12,17 @@ def get_collection(collection_id:int): collection = Collection.objects.get(collection_id=collection_id) # problems = Problem.objects.filter(collectionproblem__collection_id=collection_id) - collectionProblems = CollectionProblem.objects.filter(collection=collection) + collectionProblems = CollectionProblem.objects.filter(collection=collection).order_by('order') collection_ser = CollectionSerializer(collection) - populated_problems = [] - for col_prob in collectionProblems: - col_prob_serialize = CollectionProblemSerializer(col_prob) - prob_serialize = ProblemSerializer(col_prob.problem) - populated_problems.append({**col_prob_serialize.data,**prob_serialize.data}) + collectionProblems_ser = CollectionProblemPopulateProblemSecureSerializer(collectionProblems,many=True) + # populated_problems = [] + # for col_prob in collectionProblems: + # col_prob_serialize = CollectionProblemPopulateProblemSecureSerializer(col_prob) + # # prob_serialize = ProblemSerializer(col_prob.problem) + # populated_problems.append(col_prob_serialize.data) return Response({ **collection_ser.data, - 'problems': sorted(populated_problems,key=lambda problem: problem['order']) + 'problems': collectionProblems_ser.data } ,status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 936a07a..d312138 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -64,6 +64,12 @@ class Meta: model = CollectionProblem fields = "__all__" +class CollectionProblemPopulateProblemSecureSerializer(serializers.ModelSerializer): + problem = ProblemSecureSerializer() + class Meta: + model = CollectionProblem + fields = "__all__" + class CollectionSerializer(serializers.ModelSerializer): class Meta: model = Collection diff --git a/api/urls.py b/api/urls.py index d03a5ef..8cf70bd 100644 --- a/api/urls.py +++ b/api/urls.py @@ -26,7 +26,7 @@ path('topics//access',topic.account_access), path('topics//collections/',topic.topic_collections_view), - path('accounts//collections',collection.create_collection_view), + path('accounts//collections',collection.account_collections_view), path('collections',collection.all_collections_view), path('collections/',collection.one_collection_view), path('collections//problems/',collection.collection_problems_view), diff --git a/api/views/collection.py b/api/views/collection.py index b8cdbf4..747bab8 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -15,11 +15,15 @@ from ..controllers.collection.delete_collection import * from ..controllers.collection.add_problems_to_collection import * from ..controllers.collection.remove_problems_from_collection import * +from ..controllers.collection.get_all_collections_by_account import * -@api_view([POST]) -def create_collection_view(request,account_id:int): - return create_collection(account_id,request) +@api_view([POST,GET]) +def account_collections_view(request,account_id:int): + if request.method == POST: + return create_collection(account_id,request) + if request.method == GET: + return get_all_collections_by_account(account_id) @api_view([GET]) def all_collections_view(request): @@ -36,7 +40,10 @@ def one_collection_view(request,collection_id:int): @api_view([PUT]) def collection_problems_view(request,collection_id:int,method:str): + + collection = Collection.objects.get(collection_id=collection_id) + if method == "add": - return add_problems_to_collection(collection_id,request) + return add_problems_to_collection(collection,request) if method == "remove": - return remove_problems_from_collection(collection_id,request) \ No newline at end of file + return remove_problems_from_collection(collection,request) \ No newline at end of file From 86b2817f5c7470c270d50395b2e487bb9b70b679 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 6 Dec 2023 00:30:59 +0700 Subject: [PATCH 21/61] ProblemSecureSerializer also provide created/updated time --- api/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/serializers.py b/api/serializers.py index d312138..f8735d4 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -46,7 +46,7 @@ class Meta: class ProblemSecureSerializer(serializers.ModelSerializer): class Meta: model = Problem - fields = ['problem_id','title','description','is_active','is_private'] + fields = ['problem_id','title','description','is_active','is_private','updated_date','created_date'] class ProblemPopulateAccountSerializer(serializers.ModelSerializer): creator = AccountSecureSerializer() From 29d35ea17a3c9989cc6e129edcb649e0f1913b64 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 6 Dec 2023 23:51:18 +0700 Subject: [PATCH 22/61] Draft: All problem with best submission --- .../get_all_problem_with_best_submission.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 api/controllers/problem/get_all_problem_with_best_submission.py diff --git a/api/controllers/problem/get_all_problem_with_best_submission.py b/api/controllers/problem/get_all_problem_with_best_submission.py new file mode 100644 index 0000000..fc4ac17 --- /dev/null +++ b/api/controllers/problem/get_all_problem_with_best_submission.py @@ -0,0 +1,17 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_problem_with_best_submission(account_id:int): + problems = Problem.objects.all().order_by('-updated_date') + + pass + + + # return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) \ No newline at end of file From 0e3b1c5f4cddc0b367c2832a0b7f47f992190338 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 7 Dec 2023 16:07:29 +0700 Subject: [PATCH 23/61] Explore problems api --- .../get_all_problem_with_best_submission.py | 14 +++++++++++++- api/serializers.py | 11 ++++++++++- api/views/problem.py | 3 ++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/api/controllers/problem/get_all_problem_with_best_submission.py b/api/controllers/problem/get_all_problem_with_best_submission.py index fc4ac17..f0e8e12 100644 --- a/api/controllers/problem/get_all_problem_with_best_submission.py +++ b/api/controllers/problem/get_all_problem_with_best_submission.py @@ -9,9 +9,21 @@ from ...serializers import * def get_all_problem_with_best_submission(account_id:int): + problems = Problem.objects.all().order_by('-updated_date') + + for problem in problems: + best_submission = Submission.objects.filter(problem_id=problem.problem_id).order_by('-score').first() + if not (best_submission is None): + testcases = SubmissionTestcase.objects.filter(submission_id=best_submission.submission_id) + + best_submission.runtime_output = testcases + problem.best_submission = best_submission + else: + problem.best_submission = None - pass + problem_ser = ProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(problems,many=True) + return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) # return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index f8735d4..ec5dbff 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -43,6 +43,7 @@ class Meta: model = Problem fields = "__all__" +problem_secure_fields = ['problem_id','title','description','is_active','is_private','updated_date','created_date'] class ProblemSecureSerializer(serializers.ModelSerializer): class Meta: model = Problem @@ -130,4 +131,12 @@ class SubmissionPopulateSubmissionTestcaseSecureSerializer(serializers.ModelSeri runtime_output = SubmissionTestcaseSecureSerializer(many=True) class Meta: model = Submission - fields = ['submission_id','problem','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] \ No newline at end of file + fields = ['submission_id','problem','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] + +class ProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): + # Add testcases field + creator = AccountSecureSerializer() + best_submission = SubmissionPopulateSubmissionTestcaseSecureSerializer() + class Meta: + model = Problem + fields = problem_secure_fields + ['best_submission','creator'] \ No newline at end of file diff --git a/api/views/problem.py b/api/views/problem.py index ab34ed1..beff57a 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -16,6 +16,7 @@ from ..controllers.problem.remove_bulk_problems import * from ..controllers.problem.get_all_problems_by_account import * from ..controllers.problem.validate_program import * +from ..controllers.problem.get_all_problem_with_best_submission import * # Create your views here. @api_view([POST,GET]) @@ -28,7 +29,7 @@ def all_problems_account_view(request,account_id): @api_view([GET,DELETE]) def all_problems_view(request): if request.method == GET: - return get_all_problems(request) + return get_all_problem_with_best_submission(request) elif request.method == DELETE: return remove_bulk_problems(request) From cb203e435bbe87db589282acf1ee3498cb3da4cf Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 10 Dec 2023 01:10:52 +0700 Subject: [PATCH 24/61] Best submission sorted by passed_ratio + sub_id --- api/controllers/problem/get_all_problem_with_best_submission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/controllers/problem/get_all_problem_with_best_submission.py b/api/controllers/problem/get_all_problem_with_best_submission.py index f0e8e12..437c40c 100644 --- a/api/controllers/problem/get_all_problem_with_best_submission.py +++ b/api/controllers/problem/get_all_problem_with_best_submission.py @@ -13,7 +13,7 @@ def get_all_problem_with_best_submission(account_id:int): problems = Problem.objects.all().order_by('-updated_date') for problem in problems: - best_submission = Submission.objects.filter(problem_id=problem.problem_id).order_by('-score').first() + best_submission = Submission.objects.filter(problem_id=problem.problem_id).order_by('-passed_ratio','-submission_id').first() if not (best_submission is None): testcases = SubmissionTestcase.objects.filter(submission_id=best_submission.submission_id) From 5bb807276e503fbdb393d593acc954d8a64d68b9 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 10 Dec 2023 17:39:47 +0700 Subject: [PATCH 25/61] Fix: Submission missing after problem updated --- .../get_all_problem_with_best_submission.py | 7 ++++--- api/controllers/problem/update_problem.py | 2 +- .../0033_alter_submissiontestcase_testcase.py | 19 ++++++++++++++++++ .../0034_alter_submissiontestcase_testcase.py | 20 +++++++++++++++++++ 4 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 api/migrations/0033_alter_submissiontestcase_testcase.py create mode 100644 api/migrations/0034_alter_submissiontestcase_testcase.py diff --git a/api/controllers/problem/get_all_problem_with_best_submission.py b/api/controllers/problem/get_all_problem_with_best_submission.py index 437c40c..f2d6741 100644 --- a/api/controllers/problem/get_all_problem_with_best_submission.py +++ b/api/controllers/problem/get_all_problem_with_best_submission.py @@ -13,10 +13,11 @@ def get_all_problem_with_best_submission(account_id:int): problems = Problem.objects.all().order_by('-updated_date') for problem in problems: - best_submission = Submission.objects.filter(problem_id=problem.problem_id).order_by('-passed_ratio','-submission_id').first() + best_submission = Submission.objects.filter(problem=problem).order_by('-passed_ratio','-submission_id').first() + print(problem.problem_id,problem.title) if not (best_submission is None): - testcases = SubmissionTestcase.objects.filter(submission_id=best_submission.submission_id) - + testcases = SubmissionTestcase.objects.filter(submission=best_submission) + print(testcases) best_submission.runtime_output = testcases problem.best_submission = best_submission else: diff --git a/api/controllers/problem/update_problem.py b/api/controllers/problem/update_problem.py index f26956d..70e4e63 100644 --- a/api/controllers/problem/update_problem.py +++ b/api/controllers/problem/update_problem.py @@ -31,7 +31,7 @@ def update_problem(problem_id:int,request): if not running_result.runnable: return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) - testcases.delete() + # testcases.delete() testcase_result = [] for unit in running_result.data: testcase = Testcase( diff --git a/api/migrations/0033_alter_submissiontestcase_testcase.py b/api/migrations/0033_alter_submissiontestcase_testcase.py new file mode 100644 index 0000000..cd38403 --- /dev/null +++ b/api/migrations/0033_alter_submissiontestcase_testcase.py @@ -0,0 +1,19 @@ +# Generated by Django 4.1.2 on 2023-12-10 03:59 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0032_submission_language'), + ] + + operations = [ + migrations.AlterField( + model_name='submissiontestcase', + name='testcase', + field=models.ForeignKey(db_column='testcase_id', null=True, on_delete=django.db.models.deletion.SET_NULL, to='api.testcase'), + ), + ] diff --git a/api/migrations/0034_alter_submissiontestcase_testcase.py b/api/migrations/0034_alter_submissiontestcase_testcase.py new file mode 100644 index 0000000..8ad6b26 --- /dev/null +++ b/api/migrations/0034_alter_submissiontestcase_testcase.py @@ -0,0 +1,20 @@ +# Generated by Django 4.1.2 on 2023-12-10 04:00 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0033_alter_submissiontestcase_testcase'), + ] + + operations = [ + migrations.AlterField( + model_name='submissiontestcase', + name='testcase', + field=models.ForeignKey(db_column='testcase_id', default=1, on_delete=django.db.models.deletion.CASCADE, to='api.testcase'), + preserve_default=False, + ), + ] From c077858c73bb60be5572ed1b8b65f241341f850a Mon Sep 17 00:00:00 2001 From: KanonKC Date: Tue, 12 Dec 2023 01:59:35 +0700 Subject: [PATCH 26/61] Deprecated testcases --- .../problem/get_all_problems_by_account.py | 6 ++++-- api/controllers/problem/get_problem.py | 2 +- api/controllers/problem/update_problem.py | 10 +++++++--- api/controllers/submission/submit_problem.py | 2 +- api/migrations/0035_testcase_depricated.py | 18 +++++++++++++++++ ...6_rename_depricated_testcase_deprecated.py | 18 +++++++++++++++++ api/models.py | 1 + api/serializers.py | 20 +++++++++++++++++++ 8 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 api/migrations/0035_testcase_depricated.py create mode 100644 api/migrations/0036_rename_depricated_testcase_deprecated.py diff --git a/api/controllers/problem/get_all_problems_by_account.py b/api/controllers/problem/get_all_problems_by_account.py index ca2c270..bae9918 100644 --- a/api/controllers/problem/get_all_problems_by_account.py +++ b/api/controllers/problem/get_all_problems_by_account.py @@ -10,7 +10,9 @@ def get_all_problems_by_account(account_id:int): problems = Problem.objects.filter(creator=account_id).order_by('-updated_date') - problem_ser = ProblemSerializer(problems,many=True) - + for problem in problems: + problem.testcases = Testcase.objects.filter(problem=problem,deprecated=False) + + problem_ser = ProblemPopulateTestcaseSerializer(problems,many=True) return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/problem/get_problem.py b/api/controllers/problem/get_problem.py index 7a70541..56f78f8 100644 --- a/api/controllers/problem/get_problem.py +++ b/api/controllers/problem/get_problem.py @@ -13,7 +13,7 @@ def get_problem(problem_id:int): problem = Problem.objects.get(problem_id=problem_id) except Problem.DoesNotExist: return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) - testcases = Testcase.objects.filter(problem_id=problem_id) + testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) problem_serialize = ProblemPopulateAccountSerializer(problem) testcases_serialize = TestcaseSerializer(testcases,many=True) return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_200_OK) diff --git a/api/controllers/problem/update_problem.py b/api/controllers/problem/update_problem.py index 70e4e63..5557640 100644 --- a/api/controllers/problem/update_problem.py +++ b/api/controllers/problem/update_problem.py @@ -14,7 +14,7 @@ def update_problem(problem_id:int,request): problem = Problem.objects.get(problem_id=problem_id) except Problem.DoesNotExist: return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) - testcases = Testcase.objects.filter(problem_id=problem_id) + testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) problem.title = request.data.get("title",problem.title) problem.language = request.data.get("language",problem.language) @@ -30,14 +30,18 @@ def update_problem(problem_id:int,request): if not running_result.runnable: return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) + + for testcase in testcases: + testcase.deprecated = True + testcase.save() - # testcases.delete() testcase_result = [] for unit in running_result.data: testcase = Testcase( problem = problem, input = unit.input, - output = unit.output + output = unit.output, + runtime_status = unit.runtime_status ) testcase.save() testcase_result.append(testcase) diff --git a/api/controllers/submission/submit_problem.py b/api/controllers/submission/submit_problem.py index cd68273..fa5226b 100644 --- a/api/controllers/submission/submit_problem.py +++ b/api/controllers/submission/submit_problem.py @@ -22,7 +22,7 @@ def avaliableQueue(): def submit_problem(account_id:int,problem_id:int,request): global QUEUE problem = Problem.objects.get(problem_id=problem_id) - testcases = Testcase.objects.filter(problem=problem) + testcases = Testcase.objects.filter(problem=problem,deprecated=False) submission_code = request.data['submission_code'] solution_input = [model_to_dict(i)['input'] for i in testcases] diff --git a/api/migrations/0035_testcase_depricated.py b/api/migrations/0035_testcase_depricated.py new file mode 100644 index 0000000..098108d --- /dev/null +++ b/api/migrations/0035_testcase_depricated.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2023-12-11 09:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0034_alter_submissiontestcase_testcase'), + ] + + operations = [ + migrations.AddField( + model_name='testcase', + name='depricated', + field=models.BooleanField(blank=True, default=False), + ), + ] diff --git a/api/migrations/0036_rename_depricated_testcase_deprecated.py b/api/migrations/0036_rename_depricated_testcase_deprecated.py new file mode 100644 index 0000000..fb93e28 --- /dev/null +++ b/api/migrations/0036_rename_depricated_testcase_deprecated.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2023-12-11 09:26 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0035_testcase_depricated'), + ] + + operations = [ + migrations.RenameField( + model_name='testcase', + old_name='depricated', + new_name='deprecated', + ), + ] diff --git a/api/models.py b/api/models.py index 35ba146..2426647 100644 --- a/api/models.py +++ b/api/models.py @@ -46,6 +46,7 @@ class Testcase(models.Model): input = models.CharField(max_length=100000) output = models.CharField(max_length=100000) runtime_status = models.CharField(max_length=10) + deprecated = models.BooleanField(default=False,blank=True) class Submission(models.Model): submission_id = models.AutoField(primary_key=True) diff --git a/api/serializers.py b/api/serializers.py index ec5dbff..6385714 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -109,6 +109,26 @@ class Meta: model = Testcase fields = "__all__" +class ProblemPopulateTestcaseSerializer(serializers.ModelSerializer): + testcases = TestcaseSerializer(many=True) + class Meta: + model = Problem + fields = [ + 'problem_id', + 'language', + 'title', + 'description', + 'solution', + 'time_limit', + 'is_active', + 'is_private', + 'submission_regex', + 'created_date', + 'updated_date', + 'creator', + 'testcases' + ] + class ProblemPopulateAccountSecureSerializer(serializers.ModelSerializer): creator = AccountSecureSerializer() class Meta: From 91b630fd48f7f51d09e493ac09600846e7204f26 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Tue, 12 Dec 2023 13:44:59 +0700 Subject: [PATCH 27/61] MOD-72,73: CreateProblem accept problem with runtime error --- api/controllers/problem/create_problem.py | 4 ++-- api/controllers/problem/update_problem.py | 4 ++-- api/migrations/0037_alter_testcase_output.py | 18 ++++++++++++++++++ api/models.py | 2 +- 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 api/migrations/0037_alter_testcase_output.py diff --git a/api/controllers/problem/create_problem.py b/api/controllers/problem/create_problem.py index 65e590f..3998d2e 100644 --- a/api/controllers/problem/create_problem.py +++ b/api/controllers/problem/create_problem.py @@ -13,8 +13,8 @@ def create_problem(account_id:int,request): running_result = PythonGrader(request.data['solution'],request.data['testcases'],1,1.5).generate_output() - if not running_result.runnable: - return Response({'detail': 'Error during creating. Your code may has an error/timeout!','output': running_result.getResult()},status=status.HTTP_406_NOT_ACCEPTABLE) + # if not running_result.runnable: + # return Response({'detail': 'Error during creating. Your code may has an error/timeout!','output': running_result.getResult()},status=status.HTTP_406_NOT_ACCEPTABLE) problem = Problem( language = request.data['language'], diff --git a/api/controllers/problem/update_problem.py b/api/controllers/problem/update_problem.py index 5557640..3380add 100644 --- a/api/controllers/problem/update_problem.py +++ b/api/controllers/problem/update_problem.py @@ -28,8 +28,8 @@ def update_problem(problem_id:int,request): if 'testcases' in request.data: running_result = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() - if not running_result.runnable: - return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) + # if not running_result.runnable: + # return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) for testcase in testcases: testcase.deprecated = True diff --git a/api/migrations/0037_alter_testcase_output.py b/api/migrations/0037_alter_testcase_output.py new file mode 100644 index 0000000..3f7f773 --- /dev/null +++ b/api/migrations/0037_alter_testcase_output.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2023-12-12 06:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0036_rename_depricated_testcase_deprecated'), + ] + + operations = [ + migrations.AlterField( + model_name='testcase', + name='output', + field=models.CharField(max_length=100000, null=True), + ), + ] diff --git a/api/models.py b/api/models.py index 2426647..7a002f1 100644 --- a/api/models.py +++ b/api/models.py @@ -44,7 +44,7 @@ class Testcase(models.Model): testcase_id = models.AutoField(primary_key=True) problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") input = models.CharField(max_length=100000) - output = models.CharField(max_length=100000) + output = models.CharField(max_length=100000,null=True) runtime_status = models.CharField(max_length=10) deprecated = models.BooleanField(default=False,blank=True) From c52b84d31b15c806ef9ec926c260353094ba01f5 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 14 Dec 2023 09:50:17 +0700 Subject: [PATCH 28/61] Ignore testcase+source --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6aebf24..f0794a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,15 @@ .dist/ __pycache__ -api/sandbox/testcases/*.txt +api/sandbox/section*/testcases/*.txt +api/sandbox/section*/runner* runner.py @/* env/ .env -[0-9]*.txt +# [0-9]*.txt media/testfile media/topic From 2b525bac3767dc85fd28cc19cefbb53cde1bace1 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 14 Dec 2023 15:59:50 +0700 Subject: [PATCH 29/61] Created date + updated date for Collection --- .../collection/add_problems_to_collection.py | 2 +- .../remove_problems_from_collection.py | 1 + .../collection/update_collection.py | 2 ++ ...on_created_date_collection_updated_date.py | 24 +++++++++++++++++++ api/models.py | 2 ++ 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 api/migrations/0038_collection_created_date_collection_updated_date.py diff --git a/api/controllers/collection/add_problems_to_collection.py b/api/controllers/collection/add_problems_to_collection.py index 048edd7..6ac7f98 100644 --- a/api/controllers/collection/add_problems_to_collection.py +++ b/api/controllers/collection/add_problems_to_collection.py @@ -28,7 +28,7 @@ def add_problems_to_collection(collection:Collection,request): collection_problem.save() index += 1 populated_problems.append(collection_problem) - + collection.updated_date = timezone.now() problem_serialize = CollectionProblemPopulateProblemSecureSerializer(populated_problems,many=True) collection_serialize = CollectionSerializer(collection) diff --git a/api/controllers/collection/remove_problems_from_collection.py b/api/controllers/collection/remove_problems_from_collection.py index fbb39c7..1f0a6d6 100644 --- a/api/controllers/collection/remove_problems_from_collection.py +++ b/api/controllers/collection/remove_problems_from_collection.py @@ -10,4 +10,5 @@ def remove_problems_from_collection(collection:Collection,request): CollectionProblem.objects.filter(collection=collection,problem_id__in=request.data['problem_ids']).delete() + collection.updated_date = timezone.now() return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file diff --git a/api/controllers/collection/update_collection.py b/api/controllers/collection/update_collection.py index 626d671..9868d95 100644 --- a/api/controllers/collection/update_collection.py +++ b/api/controllers/collection/update_collection.py @@ -12,6 +12,8 @@ def update_collection(collection_id:int,request): collection = Collection.objects.get(collection_id=collection_id) collection_ser = CollectionSerializer(collection,data=request.data,partial=True) if collection_ser.is_valid(): + collection.updated_date = timezone.now() + collection_ser = CollectionSerializer(collection,data=request.data,partial=True) collection_ser.save() return Response(collection_ser.data,status=status.HTTP_200_OK) else: diff --git a/api/migrations/0038_collection_created_date_collection_updated_date.py b/api/migrations/0038_collection_created_date_collection_updated_date.py new file mode 100644 index 0000000..4fa8a37 --- /dev/null +++ b/api/migrations/0038_collection_created_date_collection_updated_date.py @@ -0,0 +1,24 @@ +# Generated by Django 4.1.2 on 2023-12-14 07:52 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0037_alter_testcase_output'), + ] + + operations = [ + migrations.AddField( + model_name='collection', + name='created_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AddField( + model_name='collection', + name='updated_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/api/models.py b/api/models.py index 7a002f1..6b55e68 100644 --- a/api/models.py +++ b/api/models.py @@ -67,6 +67,8 @@ class Collection(models.Model): description = models.CharField(max_length=1000,null=True,blank=True,default=None) is_active = models.BooleanField(default=True,blank=True) is_private = models.BooleanField(default=False,blank=True) + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) class Topic(models.Model): topic_id = models.AutoField(primary_key=True) From 9f6d71f485bdaeca2ced2bf476b2f8046d25594d Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 16 Dec 2023 03:02:15 +0700 Subject: [PATCH 30/61] Update some collection API --- .../get_all_collections_by_account.py | 2 +- .../collection/update_collection.py | 19 +++++----- .../update_problems_to_collection.py | 35 +++++++++++++++++++ api/views/collection.py | 5 ++- 4 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 api/controllers/collection/update_problems_to_collection.py diff --git a/api/controllers/collection/get_all_collections_by_account.py b/api/controllers/collection/get_all_collections_by_account.py index be5d7f9..b4f64af 100644 --- a/api/controllers/collection/get_all_collections_by_account.py +++ b/api/controllers/collection/get_all_collections_by_account.py @@ -9,7 +9,7 @@ from ...serializers import * def get_all_collections_by_account(account_id:int): - collections = Collection.objects.filter(creator=account_id) + collections = Collection.objects.filter(creator=account_id).order_by('-updated_date') problemCollections = CollectionProblem.objects.filter(collection__in=collections) populated_collections = [] diff --git a/api/controllers/collection/update_collection.py b/api/controllers/collection/update_collection.py index 9868d95..5abdc62 100644 --- a/api/controllers/collection/update_collection.py +++ b/api/controllers/collection/update_collection.py @@ -10,11 +10,14 @@ def update_collection(collection_id:int,request): collection = Collection.objects.get(collection_id=collection_id) - collection_ser = CollectionSerializer(collection,data=request.data,partial=True) - if collection_ser.is_valid(): - collection.updated_date = timezone.now() - collection_ser = CollectionSerializer(collection,data=request.data,partial=True) - collection_ser.save() - return Response(collection_ser.data,status=status.HTTP_200_OK) - else: - return Response(collection_ser.errors,status=status.HTTP_400_BAD_REQUEST) + + collection.name = request.data.get('name',collection.name) + collection.description = request.data.get('description',collection.description) + collection.is_private = request.data.get('is_private',collection.is_private) + collection.is_active = request.data.get('is_active',collection.is_active) + collection.updated_date = timezone.now() + + collection.save() + collection_ser = CollectionSerializer(collection) + + return Response(collection_ser.data,status=status.HTTP_200_OK) diff --git a/api/controllers/collection/update_problems_to_collection.py b/api/controllers/collection/update_problems_to_collection.py new file mode 100644 index 0000000..12fee32 --- /dev/null +++ b/api/controllers/collection/update_problems_to_collection.py @@ -0,0 +1,35 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_problems_to_collection(collection:Collection,request): + CollectionProblem.objects.filter(collection=collection).delete() + + collection_problems = [] + order = 0 + for problem_id in request.data['problem_ids']: + problem = Problem.objects.get(problem_id=problem_id) + collection_problem = CollectionProblem( + problem=problem, + collection=collection, + order=order + ) + collection_problems.append(collection_problem) + order += 1 + + CollectionProblem.objects.bulk_create(collection_problems) + collection.updated_date = timezone.now() + collection.save() + problem_serialize = CollectionProblemPopulateProblemSecureSerializer(collection_problems,many=True) + collection_serialize = CollectionSerializer(collection) + + return Response({ + **collection_serialize.data, + 'problems': problem_serialize.data + },status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/views/collection.py b/api/views/collection.py index 747bab8..493a35c 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -16,6 +16,7 @@ from ..controllers.collection.add_problems_to_collection import * from ..controllers.collection.remove_problems_from_collection import * from ..controllers.collection.get_all_collections_by_account import * +from ..controllers.collection.update_problems_to_collection import * @api_view([POST,GET]) @@ -46,4 +47,6 @@ def collection_problems_view(request,collection_id:int,method:str): if method == "add": return add_problems_to_collection(collection,request) if method == "remove": - return remove_problems_from_collection(collection,request) \ No newline at end of file + return remove_problems_from_collection(collection,request) + if method == "update": + return update_problems_to_collection(collection,request) \ No newline at end of file From 6a3a1b168c1df9170c2c81df117d57ac36368a5d Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 16 Dec 2023 22:41:44 +0700 Subject: [PATCH 31/61] Topic (Course) API --- .../topic/get_all_topics_by_account.py | 24 +++++++++++++++++++ ...9_topic_created_date_topic_updated_date.py | 24 +++++++++++++++++++ api/models.py | 2 ++ api/serializers.py | 16 ++++++++++++- api/urls.py | 2 +- api/views/topic.py | 10 +++++--- 6 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 api/controllers/topic/get_all_topics_by_account.py create mode 100644 api/migrations/0039_topic_created_date_topic_updated_date.py diff --git a/api/controllers/topic/get_all_topics_by_account.py b/api/controllers/topic/get_all_topics_by_account.py new file mode 100644 index 0000000..b500578 --- /dev/null +++ b/api/controllers/topic/get_all_topics_by_account.py @@ -0,0 +1,24 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_topics_by_account(account_id:int,request): + topics = Topic.objects.filter(creator_id=account_id) + topicCollections = TopicCollection.objects.filter(topic__in=topics) + + populated_topics = [] + for topic in topics: + topic.collections = topicCollections.filter(topic=topic) + populated_topics.append(topic) + + serialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(populated_topics,many=True) + + return Response({ + 'topics': serialize.data + },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/migrations/0039_topic_created_date_topic_updated_date.py b/api/migrations/0039_topic_created_date_topic_updated_date.py new file mode 100644 index 0000000..04d4abb --- /dev/null +++ b/api/migrations/0039_topic_created_date_topic_updated_date.py @@ -0,0 +1,24 @@ +# Generated by Django 4.1.2 on 2023-12-16 04:27 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0038_collection_created_date_collection_updated_date'), + ] + + operations = [ + migrations.AddField( + model_name='topic', + name='created_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AddField( + model_name='topic', + name='updated_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/api/models.py b/api/models.py index 6b55e68..bb574bd 100644 --- a/api/models.py +++ b/api/models.py @@ -78,6 +78,8 @@ class Topic(models.Model): image_url = models.ImageField(upload_to='topic/',null=True,blank=True,default=None) is_active = models.BooleanField(default=True,blank=True) is_private = models.BooleanField(default=False,blank=True) + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) class TopicCollection(models.Model): topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") diff --git a/api/serializers.py b/api/serializers.py index 6385714..07f2841 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -25,6 +25,7 @@ def update(self,instance,validate_data): instance.image_url = validate_data.get('image_url',instance.image_url) instance.is_active = validate_data.get('is_active',instance.is_active) instance.is_private = validate_data.get('is_private',instance.is_private) + instance.updated_date = timezone.now() instance.save() return instance @@ -60,6 +61,8 @@ class Meta: model = TopicCollection fields = "__all__" + + class CollectionProblemSerializer(serializers.ModelSerializer): class Meta: model = CollectionProblem @@ -159,4 +162,15 @@ class ProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerial best_submission = SubmissionPopulateSubmissionTestcaseSecureSerializer() class Meta: model = Problem - fields = problem_secure_fields + ['best_submission','creator'] \ No newline at end of file + fields = problem_secure_fields + ['best_submission','creator'] + +class TopicCollectionPopulateCollectionSerializer(serializers.ModelSerializer): + collection = CollectionSerializer() + class Meta: + model = TopicCollection + fields = "__all__" +class TopicPopulateTopicCollectionPopulateCollectionSerializer(serializers.ModelSerializer): + collections = TopicCollectionPopulateCollectionSerializer(many=True) + class Meta: + model = Topic + fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','creator','collections'] \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index 8cf70bd..da6b13f 100644 --- a/api/urls.py +++ b/api/urls.py @@ -20,7 +20,7 @@ path('submissions',submission.all_submission_view), path("accounts//problems//submissions",submission.account_problem_submission_view), - path('accounts//topics',topic.create_topic_view), + path('accounts//topics',topic.all_topics_account_view), path('topics',topic.all_topics_view), path('topics/',topic.one_topic_view), path('topics//access',topic.account_access), diff --git a/api/views/topic.py b/api/views/topic.py index 4aa8a9b..8d90f10 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -15,11 +15,15 @@ from ..controllers.topic.delete_topic import * from ..controllers.topic.add_collections_to_topic import * from ..controllers.topic.remove_collections_from_topic import * +from ..controllers.topic.get_all_topics_by_account import * -@api_view([POST]) +@api_view([POST,GET]) @parser_classes([MultiPartParser,FormParser]) -def create_topic_view(request,account_id :int): - return create_topic(account_id,request) +def all_topics_account_view(request,account_id :int): + if request.method == POST: + return create_topic(account_id,request) + elif request.method == GET: + return get_all_topics_by_account(account_id,request) @api_view([GET]) def all_topics_view(request): From b7bc09696fd74a881a620b7cfdc94ee4a9b50392 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 17 Dec 2023 17:31:48 +0700 Subject: [PATCH 32/61] Update Topic API --- .../topic/get_all_topics_by_account.py | 2 +- .../topic/update_collections_to_topic.py | 36 +++++++++++++++++++ api/views/topic.py | 6 ++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 api/controllers/topic/update_collections_to_topic.py diff --git a/api/controllers/topic/get_all_topics_by_account.py b/api/controllers/topic/get_all_topics_by_account.py index b500578..d9dd97b 100644 --- a/api/controllers/topic/get_all_topics_by_account.py +++ b/api/controllers/topic/get_all_topics_by_account.py @@ -9,7 +9,7 @@ from ...serializers import * def get_all_topics_by_account(account_id:int,request): - topics = Topic.objects.filter(creator_id=account_id) + topics = Topic.objects.filter(creator_id=account_id).order_by('-updated_date') topicCollections = TopicCollection.objects.filter(topic__in=topics) populated_topics = [] diff --git a/api/controllers/topic/update_collections_to_topic.py b/api/controllers/topic/update_collections_to_topic.py new file mode 100644 index 0000000..4bb3e81 --- /dev/null +++ b/api/controllers/topic/update_collections_to_topic.py @@ -0,0 +1,36 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_collections_to_topic(topic:Topic,request): + TopicCollection.objects.filter(topic=topic).delete() + + topic_collections = [] + order = 0 + for collection_id in request.data['collection_ids']: + collection = Collection.objects.get(collection_id=collection_id) + topic_collection = TopicCollection( + collection=collection, + topic=topic, + order=order + ) + topic_collections.append(topic_collection) + order += 1 + + TopicCollection.objects.bulk_create(topic_collections) + topic.updated_date = timezone.now() + topic.save() + + collection_serialize = TopicCollectionPopulateCollectionSerializer(topic_collections,many=True) + topic_serialize = TopicSerializer(topic) + + return Response({ + **topic_serialize.data, + 'collections': collection_serialize.data + },status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/views/topic.py b/api/views/topic.py index 8d90f10..2d30825 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -16,6 +16,7 @@ from ..controllers.topic.add_collections_to_topic import * from ..controllers.topic.remove_collections_from_topic import * from ..controllers.topic.get_all_topics_by_account import * +from ..controllers.topic.update_collections_to_topic import * @api_view([POST,GET]) @parser_classes([MultiPartParser,FormParser]) @@ -40,10 +41,15 @@ def one_topic_view(request,topic_id:int): @api_view([PUT]) def topic_collections_view(request,topic_id:int,method:str): + + topic = Topic.objects.get(topic_id=topic_id) + if method == "add": return add_collections_to_topic(topic_id,request) elif method == "remove": return remove_collections_from_topic(topic_id,request) + elif method == "update": + return update_collections_to_topic(topic,request) @api_view([POST,PUT]) def account_access(request,topic_id:int): From b3dd86c36ded697589beb7e2844e6a71ace238b1 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 18 Dec 2023 01:15:21 +0700 Subject: [PATCH 33/61] Update get topic API --- api/controllers/topic/get_topic.py | 62 +++++++++++++++++------------- api/serializers.py | 22 ++++++++++- api/urls.py | 24 +++++++----- api/views/collection.py | 11 +++++- api/views/problem.py | 9 +++++ api/views/topic.py | 9 +++++ 6 files changed, 99 insertions(+), 38 deletions(-) diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py index 33c55ce..89f37b4 100644 --- a/api/controllers/topic/get_topic.py +++ b/api/controllers/topic/get_topic.py @@ -10,31 +10,39 @@ def get_topic(topic_id:int): topic = Topic.objects.get(topic_id=topic_id) - topicCollections = TopicCollection.objects.filter(topic_id=topic_id) - accessedAccounts = Account.objects.filter(topicaccountaccess__topic_id=topic_id) + topic.collections = TopicCollection.objects.filter(topic_id=topic_id) + serialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(topic) - topic_ser = TopicSerializer(topic) - populate_collections = [] - - for top_col in topicCollections: - collection_serialize = CollectionSerializer(top_col.collection) - collection_data = collection_serialize.data - - populate_problems = [] - collection_problems = CollectionProblem.objects.filter(collection=top_col.collection) - for col_prob in collection_problems: - prob_serialize = ProblemSerializer(col_prob.problem) - col_prob_serialize = CollectionProblemSerializer(col_prob) - populate_problems.append({**col_prob_serialize.data,**prob_serialize.data}) - - collection_data['problems'] = populate_problems - top_col_serialize = TopicCollectionSerializer(top_col) - populate_collections.append({**top_col_serialize.data,**collection_data}) - - accessedAccountsSerialize = AccountSecureSerializer(accessedAccounts,many=True) - - return Response({ - **topic_ser.data, - "collections": sorted(populate_collections,key=lambda collection: collection['order']), - "accessed_accounts": accessedAccountsSerialize.data - },status=status.HTTP_200_OK) \ No newline at end of file + return Response(serialize.data,status=status.HTTP_200_OK) + + + + # topic = Topic.objects.get(topic_id=topic_id) + # topicCollections = TopicCollection.objects.filter(topic_id=topic_id) + # # accessedAccounts = Account.objects.filter(topicaccountaccess__topic_id=topic_id) + + # topic_ser = TopicSerializer(topic) + # populate_collections = [] + + # for top_col in topicCollections: + # collection_serialize = CollectionSerializer(top_col.collection) + # collection_data = collection_serialize.data + + # populate_problems = [] + # collection_problems = CollectionProblem.objects.filter(collection=top_col.collection) + # for col_prob in collection_problems: + # prob_serialize = ProblemSerializer(col_prob.problem) + # col_prob_serialize = CollectionProblemSerializer(col_prob) + # populate_problems.append({**col_prob_serialize.data,**prob_serialize.data}) + + # collection_data['problems'] = populate_problems + # top_col_serialize = TopicCollectionSerializer(top_col) + # populate_collections.append({**top_col_serialize.data,**collection_data}) + + # # accessedAccountsSerialize = AccountSecureSerializer(accessedAccounts,many=True) + + # return Response({ + # **topic_ser.data, + # "collections": sorted(populate_collections,key=lambda collection: collection['order']), + # # "accessed_accounts": accessedAccountsSerialize.data + # },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 07f2841..745a59b 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -68,6 +68,12 @@ class Meta: model = CollectionProblem fields = "__all__" +class CollectionProblemPopulateProblemSerializer(serializers.ModelSerializer): + problem = ProblemSerializer() + class Meta: + model = CollectionProblem + fields = "__all__" + class CollectionProblemPopulateProblemSecureSerializer(serializers.ModelSerializer): problem = ProblemSecureSerializer() class Meta: @@ -169,8 +175,22 @@ class TopicCollectionPopulateCollectionSerializer(serializers.ModelSerializer): class Meta: model = TopicCollection fields = "__all__" + +class TopicCollectionPopulateCollectionProblemPopulateProblemSerializer(serializers.ModelSerializer): + collection = CollectionProblemPopulateProblemSerializer() + class Meta: + model = TopicCollection + fields = "__all__" + class TopicPopulateTopicCollectionPopulateCollectionSerializer(serializers.ModelSerializer): collections = TopicCollectionPopulateCollectionSerializer(many=True) class Meta: model = Topic - fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','creator','collections'] \ No newline at end of file + fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','creator','collections'] + + +class TopicPopulateTopicCollectionPopulateCollectionProblemPopulateProblemSerializer(serializers.ModelSerializer): + collections = CollectionProblemPopulateProblemSerializer(many=True) + class Meta: + model = Topic + fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','collections'] \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index da6b13f..395d2c5 100644 --- a/api/urls.py +++ b/api/urls.py @@ -13,24 +13,30 @@ path("accounts//password",account.change_password), path('accounts//problems',problem.all_problems_account_view), + path('accounts//problems/',problem.one_problem_account_view), + path("accounts//problems//submissions",submission.account_problem_submission_view), + + path('accounts//collections',collection.all_collections_account_view), + path('accounts//collections/',collection.one_collection_account_view), + + path('accounts//topics',topic.all_topics_account_view), + path('accounts//topics/',topic.one_topic_account_view), + path('problems',problem.all_problems_view), + path('problems/validate',problem.validation_view), path('problems/',problem.one_problem_view), - # path('problems//',submission.submit_problem_view), - path('submissions',submission.all_submission_view), - path("accounts//problems//submissions",submission.account_problem_submission_view), + path('collections',collection.all_collections_view), + path('collections/',collection.one_collection_view), + path('collections//problems/',collection.collection_problems_view), - path('accounts//topics',topic.all_topics_account_view), path('topics',topic.all_topics_view), path('topics/',topic.one_topic_view), path('topics//access',topic.account_access), path('topics//collections/',topic.topic_collections_view), - path('accounts//collections',collection.account_collections_view), - path('collections',collection.all_collections_view), - path('collections/',collection.one_collection_view), - path('collections//problems/',collection.collection_problems_view), + path('submissions',submission.all_submission_view), + path('script',script.run_script), - path('problems/validate',problem.validation_view), ] \ No newline at end of file diff --git a/api/views/collection.py b/api/views/collection.py index 493a35c..6414f0d 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -20,12 +20,21 @@ @api_view([POST,GET]) -def account_collections_view(request,account_id:int): +def all_collections_account_view(request,account_id:int): if request.method == POST: return create_collection(account_id,request) if request.method == GET: return get_all_collections_by_account(account_id) +@api_view([GET,PUT,DELETE]) +def one_collection_account_view(request,collection_id:int): + if request.method == GET: + return get_collection(collection_id) + if request.method == PUT: + return update_collection(collection_id,request) + if request.method == DELETE: + return delete_collection(collection_id) + @api_view([GET]) def all_collections_view(request): return get_all_collections(request) diff --git a/api/views/problem.py b/api/views/problem.py index beff57a..1a4c520 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -26,6 +26,15 @@ def all_problems_account_view(request,account_id): if request.method == GET: return get_all_problems_by_account(account_id) +@api_view([GET,PUT,DELETE]) +def one_problem_account_view(problem_id:int,request): + if request.method == GET: + return get_problem(problem_id) + elif request.method == PUT: + return update_problem(problem_id,request) + elif request.method == DELETE: + return delete_problem(problem_id) + @api_view([GET,DELETE]) def all_problems_view(request): if request.method == GET: diff --git a/api/views/topic.py b/api/views/topic.py index 2d30825..5fc81f2 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -26,6 +26,15 @@ def all_topics_account_view(request,account_id :int): elif request.method == GET: return get_all_topics_by_account(account_id,request) +@api_view([GET,PUT,DELETE]) +def one_topic_account_view(request,topic_id:int): + if request.method == GET: + return get_topic(topic_id) + elif request.method == PUT: + return update_topic(topic_id,request) + elif request.method == DELETE: + return delete_topic(topic_id) + @api_view([GET]) def all_topics_view(request): return get_all_topics(request) From 1f97808cc79f68c82ff5eaca80a4beb9c9f241f1 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Tue, 19 Dec 2023 19:27:36 +0700 Subject: [PATCH 34/61] API: Public topic view (Populate hell) --- api/controllers/submission/submit_problem.py | 36 +++++++++++++++++-- .../submission/submit_problem_on_topic.py | 15 ++++++++ api/controllers/topic/get_topic_public.py | 36 +++++++++++++++++++ api/migrations/0040_submission_topic.py | 19 ++++++++++ api/migrations/0041_bestsubmission.py | 24 +++++++++++++ api/models.py | 34 +++++++++++------- api/serializers.py | 30 +++++++++++++++- api/urls.py | 15 ++++---- api/views/account.py | 2 +- api/views/collection.py | 4 +-- api/views/problem.py | 4 +-- api/views/submission.py | 4 +++ api/views/topic.py | 7 ++-- 13 files changed, 198 insertions(+), 32 deletions(-) create mode 100644 api/controllers/submission/submit_problem_on_topic.py create mode 100644 api/controllers/topic/get_topic_public.py create mode 100644 api/migrations/0040_submission_topic.py create mode 100644 api/migrations/0041_bestsubmission.py diff --git a/api/controllers/submission/submit_problem.py b/api/controllers/submission/submit_problem.py index fa5226b..1fa1b8d 100644 --- a/api/controllers/submission/submit_problem.py +++ b/api/controllers/submission/submit_problem.py @@ -19,10 +19,11 @@ def avaliableQueue(): return i return -1 -def submit_problem(account_id:int,problem_id:int,request): +def submit_problem_function(account_id:int,problem_id:int,topic_id:int,request): global QUEUE problem = Problem.objects.get(problem_id=problem_id) testcases = Testcase.objects.filter(problem=problem,deprecated=False) + account = Account.objects.get(account_id=account_id) submission_code = request.data['submission_code'] solution_input = [model_to_dict(i)['input'] for i in testcases] @@ -47,7 +48,7 @@ def submit_problem(account_id:int,problem_id:int,request): submission = Submission( problem = problem, - account = Account.objects.get(account_id=account_id), + account = account, language = request.data['language'], submission_code = request.data['submission_code'], is_passed = grading_result.is_passed, @@ -55,8 +56,34 @@ def submit_problem(account_id:int,problem_id:int,request): max_score = max_score, passed_ratio = total_score/max_score ) + + if topic_id: + submission.topic = Topic.objects.get(topic_id=topic_id) + submission.save() + # Best Submission + try: + best_submission = None + if topic_id: + best_submission = BestSubmission.objects.get(problem=problem,account=account,topic=Topic.objects.get(topic_id=topic_id)) + else: + best_submission = BestSubmission.objects.get(problem=problem,account=account) + except: + best_submission = BestSubmission( + problem = problem, + account = account, + topic = Topic.objects.get(topic_id=topic_id) if topic_id else None, + submission = submission + ) + best_submission.save() + else: + if submission.passed_ratio >= best_submission.submission.passed_ratio: + best_submission.submission = submission + best_submission.save() + + # End Best Submission + submission_testcases = [] for i in range(len(grading_result.data)): submission_testcases.append(SubmissionTestcase( @@ -72,4 +99,7 @@ def submit_problem(account_id:int,problem_id:int,request): submission.runtime_output = submission_testcases testser = SubmissionPopulateSubmissionTestcaseSecureSerializer(submission) - return Response(testser.data,status=status.HTTP_201_CREATED) \ No newline at end of file + return Response(testser.data,status=status.HTTP_201_CREATED) + +def submit_problem(account_id:int,problem_id:int,request): + return submit_problem_function(account_id,problem_id,None,request) \ No newline at end of file diff --git a/api/controllers/submission/submit_problem_on_topic.py b/api/controllers/submission/submit_problem_on_topic.py new file mode 100644 index 0000000..b2940e8 --- /dev/null +++ b/api/controllers/submission/submit_problem_on_topic.py @@ -0,0 +1,15 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader,Grader,ProgramGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * +from ...utility import regexMatching +from time import sleep +from .submit_problem import * + +def submit_problem_on_topic(account_id:int,problem_id:int,topic_id:int,request): + return submit_problem_function(account_id,problem_id,topic_id,request) \ No newline at end of file diff --git a/api/controllers/topic/get_topic_public.py b/api/controllers/topic/get_topic_public.py new file mode 100644 index 0000000..64eb926 --- /dev/null +++ b/api/controllers/topic/get_topic_public.py @@ -0,0 +1,36 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_topic_public(topic_id:int,request): + + account_id = request.query_params.get('account_id',None) + + topic = Topic.objects.get(topic_id=topic_id) + account = Account.objects.get(account_id=account_id) + topicCollections = TopicCollection.objects.filter(topic=topic) + + for tp in topicCollections: + # tp.collection.problems = CollectionProblem.objects.filter(collection=tp.collection) + collectionProblems = CollectionProblem.objects.filter(collection=tp.collection) + for cp in collectionProblems: + try: + best_submission = BestSubmission.objects.get(problem=cp.problem,account=account,topic=topic) + best_submission = best_submission.submission + except: + best_submission = None + cp.problem.best_submission = best_submission + + tp.collection.problems = collectionProblems + + topic.collections = topicCollections + + serialize = TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(topic) + + return Response(serialize.data,status=status.HTTP_200_OK) diff --git a/api/migrations/0040_submission_topic.py b/api/migrations/0040_submission_topic.py new file mode 100644 index 0000000..a22e553 --- /dev/null +++ b/api/migrations/0040_submission_topic.py @@ -0,0 +1,19 @@ +# Generated by Django 4.1.2 on 2023-12-19 05:21 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0039_topic_created_date_topic_updated_date'), + ] + + operations = [ + migrations.AddField( + model_name='submission', + name='topic', + field=models.ForeignKey(db_column='topic_id', null=True, on_delete=django.db.models.deletion.CASCADE, to='api.topic'), + ), + ] diff --git a/api/migrations/0041_bestsubmission.py b/api/migrations/0041_bestsubmission.py new file mode 100644 index 0000000..b50c3db --- /dev/null +++ b/api/migrations/0041_bestsubmission.py @@ -0,0 +1,24 @@ +# Generated by Django 4.1.2 on 2023-12-19 08:49 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0040_submission_topic'), + ] + + operations = [ + migrations.CreateModel( + name='BestSubmission', + fields=[ + ('best_submission_id', models.AutoField(primary_key=True, serialize=False)), + ('account', models.ForeignKey(db_column='account_id', on_delete=django.db.models.deletion.CASCADE, to='api.account')), + ('problem', models.ForeignKey(db_column='problem_id', on_delete=django.db.models.deletion.CASCADE, to='api.problem')), + ('submission', models.ForeignKey(db_column='submission_id', on_delete=django.db.models.deletion.CASCADE, to='api.submission')), + ('topic', models.ForeignKey(db_column='topic_id', null=True, on_delete=django.db.models.deletion.CASCADE, to='api.topic')), + ], + ), + ] diff --git a/api/models.py b/api/models.py index bb574bd..f2d19e5 100644 --- a/api/models.py +++ b/api/models.py @@ -48,18 +48,6 @@ class Testcase(models.Model): runtime_status = models.CharField(max_length=10) deprecated = models.BooleanField(default=False,blank=True) -class Submission(models.Model): - submission_id = models.AutoField(primary_key=True) - problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") - account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") - language = models.CharField(max_length=15) - submission_code = models.CharField(max_length=20000) - is_passed = models.BooleanField() - date = models.DateTimeField(default=timezone.now) - score = models.IntegerField(default=0) - max_score = models.IntegerField(default=0) - passed_ratio = models.FloatField(default=0) - class Collection(models.Model): collection_id = models.AutoField(primary_key=True) creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") @@ -100,10 +88,30 @@ class TopicAccountAccess(models.Model): topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") +class Submission(models.Model): + submission_id = models.AutoField(primary_key=True) + problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") + topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id",null=True) + account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") + language = models.CharField(max_length=15) + submission_code = models.CharField(max_length=20000) + is_passed = models.BooleanField() + date = models.DateTimeField(default=timezone.now) + score = models.IntegerField(default=0) + max_score = models.IntegerField(default=0) + passed_ratio = models.FloatField(default=0) + class SubmissionTestcase(models.Model): submission_testcase_id = models.AutoField(primary_key=True) submission = models.ForeignKey(Submission,on_delete=models.CASCADE,db_column="submission_id") testcase = models.ForeignKey(Testcase,on_delete=models.CASCADE,db_column="testcase_id") output = models.CharField(max_length=100000,blank=True,null=True) is_passed = models.BooleanField(default=False,blank=True) - runtime_status = models.CharField(max_length=10) \ No newline at end of file + runtime_status = models.CharField(max_length=10) + +class BestSubmission(models.Model): + best_submission_id = models.AutoField(primary_key=True) + problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") + topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id",null=True) + account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") + submission = models.ForeignKey(Submission,on_delete=models.CASCADE,db_column="submission_id") \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 745a59b..12cdb64 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -170,6 +170,11 @@ class Meta: model = Problem fields = problem_secure_fields + ['best_submission','creator'] +class ProblemPopulatSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): + best_submission = SubmissionPopulateSubmissionTestcaseSecureSerializer() + class Meta: + model = Problem + fields = problem_secure_fields + ['best_submission'] class TopicCollectionPopulateCollectionSerializer(serializers.ModelSerializer): collection = CollectionSerializer() class Meta: @@ -193,4 +198,27 @@ class TopicPopulateTopicCollectionPopulateCollectionProblemPopulateProblemSerial collections = CollectionProblemPopulateProblemSerializer(many=True) class Meta: model = Topic - fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','collections'] \ No newline at end of file + fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','collections'] + +class CollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): + problem = ProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer() + class Meta: + model = CollectionProblem + fields = "__all__" +class CollectionPopulateCollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): + problems = CollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(many=True) + class Meta: + model = Collection + fields = "__all__" + +class TopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): + collection = CollectionPopulateCollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer() + class Meta: + model = TopicCollection + fields = "__all__" + +class TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): + collections = TopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(many=True) + class Meta: + model = Topic + fields = ['topic_id','name','description','image_url','created_date','updated_date','collections'] \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index 395d2c5..fe0f2a8 100644 --- a/api/urls.py +++ b/api/urls.py @@ -8,19 +8,20 @@ path('token',auth.authorization_view), path("accounts",account.all_accounts_view), - path("accounts/",account.one_account_view), + path("accounts/",account.one_creator_view), path("accounts//daily-submissions",account.get_daily_submission), path("accounts//password",account.change_password), - path('accounts//problems',problem.all_problems_account_view), - path('accounts//problems/',problem.one_problem_account_view), + path('accounts//problems',problem.all_problems_creator_view), + path('accounts//problems/',problem.one_problem_creator_view), path("accounts//problems//submissions",submission.account_problem_submission_view), + path("accounts//topics//problems//submissions",submission.topic_account_problem_submission_view), - path('accounts//collections',collection.all_collections_account_view), - path('accounts//collections/',collection.one_collection_account_view), + path('accounts//collections',collection.all_collections_creator_view), + path('accounts//collections/',collection.one_collection_creator_view), - path('accounts//topics',topic.all_topics_account_view), - path('accounts//topics/',topic.one_topic_account_view), + path('accounts//topics',topic.all_topics_creator_view), + path('accounts//topics/',topic.one_topic_creator_view), path('problems',problem.all_problems_view), path('problems/validate',problem.validation_view), diff --git a/api/views/account.py b/api/views/account.py index 8d7549f..d9f4caa 100644 --- a/api/views/account.py +++ b/api/views/account.py @@ -19,7 +19,7 @@ def all_accounts_view(request): return create_account(request) @api_view([GET]) -def one_account_view(request,account_id): +def one_creator_view(request,account_id): return get_account(account_id) @api_view([PUT]) diff --git a/api/views/collection.py b/api/views/collection.py index 6414f0d..1213b1c 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -20,14 +20,14 @@ @api_view([POST,GET]) -def all_collections_account_view(request,account_id:int): +def all_collections_creator_view(request,account_id:int): if request.method == POST: return create_collection(account_id,request) if request.method == GET: return get_all_collections_by_account(account_id) @api_view([GET,PUT,DELETE]) -def one_collection_account_view(request,collection_id:int): +def one_collection_creator_view(request,collection_id:int): if request.method == GET: return get_collection(collection_id) if request.method == PUT: diff --git a/api/views/problem.py b/api/views/problem.py index 1a4c520..085153e 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -20,14 +20,14 @@ # Create your views here. @api_view([POST,GET]) -def all_problems_account_view(request,account_id): +def all_problems_creator_view(request,account_id): if request.method == POST: return create_problem(account_id,request) if request.method == GET: return get_all_problems_by_account(account_id) @api_view([GET,PUT,DELETE]) -def one_problem_account_view(problem_id:int,request): +def one_problem_creator_view(problem_id:int,request): if request.method == GET: return get_problem(problem_id) elif request.method == PUT: diff --git a/api/views/submission.py b/api/views/submission.py index bc9b52b..cd7efd9 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -14,6 +14,7 @@ from ..controllers.submission.submit_problem import * from ..controllers.submission.get_submission_by_quries import * from ..controllers.submission.get_submissions_by_account_problem import * +from ..controllers.submission.submit_problem_on_topic import * @api_view([POST,GET]) @@ -27,6 +28,9 @@ def account_problem_submission_view(request,problem_id,account_id): def all_submission_view(request): return get_submission_by_quries(request) +def topic_account_problem_submission_view(request,topic_id,account_id,problem_id): + return submit_problem_on_topic(account_id,problem_id,topic_id,request) + # @api_view([GET]) # def submission_account_problem_view(request,account_id:int,problem_id:int): # return get_submissions_by_account_problem(account_id,problem_id) \ No newline at end of file diff --git a/api/views/topic.py b/api/views/topic.py index 5fc81f2..b8932e3 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -17,17 +17,18 @@ from ..controllers.topic.remove_collections_from_topic import * from ..controllers.topic.get_all_topics_by_account import * from ..controllers.topic.update_collections_to_topic import * +from ..controllers.topic.get_topic_public import * @api_view([POST,GET]) @parser_classes([MultiPartParser,FormParser]) -def all_topics_account_view(request,account_id :int): +def all_topics_creator_view(request,account_id :int): if request.method == POST: return create_topic(account_id,request) elif request.method == GET: return get_all_topics_by_account(account_id,request) @api_view([GET,PUT,DELETE]) -def one_topic_account_view(request,topic_id:int): +def one_topic_creator_view(request,account_id:int,topic_id:int): if request.method == GET: return get_topic(topic_id) elif request.method == PUT: @@ -42,7 +43,7 @@ def all_topics_view(request): @api_view([GET,PUT,DELETE]) def one_topic_view(request,topic_id:int): if request.method == GET: - return get_topic(topic_id) + return get_topic_public(topic_id,request) elif request.method == PUT: return update_topic(topic_id,request) elif request.method == DELETE: From f532696a3d84a958cc387deb51c5e6a18982e0d3 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 20 Dec 2023 15:24:21 +0700 Subject: [PATCH 35/61] API for problem in course view --- ...t_problem_in_topic_with_best_submission.py | 31 ++++++++++++++++ ...submissions_by_account_problem_in_topic.py | 36 +++++++++++++++++++ api/urls.py | 1 + api/views/problem.py | 8 ++++- api/views/submission.py | 7 +++- 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 api/controllers/problem/get_problem_in_topic_with_best_submission.py create mode 100644 api/controllers/submission/get_submissions_by_account_problem_in_topic.py diff --git a/api/controllers/problem/get_problem_in_topic_with_best_submission.py b/api/controllers/problem/get_problem_in_topic_with_best_submission.py new file mode 100644 index 0000000..0be0585 --- /dev/null +++ b/api/controllers/problem/get_problem_in_topic_with_best_submission.py @@ -0,0 +1,31 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_problem_in_topic_with_best_submission(account_id:int,topic_id:int,problem:int): + + account = Account.objects.get(account_id=account_id) + problem = Problem.objects.get(problem_id=problem) + topic = Topic.objects.get(topic_id=topic_id) + + best_submission = BestSubmission.objects.filter(problem=problem,topic=topic,account=account).first() + # print(problem.problem_id,problem.title) + if not (best_submission is None): + testcases = SubmissionTestcase.objects.filter(submission=best_submission.submission) + print(testcases) + best_submission.runtime_output = testcases + problem.best_submission = best_submission + else: + problem.best_submission = None + + serialize = ProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(problem) + return Response(serialize.data,status=status.HTTP_200_OK) + + + # return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/submission/get_submissions_by_account_problem_in_topic.py b/api/controllers/submission/get_submissions_by_account_problem_in_topic.py new file mode 100644 index 0000000..7e7b91f --- /dev/null +++ b/api/controllers/submission/get_submissions_by_account_problem_in_topic.py @@ -0,0 +1,36 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_submissions_by_account_problem_in_topic(account_id:int,problem_id:int,topic_id:int): + submissions = Submission.objects.filter(account=account_id,problem=problem_id,topic_id=topic_id) + + if submissions.count() == 0: + return Response({"best_submission": None,"submissions": []},status=status.HTTP_204_NO_CONTENT) + + submissions = submissions.order_by('-submission_id') + + result = [] + + for submission in submissions: + submission_testcases = SubmissionTestcase.objects.filter(submission=submission) + submission.runtime_output = submission_testcases + result.append(submission) + + best_submission = BestSubmission.objects.filter(problem=problem_id,topic=topic_id,account=account_id).first() + if best_submission: + best_submission.submission.runtime_output = SubmissionTestcase.objects.filter(submission=best_submission.submission) + best_submission_serializer = SubmissionPopulateSubmissionTestcaseSecureSerializer(best_submission.submission) + best_submission_result = best_submission_serializer.data + else: + best_submission_result = None + + submissions_serializer = SubmissionPopulateSubmissionTestcaseSecureSerializer(result,many=True) + + return Response({"best_submission": best_submission_result,"submissions": submissions_serializer.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index fe0f2a8..caa4ed0 100644 --- a/api/urls.py +++ b/api/urls.py @@ -26,6 +26,7 @@ path('problems',problem.all_problems_view), path('problems/validate',problem.validation_view), path('problems/',problem.one_problem_view), + path('topics//problems//accounts/',problem.problem_in_topic_account_view), path('collections',collection.all_collections_view), path('collections/',collection.one_collection_view), diff --git a/api/views/problem.py b/api/views/problem.py index 085153e..8c7224b 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -17,6 +17,7 @@ from ..controllers.problem.get_all_problems_by_account import * from ..controllers.problem.validate_program import * from ..controllers.problem.get_all_problem_with_best_submission import * +from ..controllers.problem.get_problem_in_topic_with_best_submission import * # Create your views here. @api_view([POST,GET]) @@ -54,4 +55,9 @@ def one_problem_view(request,problem_id: int): @api_view([POST]) def validation_view(request): if request.method == POST: - return validate_program(request) \ No newline at end of file + return validate_program(request) + +@api_view([GET]) +def problem_in_topic_account_view(request,account_id:int,topic_id:int,problem_id:int): + if request.method == GET: + return get_problem_in_topic_with_best_submission(account_id,topic_id,problem_id) \ No newline at end of file diff --git a/api/views/submission.py b/api/views/submission.py index cd7efd9..5973897 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -15,6 +15,7 @@ from ..controllers.submission.get_submission_by_quries import * from ..controllers.submission.get_submissions_by_account_problem import * from ..controllers.submission.submit_problem_on_topic import * +from ..controllers.submission.get_submissions_by_account_problem_in_topic import * @api_view([POST,GET]) @@ -28,8 +29,12 @@ def account_problem_submission_view(request,problem_id,account_id): def all_submission_view(request): return get_submission_by_quries(request) +@api_view([POST,GET]) def topic_account_problem_submission_view(request,topic_id,account_id,problem_id): - return submit_problem_on_topic(account_id,problem_id,topic_id,request) + if request.method == POST: + return submit_problem_on_topic(account_id,problem_id,topic_id,request) + if request.method == GET: + return get_submissions_by_account_problem_in_topic(account_id,problem_id,topic_id) # @api_view([GET]) # def submission_account_problem_view(request,account_id:int,problem_id:int): From 5a00b0d4cffe9d3348fbbf23d7e8e9db44af4028 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 20 Dec 2023 17:10:25 +0700 Subject: [PATCH 36/61] Extend descirption length --- api/controllers/topic/get_topic_public.py | 1 + api/controllers/topic/update_topic.py | 1 + ...2_alter_collection_description_and_more.py | 28 +++++++++++++++++++ api/models.py | 6 ++-- 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 api/migrations/0042_alter_collection_description_and_more.py diff --git a/api/controllers/topic/get_topic_public.py b/api/controllers/topic/get_topic_public.py index 64eb926..177f894 100644 --- a/api/controllers/topic/get_topic_public.py +++ b/api/controllers/topic/get_topic_public.py @@ -23,6 +23,7 @@ def get_topic_public(topic_id:int,request): try: best_submission = BestSubmission.objects.get(problem=cp.problem,account=account,topic=topic) best_submission = best_submission.submission + best_submission.runtime_output = SubmissionTestcase.objects.filter(submission=best_submission) except: best_submission = None cp.problem.best_submission = best_submission diff --git a/api/controllers/topic/update_topic.py b/api/controllers/topic/update_topic.py index 7223acb..3a76351 100644 --- a/api/controllers/topic/update_topic.py +++ b/api/controllers/topic/update_topic.py @@ -15,5 +15,6 @@ def update_topic(topic_id:int,request): if topic_ser.is_valid(): topic_ser.save() return Response(topic_ser.data,status=status.HTTP_200_OK) + print(topic_ser.errors) return Response(topic_ser.errors,status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/api/migrations/0042_alter_collection_description_and_more.py b/api/migrations/0042_alter_collection_description_and_more.py new file mode 100644 index 0000000..8912bbd --- /dev/null +++ b/api/migrations/0042_alter_collection_description_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.1.2 on 2023-12-20 08:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0041_bestsubmission'), + ] + + operations = [ + migrations.AlterField( + model_name='collection', + name='description', + field=models.CharField(blank=True, default=None, max_length=100000, null=True), + ), + migrations.AlterField( + model_name='problem', + name='description', + field=models.CharField(max_length=100000), + ), + migrations.AlterField( + model_name='topic', + name='description', + field=models.CharField(blank=True, default=None, max_length=100000, null=True), + ), + ] diff --git a/api/models.py b/api/models.py index f2d19e5..a6d0fae 100644 --- a/api/models.py +++ b/api/models.py @@ -30,7 +30,7 @@ class Problem(models.Model): creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") language = models.CharField(max_length=15) # ,choices=ProgrammingLanguage.choices,default=ProgrammingLanguage.PYTHON) title = models.CharField(max_length=50) - description = models.CharField(max_length=10000) + description = models.CharField(max_length=100000) solution = models.CharField(max_length=20000) time_limit = models.FloatField(default=1.5,blank=True) is_active = models.BooleanField(default=True,blank=True) @@ -52,7 +52,7 @@ class Collection(models.Model): collection_id = models.AutoField(primary_key=True) creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) - description = models.CharField(max_length=1000,null=True,blank=True,default=None) + description = models.CharField(max_length=100000,null=True,blank=True,default=None) is_active = models.BooleanField(default=True,blank=True) is_private = models.BooleanField(default=False,blank=True) created_date = models.DateTimeField(default=timezone.now) @@ -62,7 +62,7 @@ class Topic(models.Model): topic_id = models.AutoField(primary_key=True) creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) - description = models.CharField(max_length=1000,null=True,blank=True,default=None) + description = models.CharField(max_length=100000,null=True,blank=True,default=None) image_url = models.ImageField(upload_to='topic/',null=True,blank=True,default=None) is_active = models.BooleanField(default=True,blank=True) is_private = models.BooleanField(default=False,blank=True) From 62541a32e7367b6133b016b4552897f4d584035b Mon Sep 17 00:00:00 2001 From: KanonKC Date: Fri, 22 Dec 2023 03:48:11 +0700 Subject: [PATCH 37/61] Valid description for older version --- api/views/script.py | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/api/views/script.py b/api/views/script.py index cd335f8..afc396b 100644 --- a/api/views/script.py +++ b/api/views/script.py @@ -22,17 +22,37 @@ # print(f"({count}/{total})") # return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) -@api_view([POST]) -def run_script(request): - submissionTestcases = SubmissionTestcase.objects.all() +# @api_view([POST]) +# def run_script(request): +# submissionTestcases = SubmissionTestcase.objects.all() - total = len(submissionTestcases) - count = 0 - for testcase in submissionTestcases: - if testcase.runtime_status == "OK" and (not testcase.is_passed): - testcase.runtime_status = "FAILED" - testcase.save() - count += 1 +# total = len(submissionTestcases) +# count = 0 +# for testcase in submissionTestcases: +# if testcase.runtime_status == "OK" and (not testcase.is_passed): +# testcase.runtime_status = "FAILED" +# testcase.save() +# count += 1 - print(f"({count}/{total})") +# print(f"({count}/{total})") +# return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) + +# @api_view([POST]) +# def run_script(request): +# topics = Topic.objects.all() +# for topic in topics: +# if len(topic.description) == 0: +# topic.description = f'[{{"id": "1","type": ELEMENT_PARAGRAPH,"children": [{{ "text": "" }}]}}]' +# topic.save() +# elif topic.description[0] != '[': +# topic.description = f'[{{"id": "1","type": ELEMENT_PARAGRAPH,"children": [{{ "text": "{topic.description}" }}]}}]' +# topic.save() +# return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) + +@api_view([POST]) +def run_script(request): + collections = Collection.objects.all() + for collection in collections: + collection.description = '[{"id":"1","type":"p","children":[{"text":"Just course"}]}]' + collection.save() return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) From c6d3372b85c924ebf800486cdcc1981b46c0bf91 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 23 Dec 2023 17:48:05 +0700 Subject: [PATCH 38/61] fix: submission serializer also include account --- api/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/serializers.py b/api/serializers.py index 12cdb64..b57fe1f 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -160,7 +160,7 @@ class SubmissionPopulateSubmissionTestcaseSecureSerializer(serializers.ModelSeri runtime_output = SubmissionTestcaseSecureSerializer(many=True) class Meta: model = Submission - fields = ['submission_id','problem','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] + fields = ['submission_id','account','problem','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] class ProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): # Add testcases field From 53a51bb426b68fdffa79020f0ac86098c1d71434 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 24 Dec 2023 20:37:31 +0700 Subject: [PATCH 39/61] DB updated script folder --- .../generate_failed_submission_status.py | 21 +++++++++++++++++++ .../script/generate_submission_score.py | 20 ++++++++++++++++++ .../replace_collections_empty_description.py | 14 +++++++++++++ .../script/replace_topic_empty_description.py | 18 ++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 api/controllers/script/generate_failed_submission_status.py create mode 100644 api/controllers/script/generate_submission_score.py create mode 100644 api/controllers/script/replace_collections_empty_description.py create mode 100644 api/controllers/script/replace_topic_empty_description.py diff --git a/api/controllers/script/generate_failed_submission_status.py b/api/controllers/script/generate_failed_submission_status.py new file mode 100644 index 0000000..7370b9f --- /dev/null +++ b/api/controllers/script/generate_failed_submission_status.py @@ -0,0 +1,21 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict + +def generate_failed_submission_status(request): + submissionTestcases = SubmissionTestcase.objects.all() + + total = len(submissionTestcases) + count = 0 + for testcase in submissionTestcases: + if testcase.runtime_status == "OK" and (not testcase.is_passed): + testcase.runtime_status = "FAILED" + testcase.save() + count += 1 + + print(f"({count}/{total})") + return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) diff --git a/api/controllers/script/generate_submission_score.py b/api/controllers/script/generate_submission_score.py new file mode 100644 index 0000000..dad390f --- /dev/null +++ b/api/controllers/script/generate_submission_score.py @@ -0,0 +1,20 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict + +def generate_submission_score(request): + submissions = Submission.objects.all() + total = len(submissions) + count = 0 + for submission in submissions: + submission.score = submission.result.count('P') + submission.max_score = len(submission.result) + submission.passed_ratio = submission.score/submission.max_score + submission.save() + count += 1 + print(f"({count}/{total})") + return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/controllers/script/replace_collections_empty_description.py b/api/controllers/script/replace_collections_empty_description.py new file mode 100644 index 0000000..1dc31e8 --- /dev/null +++ b/api/controllers/script/replace_collections_empty_description.py @@ -0,0 +1,14 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict + +def replace_collections_empty_description(request): + collections = Collection.objects.all() + for collection in collections: + collection.description = '[{"id":"1","type":"p","children":[{"text":"Just course"}]}]' + collection.save() + return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) diff --git a/api/controllers/script/replace_topic_empty_description.py b/api/controllers/script/replace_topic_empty_description.py new file mode 100644 index 0000000..e1fc519 --- /dev/null +++ b/api/controllers/script/replace_topic_empty_description.py @@ -0,0 +1,18 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict + +def replace_topic_empty_description(request): + topics = Topic.objects.all() + for topic in topics: + if len(topic.description) == 0: + topic.description = f'[{{"id": "1","type": ELEMENT_PARAGRAPH,"children": [{{ "text": "" }}]}}]' + topic.save() + elif topic.description[0] != '[': + topic.description = f'[{{"id": "1","type": ELEMENT_PARAGRAPH,"children": [{{ "text": "{topic.description}" }}]}}]' + topic.save() + return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) \ No newline at end of file From f9d71b064fd20b2b79e22df2877b233ba0292437 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 25 Dec 2023 18:28:02 +0700 Subject: [PATCH 40/61] Improve submission search quality --- .../submission/get_submission_by_quries.py | 30 ++++++++++++------- api/models.py | 23 +++++++++++++- api/serializers.py | 10 ++++++- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/api/controllers/submission/get_submission_by_quries.py b/api/controllers/submission/get_submission_by_quries.py index 99a0a62..216233e 100644 --- a/api/controllers/submission/get_submission_by_quries.py +++ b/api/controllers/submission/get_submission_by_quries.py @@ -9,7 +9,7 @@ from ...serializers import * def get_submission_by_quries(request): - submission = Submission.objects.all() + submissions = Submission.objects.all() # Query params problem_id = int(request.query_params.get("problem_id", 0)) @@ -18,28 +18,36 @@ def get_submission_by_quries(request): passed = int(request.query_params.get("passed", -1)) sort_score = int(request.query_params.get("sort_score", 0)) sort_date = int(request.query_params.get("sort_date", 0)) + start = int(request.query_params.get("start", -1)) + end = int(request.query_params.get("end", -1)) if problem_id != 0: - submission = submission.filter(problem_id=problem_id) + submissions = submissions.filter(problem_id=problem_id) if account_id != 0: - submission = submission.filter(account_id=account_id) + submissions = submissions.filter(account_id=account_id) if topic_id != 0: - submission = submission.filter(problem__topic_id=topic_id) + submissions = submissions.filter(problem__topic_id=topic_id) if passed == 0: - submission = submission.filter(is_passed=False) + submissions = submissions.filter(is_passed=False) elif passed == 1: - submission = submission.filter(is_passed=True) + submissions = submissions.filter(is_passed=True) if sort_score == -1: - submission = submission.order_by('passed_ratio') + submissions = submissions.order_by('passed_ratio') elif sort_score == 1: - submission = submission.order_by('-passed_ratio') + submissions = submissions.order_by('-passed_ratio') if sort_date == -1: - submission = submission.order_by('date') + submissions = submissions.order_by('date') elif sort_date == 1: - submission = submission.order_by('-date') + submissions = submissions.order_by('-date') + + if start != -1 and end != -1: + submissions = submissions[start:end] + + for submission in submissions: + submission.runtime_output = SubmissionTestcase.objects.filter(submission=submission) - serialize = SubmissionPoplulateProblemSerializer(submission,many=True) + serialize = SubmissionPopulateSubmissionTestcaseAndProblemSecureSerializer(submissions,many=True) return Response({"submissions": serialize.data},status=status.HTTP_200_OK) diff --git a/api/models.py b/api/models.py index a6d0fae..54dd897 100644 --- a/api/models.py +++ b/api/models.py @@ -114,4 +114,25 @@ class BestSubmission(models.Model): problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id",null=True) account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") - submission = models.ForeignKey(Submission,on_delete=models.CASCADE,db_column="submission_id") \ No newline at end of file + submission = models.ForeignKey(Submission,on_delete=models.CASCADE,db_column="submission_id") + +class Group(models.Model): + group_id = models.AutoField(primary_key=True) + creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") + name = models.CharField(max_length=100) + description = models.CharField(max_length=100000,null=True,blank=True,default=None) + +class TopicGroupPermission(models.Model): + topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") + group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") + permission_access = models.BooleanField(default=False,blank=True) + # สามารถเข้าถึง Course นี้ได้ โดยสามารถดูโจทย์ ส่งโจทย์ได้ + + permission_view_problems = models.BooleanField(default=False,blank=True) + # เข้าถึงโจทย์เชิงลึกแบบดู Testcases ได้ + permission_manage_collections = models.BooleanField(default=False,blank=True) + # จัดการเพิ่ม/ลบ โจทย์ออกจาก Collection ได้ + permission_manage_topic = models.BooleanField(default=False,blank=True) + # สามารถแก้ไข + permission_manage_members = models.BooleanField(default=False,blank=True) + \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index b57fe1f..78549fc 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -160,7 +160,15 @@ class SubmissionPopulateSubmissionTestcaseSecureSerializer(serializers.ModelSeri runtime_output = SubmissionTestcaseSecureSerializer(many=True) class Meta: model = Submission - fields = ['submission_id','account','problem','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] + fields = ['submission_id','account','problem','topic','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] + +class SubmissionPopulateSubmissionTestcaseAndProblemSecureSerializer(serializers.ModelSerializer): + # Add testcases field + runtime_output = SubmissionTestcaseSecureSerializer(many=True) + problem = ProblemSecureSerializer() + class Meta: + model = Submission + fields = ['submission_id','account','problem','topic','language','submission_code','is_passed','date','score','max_score','passed_ratio','runtime_output'] class ProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(serializers.ModelSerializer): # Add testcases field From f0150ce3676dee81adae2f89cbf4b245c804d5c5 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Mon, 25 Dec 2023 18:32:18 +0700 Subject: [PATCH 41/61] MOD-90: Model: Group, GroupMember --- api/migrations/0043_group_groupmember.py | 34 ++++++++++++++++++++++++ api/models.py | 31 ++++++++++++--------- 2 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 api/migrations/0043_group_groupmember.py diff --git a/api/migrations/0043_group_groupmember.py b/api/migrations/0043_group_groupmember.py new file mode 100644 index 0000000..68b0739 --- /dev/null +++ b/api/migrations/0043_group_groupmember.py @@ -0,0 +1,34 @@ +# Generated by Django 4.1.2 on 2023-12-25 11:30 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0042_alter_collection_description_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Group', + fields=[ + ('group_id', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=100)), + ('description', models.CharField(blank=True, default=None, max_length=100000, null=True)), + ('creator', models.ForeignKey(db_column='creator_id', on_delete=django.db.models.deletion.CASCADE, to='api.account')), + ], + ), + migrations.CreateModel( + name='GroupMember', + fields=[ + ('group_member_id', models.AutoField(primary_key=True, serialize=False)), + ('created_date', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_date', models.DateTimeField(default=django.utils.timezone.now)), + ('account', models.ForeignKey(db_column='account_id', on_delete=django.db.models.deletion.CASCADE, to='api.account')), + ('group', models.ForeignKey(db_column='group_id', on_delete=django.db.models.deletion.CASCADE, to='api.group')), + ], + ), + ] diff --git a/api/models.py b/api/models.py index 54dd897..f81316e 100644 --- a/api/models.py +++ b/api/models.py @@ -122,17 +122,24 @@ class Group(models.Model): name = models.CharField(max_length=100) description = models.CharField(max_length=100000,null=True,blank=True,default=None) -class TopicGroupPermission(models.Model): - topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") +class GroupMember(models.Model): + group_member_id = models.AutoField(primary_key=True) group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") - permission_access = models.BooleanField(default=False,blank=True) - # สามารถเข้าถึง Course นี้ได้ โดยสามารถดูโจทย์ ส่งโจทย์ได้ - - permission_view_problems = models.BooleanField(default=False,blank=True) - # เข้าถึงโจทย์เชิงลึกแบบดู Testcases ได้ - permission_manage_collections = models.BooleanField(default=False,blank=True) - # จัดการเพิ่ม/ลบ โจทย์ออกจาก Collection ได้ - permission_manage_topic = models.BooleanField(default=False,blank=True) - # สามารถแก้ไข - permission_manage_members = models.BooleanField(default=False,blank=True) + account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) + +# class TopicGroupPermission(models.Model): +# topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") +# group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") +# permission_access = models.BooleanField(default=False,blank=True) +# # สามารถเข้าถึง Course นี้ได้ โดยสามารถดูโจทย์ ส่งโจทย์ได้ + +# permission_view_problems = models.BooleanField(default=False,blank=True) +# # เข้าถึงโจทย์เชิงลึกแบบดู Testcases ได้ +# permission_manage_collections = models.BooleanField(default=False,blank=True) +# # จัดการเพิ่ม/ลบ โจทย์ออกจาก Collection ได้ +# permission_manage_topic = models.BooleanField(default=False,blank=True) +# # สามารถแก้ไข +# permission_manage_members = models.BooleanField(default=False,blank=True) \ No newline at end of file From 8b4836b6689a1138367c0a1f80fa4727d0020b14 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Tue, 26 Dec 2023 09:38:59 +0700 Subject: [PATCH 42/61] Group API (Not finished) --- api/controllers/group/create_group.py | 23 +++++++++++++ api/controllers/group/delete_group.py | 13 ++++++++ api/controllers/group/update_group.py | 20 +++++++++++ .../group/update_members_to_group.py | 22 +++++++++++++ ...ember_updated_date_group_color_and_more.py | 33 +++++++++++++++++++ api/models.py | 4 ++- api/serializers.py | 7 +++- api/views/group.py | 33 +++++++++++++++++++ 8 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 api/controllers/group/create_group.py create mode 100644 api/controllers/group/delete_group.py create mode 100644 api/controllers/group/update_group.py create mode 100644 api/controllers/group/update_members_to_group.py create mode 100644 api/migrations/0044_remove_groupmember_updated_date_group_color_and_more.py create mode 100644 api/views/group.py diff --git a/api/controllers/group/create_group.py b/api/controllers/group/create_group.py new file mode 100644 index 0000000..f6b3a5e --- /dev/null +++ b/api/controllers/group/create_group.py @@ -0,0 +1,23 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def create_group(account:Account,request): + + group = Group( + creator=account, + name=request.data['name'], + description=request.data['description'] if 'description' in request.data else None, + color=request.data['color'] if 'color' in request.data else None, + ) + + group.save() + serialize = GroupSerializer(group) + + return Response(serialize.data,status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/api/controllers/group/delete_group.py b/api/controllers/group/delete_group.py new file mode 100644 index 0000000..145b084 --- /dev/null +++ b/api/controllers/group/delete_group.py @@ -0,0 +1,13 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def delete_group(group:Group,request): + group.delete() + return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file diff --git a/api/controllers/group/update_group.py b/api/controllers/group/update_group.py new file mode 100644 index 0000000..d1e1d4f --- /dev/null +++ b/api/controllers/group/update_group.py @@ -0,0 +1,20 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_group(group:Group,request): + + group.name = request.data.get('name',group.name) + group.description = request.data.get('description',group.description) + group.color = request.data.get('color',group.color) + + group.save() + serialize = GroupSerializer(group) + + return Response(serialize.data,status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/group/update_members_to_group.py b/api/controllers/group/update_members_to_group.py new file mode 100644 index 0000000..9dc8c9b --- /dev/null +++ b/api/controllers/group/update_members_to_group.py @@ -0,0 +1,22 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_members_to_group(group:Group,request): + GroupMember.objects.filter(group=group).delete() + + group_members = [] + for accountId in request.data['account_ids']: + account = Account.objects.get(account_id=accountId) + group_members.append(GroupMember( + group=group, + account=account + )) + + GroupMember.objects.bulk_create(group_members) \ No newline at end of file diff --git a/api/migrations/0044_remove_groupmember_updated_date_group_color_and_more.py b/api/migrations/0044_remove_groupmember_updated_date_group_color_and_more.py new file mode 100644 index 0000000..1a32570 --- /dev/null +++ b/api/migrations/0044_remove_groupmember_updated_date_group_color_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.1.2 on 2023-12-25 11:55 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0043_group_groupmember'), + ] + + operations = [ + migrations.RemoveField( + model_name='groupmember', + name='updated_date', + ), + migrations.AddField( + model_name='group', + name='color', + field=models.CharField(blank=True, default=None, max_length=10, null=True), + ), + migrations.AddField( + model_name='group', + name='created_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AddField( + model_name='group', + name='updated_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/api/models.py b/api/models.py index f81316e..38e08f5 100644 --- a/api/models.py +++ b/api/models.py @@ -121,13 +121,15 @@ class Group(models.Model): creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) description = models.CharField(max_length=100000,null=True,blank=True,default=None) + color = models.CharField(max_length=10,null=True,blank=True,default=None) + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) class GroupMember(models.Model): group_member_id = models.AutoField(primary_key=True) group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") created_date = models.DateTimeField(default=timezone.now) - updated_date = models.DateTimeField(default=timezone.now) # class TopicGroupPermission(models.Model): # topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") diff --git a/api/serializers.py b/api/serializers.py index 78549fc..58f514f 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -229,4 +229,9 @@ class TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemPop collections = TopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemPopulateAccountAndSubmissionPopulateSubmissionTestcasesSecureSerializer(many=True) class Meta: model = Topic - fields = ['topic_id','name','description','image_url','created_date','updated_date','collections'] \ No newline at end of file + fields = ['topic_id','name','description','image_url','created_date','updated_date','collections'] + +class GroupSerializer(serializers.ModelSerializer): + class Meta: + model = Group + fields = "__all__" \ No newline at end of file diff --git a/api/views/group.py b/api/views/group.py new file mode 100644 index 0000000..a9fb680 --- /dev/null +++ b/api/views/group.py @@ -0,0 +1,33 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ..constant import GET,POST,PUT,DELETE +from ..models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ..serializers import * +from ..controllers.group.create_group import create_group +from ..controllers.group.update_group import update_group +from ..controllers.group.delete_group import delete_group +from ..controllers.group.update_members_to_group import update_members_to_group + +@api_view([POST]) +def all_groups_creator_view(request,account_id:int): + account = Account.objects.get(account_id=account_id) + if request.method == POST: + return create_group(request) + +@api_view([PUT,DELETE]) +def one_group_creator_view(request,group_id:int): + group = Group.objects.get(group_id=group_id) + if request.method == PUT: + return update_group(group,request) + elif request.method == DELETE: + return delete_group(group,request) + +@api_view([PUT]) +def group_members_view(request,group_id:int): + group = Group.objects.get(group_id=group_id) + if request.method == PUT: + return update_members_to_group(group,request) \ No newline at end of file From 4f2d919104ec67c0d410cb487f799c67b97cf045 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 27 Dec 2023 22:56:58 +0700 Subject: [PATCH 43/61] More group apis --- api/controllers/group/create_group.py | 21 +++++++++---------- api/controllers/group/get_group.py | 20 ++++++++++++++++++ api/controllers/group/update_group.py | 19 ++++++++++------- .../group/update_members_to_group.py | 6 +++++- api/sandbox/section1/runner.c | 6 +----- api/serializers.py | 18 +++++++++++++++- api/urls.py | 9 ++++++-- api/views/group.py | 11 ++++++---- 8 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 api/controllers/group/get_group.py diff --git a/api/controllers/group/create_group.py b/api/controllers/group/create_group.py index f6b3a5e..4211b3a 100644 --- a/api/controllers/group/create_group.py +++ b/api/controllers/group/create_group.py @@ -9,15 +9,14 @@ from ...serializers import * def create_group(account:Account,request): + + serialize = GroupSerializer(data={ + 'creator':account.account_id, + **request.data + }) - group = Group( - creator=account, - name=request.data['name'], - description=request.data['description'] if 'description' in request.data else None, - color=request.data['color'] if 'color' in request.data else None, - ) - - group.save() - serialize = GroupSerializer(group) - - return Response(serialize.data,status=status.HTTP_201_CREATED) \ No newline at end of file + if serialize.is_valid(): + serialize.save() + return Response(serialize.data,status=status.HTTP_201_CREATED) + else: + return Response(serialize.errors,status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/api/controllers/group/get_group.py b/api/controllers/group/get_group.py new file mode 100644 index 0000000..c506ece --- /dev/null +++ b/api/controllers/group/get_group.py @@ -0,0 +1,20 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_group(group:Group,request): + + populate_members = request.GET.get('populate_members',False) + + if populate_members: + group.members = GroupMember.objects.filter(group=group) + serialize = GroupPopulateGroupMemberPopulateAccountSecureSerializer(group) + else: + serialize = GroupSerializer(group) + return Response(serialize.data,status=status.HTTP_200_OK) diff --git a/api/controllers/group/update_group.py b/api/controllers/group/update_group.py index d1e1d4f..e4008b5 100644 --- a/api/controllers/group/update_group.py +++ b/api/controllers/group/update_group.py @@ -7,14 +7,17 @@ from rest_framework import status from django.forms.models import model_to_dict from ...serializers import * +from datetime import datetime def update_group(group:Group,request): - group.name = request.data.get('name',group.name) - group.description = request.data.get('description',group.description) - group.color = request.data.get('color',group.color) - - group.save() - serialize = GroupSerializer(group) - - return Response(serialize.data,status=status.HTTP_200_OK) \ No newline at end of file + serializer = GroupSerializer(group,data={ + **request.data, + 'updated_date': datetime.now() + },partial=True) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data,status=status.HTTP_200_OK) + else: + return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/api/controllers/group/update_members_to_group.py b/api/controllers/group/update_members_to_group.py index 9dc8c9b..99a05cd 100644 --- a/api/controllers/group/update_members_to_group.py +++ b/api/controllers/group/update_members_to_group.py @@ -19,4 +19,8 @@ def update_members_to_group(group:Group,request): account=account )) - GroupMember.objects.bulk_create(group_members) \ No newline at end of file + GroupMember.objects.bulk_create(group_members) + group.members = group_members + + serialize = GroupPopulateGroupMemberPopulateAccountSecureSerializer(group) + return Response(serialize.data,status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/sandbox/section1/runner.c b/api/sandbox/section1/runner.c index 207357b..bf28f2e 100644 --- a/api/sandbox/section1/runner.c +++ b/api/sandbox/section1/runner.c @@ -1,5 +1 @@ -#include - -int main() { - printf("Hello World!\n"); -} \ No newline at end of file +n = int(input('N: '));print(2/) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 58f514f..2a30842 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -234,4 +234,20 @@ class Meta: class GroupSerializer(serializers.ModelSerializer): class Meta: model = Group - fields = "__all__" \ No newline at end of file + fields = "__all__" + +class GroupMemberSerializer(serializers.ModelSerializer): + class Meta: + model = GroupMember + fields = "__all__" +class GroupMemberPopulateAccountSecureSerializer(serializers.ModelSerializer): + account = AccountSecureSerializer() + class Meta: + model = GroupMember + fields = "__all__" + +class GroupPopulateGroupMemberPopulateAccountSecureSerializer(serializers.ModelSerializer): + members = GroupMemberPopulateAccountSecureSerializer(many=True) + class Meta: + model = Group + fields = ['group_id','name','description','color','created_date','updated_date','creator','members'] \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index caa4ed0..68591c5 100644 --- a/api/urls.py +++ b/api/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from .views import account,auth,problem, script,submission,topic,collection +from .views import account,auth,problem, script,submission,topic,collection,group urlpatterns = [ @@ -22,7 +22,9 @@ path('accounts//topics',topic.all_topics_creator_view), path('accounts//topics/',topic.one_topic_creator_view), - + + path('accounts//groups',group.all_groups_creator_view), + path('problems',problem.all_problems_view), path('problems/validate',problem.validation_view), path('problems/',problem.one_problem_view), @@ -37,6 +39,9 @@ path('topics//access',topic.account_access), path('topics//collections/',topic.topic_collections_view), + path('groups/',group.one_group_view), + path('groups//members',group.group_members_view), + path('submissions',submission.all_submission_view), diff --git a/api/views/group.py b/api/views/group.py index a9fb680..f579b57 100644 --- a/api/views/group.py +++ b/api/views/group.py @@ -11,23 +11,26 @@ from ..controllers.group.update_group import update_group from ..controllers.group.delete_group import delete_group from ..controllers.group.update_members_to_group import update_members_to_group +from ..controllers.group.get_group import get_group @api_view([POST]) def all_groups_creator_view(request,account_id:int): account = Account.objects.get(account_id=account_id) if request.method == POST: - return create_group(request) + return create_group(account,request) -@api_view([PUT,DELETE]) -def one_group_creator_view(request,group_id:int): +@api_view([PUT,DELETE,GET]) +def one_group_view(request,group_id:int): group = Group.objects.get(group_id=group_id) if request.method == PUT: return update_group(group,request) elif request.method == DELETE: return delete_group(group,request) + elif request.method == GET: + return get_group(group,request) @api_view([PUT]) -def group_members_view(request,group_id:int): +def group_members_view(request,account_id:int,group_id:int): group = Group.objects.get(group_id=group_id) if request.method == PUT: return update_members_to_group(group,request) \ No newline at end of file From c1fa2e308979c29cca9c08e11a19f7539dae3f78 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Fri, 29 Dec 2023 11:16:45 +0700 Subject: [PATCH 44/61] MOD-91: Basic API for Group --- Backend/settings.py | 1 + .../group/get_all_groups_by_account.py | 23 +++++++++++++++++++ api/controllers/group/update_group.py | 2 +- api/views/group.py | 7 ++++-- 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 api/controllers/group/get_all_groups_by_account.py diff --git a/Backend/settings.py b/Backend/settings.py index deb18fb..8553696 100644 --- a/Backend/settings.py +++ b/Backend/settings.py @@ -47,6 +47,7 @@ "http://192.168.216.250:3000", "http://192.168.0.2:3000", "http://192.168.0.5:3000", + "http://192.168.0.11:5173", FRONEND_URL ] diff --git a/api/controllers/group/get_all_groups_by_account.py b/api/controllers/group/get_all_groups_by_account.py new file mode 100644 index 0000000..c3fee84 --- /dev/null +++ b/api/controllers/group/get_all_groups_by_account.py @@ -0,0 +1,23 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_groups_by_account(account:Account,request): + + groups = Group.objects.filter(creator=account).order_by('-updated_date') + + populate_members = request.GET.get('populate_members',False) + + if populate_members: + for group in groups: + group.members = GroupMember.objects.filter(group=group) + serialize = GroupPopulateGroupMemberPopulateAccountSecureSerializer(groups,many=True) + else: + serialize = GroupSerializer(groups,many=True) + return Response({"groups":serialize.data},status=status.HTTP_200_OK) diff --git a/api/controllers/group/update_group.py b/api/controllers/group/update_group.py index e4008b5..80bc9f7 100644 --- a/api/controllers/group/update_group.py +++ b/api/controllers/group/update_group.py @@ -13,7 +13,7 @@ def update_group(group:Group,request): serializer = GroupSerializer(group,data={ **request.data, - 'updated_date': datetime.now() + 'updated_date': timezone.now() },partial=True) if serializer.is_valid(): diff --git a/api/views/group.py b/api/views/group.py index f579b57..e9d95d3 100644 --- a/api/views/group.py +++ b/api/views/group.py @@ -12,12 +12,15 @@ from ..controllers.group.delete_group import delete_group from ..controllers.group.update_members_to_group import update_members_to_group from ..controllers.group.get_group import get_group +from ..controllers.group.get_all_groups_by_account import get_all_groups_by_account -@api_view([POST]) +@api_view([POST,GET]) def all_groups_creator_view(request,account_id:int): account = Account.objects.get(account_id=account_id) if request.method == POST: return create_group(account,request) + elif request.method == GET: + return get_all_groups_by_account(account,request) @api_view([PUT,DELETE,GET]) def one_group_view(request,group_id:int): @@ -30,7 +33,7 @@ def one_group_view(request,group_id:int): return get_group(group,request) @api_view([PUT]) -def group_members_view(request,account_id:int,group_id:int): +def group_members_view(request,group_id:int): group = Group.objects.get(group_id=group_id) if request.method == PUT: return update_members_to_group(group,request) \ No newline at end of file From cac6066ea71fb669794450faa85475819dbc229a Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 31 Dec 2023 14:34:57 +0700 Subject: [PATCH 45/61] Change ID from sequence number to random uuid4 --- api/controllers/account/get_account.py | 2 +- .../collection/create_collection.py | 2 +- .../get_all_collections_by_account.py | 2 +- api/controllers/collection/get_collection.py | 2 +- .../collection/update_collection.py | 2 +- api/controllers/problem/create_problem.py | 2 +- api/controllers/problem/delete_problem.py | 2 +- .../get_all_problem_with_best_submission.py | 2 +- .../problem/get_all_problems_by_account.py | 2 +- api/controllers/problem/get_problem.py | 2 +- ...t_problem_in_topic_with_best_submission.py | 2 +- api/controllers/problem/update_problem.py | 25 +++-- .../get_submissions_by_account_problem.py | 6 +- ...submissions_by_account_problem_in_topic.py | 4 +- api/controllers/submission/submit_problem.py | 4 +- .../submission/submit_problem_on_topic.py | 2 +- .../topic/add_collections_to_topic.py | 2 +- api/controllers/topic/create_topic.py | 2 +- api/controllers/topic/delete_topic.py | 2 +- .../get_all_accessed_topics_by_account.py | 18 ++++ .../topic/get_all_topics_by_account.py | 2 +- api/controllers/topic/get_topic.py | 2 +- api/controllers/topic/get_topic_public.py | 2 +- .../topic/remove_collections_from_topic.py | 2 +- .../update_groups_permission_to_topic.py | 29 ++++++ api/controllers/topic/update_topic.py | 2 +- .../0045_collection_sharing_and_more.py | 95 +++++++++++++++++++ .../0046_alter_account_account_id_and_more.py | 78 +++++++++++++++ .../0047_alter_account_account_id_and_more.py | 78 +++++++++++++++ .../0048_alter_account_account_id_and_more.py | 78 +++++++++++++++ .../0049_alter_account_account_id_and_more.py | 88 +++++++++++++++++ .../0050_alter_account_account_id_and_more.py | 88 +++++++++++++++++ .../0051_alter_account_account_id_and_more.py | 89 +++++++++++++++++ api/models.py | 61 +++++++++--- api/serializers.py | 13 ++- api/urls.py | 45 +++++---- api/views/account.py | 2 +- api/views/collection.py | 8 +- api/views/group.py | 6 +- api/views/problem.py | 4 +- api/views/submission.py | 2 +- api/views/topic.py | 20 +++- 42 files changed, 798 insertions(+), 83 deletions(-) create mode 100644 api/controllers/topic/get_all_accessed_topics_by_account.py create mode 100644 api/controllers/topic/update_groups_permission_to_topic.py create mode 100644 api/migrations/0045_collection_sharing_and_more.py create mode 100644 api/migrations/0046_alter_account_account_id_and_more.py create mode 100644 api/migrations/0047_alter_account_account_id_and_more.py create mode 100644 api/migrations/0048_alter_account_account_id_and_more.py create mode 100644 api/migrations/0049_alter_account_account_id_and_more.py create mode 100644 api/migrations/0050_alter_account_account_id_and_more.py create mode 100644 api/migrations/0051_alter_account_account_id_and_more.py diff --git a/api/controllers/account/get_account.py b/api/controllers/account/get_account.py index 68485ff..275d3f9 100644 --- a/api/controllers/account/get_account.py +++ b/api/controllers/account/get_account.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_account(account_id:int): +def get_account(account_id:str): try: account = Account.objects.get(account_id=account_id) serialize = AccountSerializer(account) diff --git a/api/controllers/collection/create_collection.py b/api/controllers/collection/create_collection.py index 8894516..f5541bc 100644 --- a/api/controllers/collection/create_collection.py +++ b/api/controllers/collection/create_collection.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def create_collection(account_id:int,request): +def create_collection(account_id:str,request): request.data['creator'] = account_id serialize = CollectionSerializer(data=request.data) diff --git a/api/controllers/collection/get_all_collections_by_account.py b/api/controllers/collection/get_all_collections_by_account.py index b4f64af..be88a0b 100644 --- a/api/controllers/collection/get_all_collections_by_account.py +++ b/api/controllers/collection/get_all_collections_by_account.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_all_collections_by_account(account_id:int): +def get_all_collections_by_account(account_id:str): collections = Collection.objects.filter(creator=account_id).order_by('-updated_date') problemCollections = CollectionProblem.objects.filter(collection__in=collections) diff --git a/api/controllers/collection/get_collection.py b/api/controllers/collection/get_collection.py index 1814b0c..b3e0a77 100644 --- a/api/controllers/collection/get_collection.py +++ b/api/controllers/collection/get_collection.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_collection(collection_id:int): +def get_collection(collection_id:str): collection = Collection.objects.get(collection_id=collection_id) # problems = Problem.objects.filter(collectionproblem__collection_id=collection_id) diff --git a/api/controllers/collection/update_collection.py b/api/controllers/collection/update_collection.py index 5abdc62..aa2df34 100644 --- a/api/controllers/collection/update_collection.py +++ b/api/controllers/collection/update_collection.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def update_collection(collection_id:int,request): +def update_collection(collection_id:str,request): collection = Collection.objects.get(collection_id=collection_id) collection.name = request.data.get('name',collection.name) diff --git a/api/controllers/problem/create_problem.py b/api/controllers/problem/create_problem.py index 3998d2e..16fb7a5 100644 --- a/api/controllers/problem/create_problem.py +++ b/api/controllers/problem/create_problem.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def create_problem(account_id:int,request): +def create_problem(account_id:str,request): account = Account.objects.get(account_id=account_id) running_result = PythonGrader(request.data['solution'],request.data['testcases'],1,1.5).generate_output() diff --git a/api/controllers/problem/delete_problem.py b/api/controllers/problem/delete_problem.py index 4140824..bcc75f2 100644 --- a/api/controllers/problem/delete_problem.py +++ b/api/controllers/problem/delete_problem.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def delete_problem(problem_id:int): +def delete_problem(problem_id:str): try: problem = Problem.objects.get(problem_id=problem_id) except Problem.DoesNotExist: diff --git a/api/controllers/problem/get_all_problem_with_best_submission.py b/api/controllers/problem/get_all_problem_with_best_submission.py index f2d6741..679fac0 100644 --- a/api/controllers/problem/get_all_problem_with_best_submission.py +++ b/api/controllers/problem/get_all_problem_with_best_submission.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_all_problem_with_best_submission(account_id:int): +def get_all_problem_with_best_submission(account_id:str): problems = Problem.objects.all().order_by('-updated_date') diff --git a/api/controllers/problem/get_all_problems_by_account.py b/api/controllers/problem/get_all_problems_by_account.py index bae9918..27dd562 100644 --- a/api/controllers/problem/get_all_problems_by_account.py +++ b/api/controllers/problem/get_all_problems_by_account.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_all_problems_by_account(account_id:int): +def get_all_problems_by_account(account_id:str): problems = Problem.objects.filter(creator=account_id).order_by('-updated_date') for problem in problems: diff --git a/api/controllers/problem/get_problem.py b/api/controllers/problem/get_problem.py index 56f78f8..664a957 100644 --- a/api/controllers/problem/get_problem.py +++ b/api/controllers/problem/get_problem.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_problem(problem_id:int): +def get_problem(problem_id:str): try: problem = Problem.objects.get(problem_id=problem_id) except Problem.DoesNotExist: diff --git a/api/controllers/problem/get_problem_in_topic_with_best_submission.py b/api/controllers/problem/get_problem_in_topic_with_best_submission.py index 0be0585..d708d21 100644 --- a/api/controllers/problem/get_problem_in_topic_with_best_submission.py +++ b/api/controllers/problem/get_problem_in_topic_with_best_submission.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_problem_in_topic_with_best_submission(account_id:int,topic_id:int,problem:int): +def get_problem_in_topic_with_best_submission(account_id:str,topic_id:str,problem:int): account = Account.objects.get(account_id=account_id) problem = Problem.objects.get(problem_id=problem) diff --git a/api/controllers/problem/update_problem.py b/api/controllers/problem/update_problem.py index 3380add..d60f98a 100644 --- a/api/controllers/problem/update_problem.py +++ b/api/controllers/problem/update_problem.py @@ -9,13 +9,15 @@ from ...serializers import * from django.utils import timezone -def update_problem(problem_id:int,request): +def update_problem(problem_id:str,request): try: problem = Problem.objects.get(problem_id=problem_id) except Problem.DoesNotExist: return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) + print("AAA") + problem.title = request.data.get("title",problem.title) problem.language = request.data.get("language",problem.language) problem.description = request.data.get("description",problem.description) @@ -25,40 +27,47 @@ def update_problem(problem_id:int,request): problem.updated_date = timezone.now() + print("BBB") + if 'testcases' in request.data: running_result = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() # if not running_result.runnable: # return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) - + print("ZZZZZ") for testcase in testcases: testcase.deprecated = True testcase.save() - + print("ZZZZZ") testcase_result = [] for unit in running_result.data: - testcase = Testcase( + print("YYYYY") + testcase2 = Testcase( problem = problem, input = unit.input, output = unit.output, runtime_status = unit.runtime_status ) - testcase.save() - testcase_result.append(testcase) + print("YYYYY",testcase2.testcase_id) + testcase2.save() + print("YYYYY") + testcase_result.append(testcase2) problem.save() - + print("ZZZZZ") problem_serialize = ProblemSerializer(problem) testcases_serialize = TestcaseSerializer(testcase_result,many=True) return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_201_CREATED) - elif 'solution' in request.data: + if 'solution' in request.data: + testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) program_input = [i.input for i in testcases] running_result = PythonGrader(problem.solution,program_input,1,1.5).generate_output() if not running_result.runnable: return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) + print("CCC") problem.save() problem_serialize = ProblemSerializer(problem) return Response(problem_serialize.data,status=status.HTTP_201_CREATED) diff --git a/api/controllers/submission/get_submissions_by_account_problem.py b/api/controllers/submission/get_submissions_by_account_problem.py index 5c5ff9c..7c98e32 100644 --- a/api/controllers/submission/get_submissions_by_account_problem.py +++ b/api/controllers/submission/get_submissions_by_account_problem.py @@ -8,15 +8,15 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_submissions_by_account_problem(account_id:int,problem_id:int): +def get_submissions_by_account_problem(account_id:str,problem_id:str): submissions = Submission.objects.filter(account=account_id,problem=problem_id) if submissions.count() == 0: return Response({"best_submission": None,"submissions": []},status=status.HTTP_204_NO_CONTENT) - submissions = submissions.order_by('-submission_id') + submissions = submissions.order_by('-date') - best_submission_id = submissions.order_by('-passed_ratio','-submission_id').first().submission_id + best_submission_id = submissions.order_by('-passed_ratio','-date').first().submission_id best_submission = None result = [] diff --git a/api/controllers/submission/get_submissions_by_account_problem_in_topic.py b/api/controllers/submission/get_submissions_by_account_problem_in_topic.py index 7e7b91f..5c96f49 100644 --- a/api/controllers/submission/get_submissions_by_account_problem_in_topic.py +++ b/api/controllers/submission/get_submissions_by_account_problem_in_topic.py @@ -8,13 +8,13 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_submissions_by_account_problem_in_topic(account_id:int,problem_id:int,topic_id:int): +def get_submissions_by_account_problem_in_topic(account_id:str,problem_id:str,topic_id:str): submissions = Submission.objects.filter(account=account_id,problem=problem_id,topic_id=topic_id) if submissions.count() == 0: return Response({"best_submission": None,"submissions": []},status=status.HTTP_204_NO_CONTENT) - submissions = submissions.order_by('-submission_id') + submissions = submissions.order_by('-date') result = [] diff --git a/api/controllers/submission/submit_problem.py b/api/controllers/submission/submit_problem.py index 1fa1b8d..9d1e9be 100644 --- a/api/controllers/submission/submit_problem.py +++ b/api/controllers/submission/submit_problem.py @@ -19,7 +19,7 @@ def avaliableQueue(): return i return -1 -def submit_problem_function(account_id:int,problem_id:int,topic_id:int,request): +def submit_problem_function(account_id:str,problem_id:str,topic_id:str,request): global QUEUE problem = Problem.objects.get(problem_id=problem_id) testcases = Testcase.objects.filter(problem=problem,deprecated=False) @@ -101,5 +101,5 @@ def submit_problem_function(account_id:int,problem_id:int,topic_id:int,request): return Response(testser.data,status=status.HTTP_201_CREATED) -def submit_problem(account_id:int,problem_id:int,request): +def submit_problem(account_id:str,problem_id:str,request): return submit_problem_function(account_id,problem_id,None,request) \ No newline at end of file diff --git a/api/controllers/submission/submit_problem_on_topic.py b/api/controllers/submission/submit_problem_on_topic.py index b2940e8..5d7d93f 100644 --- a/api/controllers/submission/submit_problem_on_topic.py +++ b/api/controllers/submission/submit_problem_on_topic.py @@ -11,5 +11,5 @@ from time import sleep from .submit_problem import * -def submit_problem_on_topic(account_id:int,problem_id:int,topic_id:int,request): +def submit_problem_on_topic(account_id:str,problem_id:str,topic_id:str,request): return submit_problem_function(account_id,problem_id,topic_id,request) \ No newline at end of file diff --git a/api/controllers/topic/add_collections_to_topic.py b/api/controllers/topic/add_collections_to_topic.py index 14c85c7..936e05f 100644 --- a/api/controllers/topic/add_collections_to_topic.py +++ b/api/controllers/topic/add_collections_to_topic.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def add_collections_to_topic(topic_id:int,request): +def add_collections_to_topic(topic_id:str,request): topic = Topic.objects.get(topic_id=topic_id) populated_collections = [] diff --git a/api/controllers/topic/create_topic.py b/api/controllers/topic/create_topic.py index aa9d678..12557ce 100644 --- a/api/controllers/topic/create_topic.py +++ b/api/controllers/topic/create_topic.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def create_topic(account_id:int,request): +def create_topic(account_id:str,request): request.data._mutable=True request.data['creator'] = account_id serializer = TopicSerializer(data=request.data) diff --git a/api/controllers/topic/delete_topic.py b/api/controllers/topic/delete_topic.py index 67cb6c2..74938fc 100644 --- a/api/controllers/topic/delete_topic.py +++ b/api/controllers/topic/delete_topic.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def delete_topic(topic_id:int): +def delete_topic(topic_id:str): topic = Topic.objects.get(topic_id=topic_id) topic.delete() return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/api/controllers/topic/get_all_accessed_topics_by_account.py b/api/controllers/topic/get_all_accessed_topics_by_account.py new file mode 100644 index 0000000..019b175 --- /dev/null +++ b/api/controllers/topic/get_all_accessed_topics_by_account.py @@ -0,0 +1,18 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_all_accessed_topics_by_account(account:Account): + groups = [gm.group for gm in GroupMember.objects.filter(account=account)] + accessedTopics = TopicGroupPermission.objects.filter(group__in=groups).distinct() + topics = [at.topic for at in accessedTopics] + + serialize = TopicSerializer(topics,many=True) + + return Response({'topics':serialize.data},status=status.HTTP_204_NO_CONTENT) diff --git a/api/controllers/topic/get_all_topics_by_account.py b/api/controllers/topic/get_all_topics_by_account.py index d9dd97b..5d71a84 100644 --- a/api/controllers/topic/get_all_topics_by_account.py +++ b/api/controllers/topic/get_all_topics_by_account.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_all_topics_by_account(account_id:int,request): +def get_all_topics_by_account(account_id:str,request): topics = Topic.objects.filter(creator_id=account_id).order_by('-updated_date') topicCollections = TopicCollection.objects.filter(topic__in=topics) diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py index 89f37b4..6a17ce1 100644 --- a/api/controllers/topic/get_topic.py +++ b/api/controllers/topic/get_topic.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_topic(topic_id:int): +def get_topic(topic_id:str): topic = Topic.objects.get(topic_id=topic_id) topic.collections = TopicCollection.objects.filter(topic_id=topic_id) serialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(topic) diff --git a/api/controllers/topic/get_topic_public.py b/api/controllers/topic/get_topic_public.py index 177f894..b05513e 100644 --- a/api/controllers/topic/get_topic_public.py +++ b/api/controllers/topic/get_topic_public.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_topic_public(topic_id:int,request): +def get_topic_public(topic_id:str,request): account_id = request.query_params.get('account_id',None) diff --git a/api/controllers/topic/remove_collections_from_topic.py b/api/controllers/topic/remove_collections_from_topic.py index 1275956..74ac26e 100644 --- a/api/controllers/topic/remove_collections_from_topic.py +++ b/api/controllers/topic/remove_collections_from_topic.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def remove_collections_from_topic(topic_id:int,request): +def remove_collections_from_topic(topic_id:str,request): TopicCollection.objects.filter(topic_id=topic_id,collection_id__in=request.data['collection_ids']).delete() # collections = Collection.objects.filter(collection_id__in=request.data['collection_ids']) # problems = Problem.objects.filter(problem_id__in=request.data['problems_id']) diff --git a/api/controllers/topic/update_groups_permission_to_topic.py b/api/controllers/topic/update_groups_permission_to_topic.py new file mode 100644 index 0000000..5831898 --- /dev/null +++ b/api/controllers/topic/update_groups_permission_to_topic.py @@ -0,0 +1,29 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_groups_permission_to_topic(topic:Topic,request): + + topic_group_permissions = [] + for group_request in request.data['groups']: + print(group_request) + group = Group.objects.get(group_id=group_request['group_id']) + topic_group_permissions.append( + TopicGroupPermission( + topic=topic, + group=group, + **group_request + )) + + TopicGroupPermission.objects.bulk_create(topic_group_permissions) + + topic.group_permissions = topic_group_permissions + serialize = TopicPopulateTopicGroupPermissionsSerializer(topic) + + return Response(serialize.data,status=status.HTTP_202_ACCEPTED) \ No newline at end of file diff --git a/api/controllers/topic/update_topic.py b/api/controllers/topic/update_topic.py index 3a76351..f094c05 100644 --- a/api/controllers/topic/update_topic.py +++ b/api/controllers/topic/update_topic.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def update_topic(topic_id:int,request): +def update_topic(topic_id:str,request): topic = Topic.objects.get(topic_id=topic_id) topic_ser = TopicSerializer(topic,data=request.data,partial=True) diff --git a/api/migrations/0045_collection_sharing_and_more.py b/api/migrations/0045_collection_sharing_and_more.py new file mode 100644 index 0000000..ccd65f3 --- /dev/null +++ b/api/migrations/0045_collection_sharing_and_more.py @@ -0,0 +1,95 @@ +# Generated by Django 4.1.2 on 2023-12-30 13:02 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0044_remove_groupmember_updated_date_group_color_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='collection', + name='sharing', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='group', + name='permission_manage_collections', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='group', + name='permission_manage_problems', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='group', + name='permission_manage_topics', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='group', + name='permission_view_collections', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='group', + name='permission_view_problems', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='group', + name='permission_view_topics', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='group', + name='permission_view_topics_log', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='problem', + name='sharing', + field=models.BooleanField(blank=True, default=False), + ), + migrations.AddField( + model_name='topic', + name='sharing', + field=models.BooleanField(blank=True, default=False), + ), + migrations.CreateModel( + name='TopicGroupPermission', + fields=[ + ('topic_group_permission_id', models.AutoField(primary_key=True, serialize=False)), + ('permission_manage_topics', models.BooleanField(blank=True, default=False)), + ('permission_view_topics', models.BooleanField(blank=True, default=False)), + ('permission_view_topics_log', models.BooleanField(blank=True, default=False)), + ('group', models.ForeignKey(db_column='group_id', on_delete=django.db.models.deletion.CASCADE, to='api.group')), + ('topic', models.ForeignKey(db_column='topic_id', on_delete=django.db.models.deletion.CASCADE, to='api.topic')), + ], + ), + migrations.CreateModel( + name='ProblemGroupPermission', + fields=[ + ('problem_group_permission_id', models.AutoField(primary_key=True, serialize=False)), + ('permission_manage_problems', models.BooleanField(blank=True, default=False)), + ('permission_view_problems', models.BooleanField(blank=True, default=False)), + ('group', models.ForeignKey(db_column='group_id', on_delete=django.db.models.deletion.CASCADE, to='api.group')), + ('problem', models.ForeignKey(db_column='problem_id', on_delete=django.db.models.deletion.CASCADE, to='api.problem')), + ], + ), + migrations.CreateModel( + name='CollectionGroupPermission', + fields=[ + ('collection_group_permission_id', models.AutoField(primary_key=True, serialize=False)), + ('permission_manage_collections', models.BooleanField(blank=True, default=False)), + ('permission_view_collections', models.BooleanField(blank=True, default=False)), + ('collection', models.ForeignKey(db_column='collection_id', on_delete=django.db.models.deletion.CASCADE, to='api.collection')), + ('group', models.ForeignKey(db_column='group_id', on_delete=django.db.models.deletion.CASCADE, to='api.group')), + ], + ), + ] diff --git a/api/migrations/0046_alter_account_account_id_and_more.py b/api/migrations/0046_alter_account_account_id_and_more.py new file mode 100644 index 0000000..d3ba1d2 --- /dev/null +++ b/api/migrations/0046_alter_account_account_id_and_more.py @@ -0,0 +1,78 @@ +# Generated by Django 4.1.2 on 2023-12-31 06:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0045_collection_sharing_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='account_id', + field=models.IntegerField(blank=True, default=21169482018841058607917871046905516796, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='bestsubmission', + name='best_submission_id', + field=models.IntegerField(blank=True, default=149805424067452344256336652203968127971, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collection', + name='collection_id', + field=models.IntegerField(blank=True, default=268667638844507429395683049205342878308, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collectiongrouppermission', + name='collection_group_permission_id', + field=models.IntegerField(blank=True, default=109233292530947572577678851192443289212, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='group', + name='group_id', + field=models.IntegerField(blank=True, default=122445526515845715335481945122286027175, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='groupmember', + name='group_member_id', + field=models.IntegerField(blank=True, default=166402800061360647258671358541528594815, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problem', + name='problem_id', + field=models.IntegerField(blank=True, default=319367364084708849680820356972231050063, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problemgrouppermission', + name='problem_group_permission_id', + field=models.IntegerField(blank=True, default=287900638121684221482942373316315838568, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submission', + name='submission_id', + field=models.IntegerField(blank=True, default=333913260807308465398586534607890822150, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submissiontestcase', + name='submission_testcase_id', + field=models.IntegerField(blank=True, default=60359747276246222989657681614453318391, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='testcase', + name='testcase_id', + field=models.IntegerField(blank=True, default=67781662549803771653563714324350833289, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topic', + name='topic_id', + field=models.IntegerField(blank=True, default=277680624917405823307023916753225961537, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topicgrouppermission', + name='topic_group_permission_id', + field=models.IntegerField(blank=True, default=268422871249108757857865287128153578738, primary_key=True, serialize=False, unique=True), + ), + ] diff --git a/api/migrations/0047_alter_account_account_id_and_more.py b/api/migrations/0047_alter_account_account_id_and_more.py new file mode 100644 index 0000000..5d7eb2f --- /dev/null +++ b/api/migrations/0047_alter_account_account_id_and_more.py @@ -0,0 +1,78 @@ +# Generated by Django 4.1.2 on 2023-12-31 06:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0046_alter_account_account_id_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='account_id', + field=models.IntegerField(blank=True, default=255025766878975110361680320380373860653, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='bestsubmission', + name='best_submission_id', + field=models.IntegerField(blank=True, default=258922610152306027347722825318799690393, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collection', + name='collection_id', + field=models.IntegerField(blank=True, default=99617119408089154479842742330779925899, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collectiongrouppermission', + name='collection_group_permission_id', + field=models.IntegerField(blank=True, default=81014014139093807433038406409328592680, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='group', + name='group_id', + field=models.IntegerField(blank=True, default=16555706619906256397756149457406660852, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='groupmember', + name='group_member_id', + field=models.IntegerField(blank=True, default=327764340289070410599813626795123765411, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problem', + name='problem_id', + field=models.IntegerField(blank=True, default=158188918196591434367913126653525869241, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problemgrouppermission', + name='problem_group_permission_id', + field=models.IntegerField(blank=True, default=253268741446266731297890328391178611475, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submission', + name='submission_id', + field=models.IntegerField(blank=True, default=24540818810954611023886936486853063157, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submissiontestcase', + name='submission_testcase_id', + field=models.IntegerField(blank=True, default=264396448540576706768031613977560334190, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='testcase', + name='testcase_id', + field=models.IntegerField(blank=True, default=85088409562075225550176092152049933143, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topic', + name='topic_id', + field=models.IntegerField(blank=True, default=326588415083665992335616674836859249347, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topicgrouppermission', + name='topic_group_permission_id', + field=models.IntegerField(blank=True, default=224958087767984655481777651457017521859, primary_key=True, serialize=False, unique=True), + ), + ] diff --git a/api/migrations/0048_alter_account_account_id_and_more.py b/api/migrations/0048_alter_account_account_id_and_more.py new file mode 100644 index 0000000..356111b --- /dev/null +++ b/api/migrations/0048_alter_account_account_id_and_more.py @@ -0,0 +1,78 @@ +# Generated by Django 4.1.2 on 2023-12-31 06:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0047_alter_account_account_id_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='account_id', + field=models.CharField(blank=True, default='4256b03cc08048ef9aa3c0348b3271ce', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='bestsubmission', + name='best_submission_id', + field=models.CharField(blank=True, default='a6a17c8c118947ddbe19ead82fadcf13', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collection', + name='collection_id', + field=models.CharField(blank=True, default='0826e62bc2eb485bac000c5a6874354e', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collectiongrouppermission', + name='collection_group_permission_id', + field=models.CharField(blank=True, default='99f216a4857a47bebf46585de5ba10b4', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='group', + name='group_id', + field=models.CharField(blank=True, default='cc530cb9f1ee4852b1eecd54edbc1ca0', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='groupmember', + name='group_member_id', + field=models.CharField(blank=True, default='4a87ce6643ea4e46ba7a5949f80a9bfe', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problem', + name='problem_id', + field=models.CharField(blank=True, default='b8f79eec56bd42a78a993888721d2966', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problemgrouppermission', + name='problem_group_permission_id', + field=models.CharField(blank=True, default='d91f4c61dda94f2b93728feccb8441d5', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submission', + name='submission_id', + field=models.CharField(blank=True, default='c494a2d002af4c439c258553ab41fd32', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submissiontestcase', + name='submission_testcase_id', + field=models.CharField(blank=True, default='092f2c6cd8004cd68f8ae138b65d6c8e', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='testcase', + name='testcase_id', + field=models.CharField(blank=True, default='2f39f938182542d6b7d5df70a4c275a2', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topic', + name='topic_id', + field=models.CharField(blank=True, default='9c5390db0ce942ac9562ec3422222b32', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topicgrouppermission', + name='topic_group_permission_id', + field=models.CharField(blank=True, default='35981bc9854a45dd9456f4958332466b', max_length=32, primary_key=True, serialize=False, unique=True), + ), + ] diff --git a/api/migrations/0049_alter_account_account_id_and_more.py b/api/migrations/0049_alter_account_account_id_and_more.py new file mode 100644 index 0000000..efa9328 --- /dev/null +++ b/api/migrations/0049_alter_account_account_id_and_more.py @@ -0,0 +1,88 @@ +# Generated by Django 4.1.2 on 2023-12-31 06:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0048_alter_account_account_id_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='account_id', + field=models.CharField(blank=True, default='fe492e8f6bbd4df3b7d8518d66cc4141', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='bestsubmission', + name='best_submission_id', + field=models.CharField(blank=True, default='fb2ee51251b144e0980aaaab7de3e2ed', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collection', + name='collection_id', + field=models.CharField(blank=True, default='f70ffe44bd84425480ea4c73cc1eccf3', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collectiongrouppermission', + name='collection_group_permission_id', + field=models.CharField(blank=True, default='e32d76e246844cf1834c711ac1d9f2c3', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='collectionproblem', + name='id', + field=models.CharField(blank=True, default='9df47ab61f73413da2667553854563a7', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='group', + name='group_id', + field=models.CharField(blank=True, default='eeb90b4a7ee046e1be3e26967ed815b6', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='groupmember', + name='group_member_id', + field=models.CharField(blank=True, default='b046b347361a4e839828ff8dc64fbf1c', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problem', + name='problem_id', + field=models.CharField(blank=True, default='9926855227344794b60bf52d107012c7', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='problemgrouppermission', + name='problem_group_permission_id', + field=models.CharField(blank=True, default='b5eeb3a47121426e930587793bfe173f', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submission', + name='submission_id', + field=models.CharField(blank=True, default='bafecc07aa194ca8a292f387c21af764', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='submissiontestcase', + name='submission_testcase_id', + field=models.CharField(blank=True, default='0188a3eb130c480d95504eae32e1b912', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='testcase', + name='testcase_id', + field=models.CharField(blank=True, default='e47da5f04bdf4b599a6d59d439508e22', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topic', + name='topic_id', + field=models.CharField(blank=True, default='9d84e241dd0643479412cac53c408657', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topiccollection', + name='id', + field=models.CharField(blank=True, default='823d76779a1d4455aa3437ae7157fde3', max_length=32, primary_key=True, serialize=False, unique=True), + ), + migrations.AlterField( + model_name='topicgrouppermission', + name='topic_group_permission_id', + field=models.CharField(blank=True, default='9ade2833620640cda259dbc40d3638ac', max_length=32, primary_key=True, serialize=False, unique=True), + ), + ] diff --git a/api/migrations/0050_alter_account_account_id_and_more.py b/api/migrations/0050_alter_account_account_id_and_more.py new file mode 100644 index 0000000..c3087be --- /dev/null +++ b/api/migrations/0050_alter_account_account_id_and_more.py @@ -0,0 +1,88 @@ +# Generated by Django 4.1.2 on 2023-12-31 07:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0049_alter_account_account_id_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='account_id', + field=models.CharField(blank=True, default='c61cc4ec15424865814d8403791fe7de', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='bestsubmission', + name='best_submission_id', + field=models.CharField(blank=True, default='5de4232945d34426a0b7dc51c1671cbc', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='collection', + name='collection_id', + field=models.CharField(blank=True, default='c178f001e1e5408fa42263289589c1ae', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='collectiongrouppermission', + name='collection_group_permission_id', + field=models.CharField(blank=True, default='f504bf60f7d3421389bd8f939dd49caf', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='collectionproblem', + name='id', + field=models.CharField(blank=True, default='2a36719d3b224b62ad031c94da0d253d', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='group', + name='group_id', + field=models.CharField(blank=True, default='497e3357fd344fe5bdd31788c211f5e7', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='groupmember', + name='group_member_id', + field=models.CharField(blank=True, default='9fe857f7c4bf41aca173f07320779da4', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='problem', + name='problem_id', + field=models.CharField(blank=True, default='1851825ec238474dabb80d4a03a05d2d', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='problemgrouppermission', + name='problem_group_permission_id', + field=models.CharField(blank=True, default='8adfff7ea11645d88a5b97cb56979165', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='submission', + name='submission_id', + field=models.CharField(blank=True, default='0ec695421ff341e086c9a37a662be3e1', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='submissiontestcase', + name='submission_testcase_id', + field=models.CharField(blank=True, default='9bbd6f2b00234676b0b661e74768a830', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='testcase', + name='testcase_id', + field=models.CharField(blank=True, default='81fd1d215c6e41a5b5d99608ab580c7b', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='topic', + name='topic_id', + field=models.CharField(blank=True, default='950c695bdef043c0b52e79bda497423e', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='topiccollection', + name='id', + field=models.CharField(blank=True, default='0ddc6a8372ef4db59adf00aa24b39429', max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='topicgrouppermission', + name='topic_group_permission_id', + field=models.CharField(blank=True, default='8fdc25dc2fcf40588e76e71c1bed234b', max_length=32, primary_key=True, serialize=False), + ), + ] diff --git a/api/migrations/0051_alter_account_account_id_and_more.py b/api/migrations/0051_alter_account_account_id_and_more.py new file mode 100644 index 0000000..feb04e6 --- /dev/null +++ b/api/migrations/0051_alter_account_account_id_and_more.py @@ -0,0 +1,89 @@ +# Generated by Django 4.1.2 on 2023-12-31 07:30 + +import api.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0050_alter_account_account_id_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='account_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='bestsubmission', + name='best_submission_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='collection', + name='collection_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='collectiongrouppermission', + name='collection_group_permission_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='collectionproblem', + name='id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='group', + name='group_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='groupmember', + name='group_member_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='problem', + name='problem_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='problemgrouppermission', + name='problem_group_permission_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='submission', + name='submission_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='submissiontestcase', + name='submission_testcase_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='testcase', + name='testcase_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='topic', + name='topic_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='topiccollection', + name='id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='topicgrouppermission', + name='topic_group_permission_id', + field=models.CharField(blank=True, default=api.models.generate_uuid4_hex, max_length=32, primary_key=True, serialize=False), + ), + ] diff --git a/api/models.py b/api/models.py index 38e08f5..1f45db5 100644 --- a/api/models.py +++ b/api/models.py @@ -7,6 +7,10 @@ from django.utils import timezone from django.contrib.auth.base_user import AbstractBaseUser,BaseUserManager from .utility import uploadTopic +from uuid import uuid4 + +def generate_uuid4_hex(): + return uuid4().hex # Create your models here. class ProgrammingLanguage(models.TextChoices): @@ -15,7 +19,7 @@ class ProgrammingLanguage(models.TextChoices): CPP = 'cpp',_('C++') class Account(models.Model): - account_id = models.AutoField(primary_key=True) + account_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) email = models.EmailField(max_length=50,unique=True,null=True) username = models.CharField(max_length=32,unique=True) password = models.CharField(max_length=128) @@ -26,7 +30,7 @@ class Account(models.Model): is_private = models.BooleanField(default=True) class Problem(models.Model): - problem_id = models.AutoField(primary_key=True) + problem_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") language = models.CharField(max_length=15) # ,choices=ProgrammingLanguage.choices,default=ProgrammingLanguage.PYTHON) title = models.CharField(max_length=50) @@ -38,10 +42,10 @@ class Problem(models.Model): submission_regex = models.CharField(max_length=1000,null=True,blank=True,default=".*") created_date = models.DateTimeField(default=timezone.now) updated_date = models.DateTimeField(default=timezone.now) - + sharing = models.BooleanField(default=False,blank=True) class Testcase(models.Model): - testcase_id = models.AutoField(primary_key=True) + testcase_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") input = models.CharField(max_length=100000) output = models.CharField(max_length=100000,null=True) @@ -49,7 +53,7 @@ class Testcase(models.Model): deprecated = models.BooleanField(default=False,blank=True) class Collection(models.Model): - collection_id = models.AutoField(primary_key=True) + collection_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) description = models.CharField(max_length=100000,null=True,blank=True,default=None) @@ -57,9 +61,11 @@ class Collection(models.Model): is_private = models.BooleanField(default=False,blank=True) created_date = models.DateTimeField(default=timezone.now) updated_date = models.DateTimeField(default=timezone.now) + sharing = models.BooleanField(default=False,blank=True) + class Topic(models.Model): - topic_id = models.AutoField(primary_key=True) + topic_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) description = models.CharField(max_length=100000,null=True,blank=True,default=None) @@ -68,13 +74,16 @@ class Topic(models.Model): is_private = models.BooleanField(default=False,blank=True) created_date = models.DateTimeField(default=timezone.now) updated_date = models.DateTimeField(default=timezone.now) + sharing = models.BooleanField(default=False,blank=True) class TopicCollection(models.Model): + id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") collection = models.ForeignKey(Collection,on_delete=models.CASCADE,db_column="collection_id") order = models.IntegerField(blank=True,default=0) class CollectionProblem(models.Model): + id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) collection = models.ForeignKey(Collection,on_delete=models.CASCADE,db_column="collection_id") problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") order = models.IntegerField(blank=True,default=0) @@ -89,7 +98,7 @@ class TopicAccountAccess(models.Model): account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") class Submission(models.Model): - submission_id = models.AutoField(primary_key=True) + submission_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id",null=True) account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") @@ -102,7 +111,7 @@ class Submission(models.Model): passed_ratio = models.FloatField(default=0) class SubmissionTestcase(models.Model): - submission_testcase_id = models.AutoField(primary_key=True) + submission_testcase_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) submission = models.ForeignKey(Submission,on_delete=models.CASCADE,db_column="submission_id") testcase = models.ForeignKey(Testcase,on_delete=models.CASCADE,db_column="testcase_id") output = models.CharField(max_length=100000,blank=True,null=True) @@ -110,14 +119,14 @@ class SubmissionTestcase(models.Model): runtime_status = models.CharField(max_length=10) class BestSubmission(models.Model): - best_submission_id = models.AutoField(primary_key=True) + best_submission_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id",null=True) account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") submission = models.ForeignKey(Submission,on_delete=models.CASCADE,db_column="submission_id") class Group(models.Model): - group_id = models.AutoField(primary_key=True) + group_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) creator = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="creator_id") name = models.CharField(max_length=100) description = models.CharField(max_length=100000,null=True,blank=True,default=None) @@ -125,12 +134,42 @@ class Group(models.Model): created_date = models.DateTimeField(default=timezone.now) updated_date = models.DateTimeField(default=timezone.now) + permission_manage_topics = models.BooleanField(default=False,blank=True) + permission_view_topics = models.BooleanField(default=False,blank=True) + permission_view_topics_log = models.BooleanField(default=False,blank=True) + permission_manage_collections = models.BooleanField(default=False,blank=True) + permission_view_collections = models.BooleanField(default=False,blank=True) + permission_manage_problems = models.BooleanField(default=False,blank=True) + permission_view_problems = models.BooleanField(default=False,blank=True) + class GroupMember(models.Model): - group_member_id = models.AutoField(primary_key=True) + group_member_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") account = models.ForeignKey(Account,on_delete=models.CASCADE,db_column="account_id") created_date = models.DateTimeField(default=timezone.now) +class ProblemGroupPermission(models.Model): + problem_group_permission_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) + problem = models.ForeignKey(Problem,on_delete=models.CASCADE,db_column="problem_id") + group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") + permission_manage_problems = models.BooleanField(default=False,blank=True) + permission_view_problems = models.BooleanField(default=False,blank=True) + +class CollectionGroupPermission(models.Model): + collection_group_permission_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) + collection = models.ForeignKey(Collection,on_delete=models.CASCADE,db_column="collection_id") + group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") + permission_manage_collections = models.BooleanField(default=False,blank=True) + permission_view_collections = models.BooleanField(default=False,blank=True) + +class TopicGroupPermission(models.Model): + topic_group_permission_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) + topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") + group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") + permission_manage_topics = models.BooleanField(default=False,blank=True) + permission_view_topics = models.BooleanField(default=False,blank=True) + permission_view_topics_log = models.BooleanField(default=False,blank=True) + # class TopicGroupPermission(models.Model): # topic = models.ForeignKey(Topic,on_delete=models.CASCADE,db_column="topic_id") # group = models.ForeignKey(Group,on_delete=models.CASCADE,db_column="group_id") diff --git a/api/serializers.py b/api/serializers.py index 2a30842..0f63c90 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -250,4 +250,15 @@ class GroupPopulateGroupMemberPopulateAccountSecureSerializer(serializers.ModelS members = GroupMemberPopulateAccountSecureSerializer(many=True) class Meta: model = Group - fields = ['group_id','name','description','color','created_date','updated_date','creator','members'] \ No newline at end of file + fields = ['group_id','name','description','color','created_date','updated_date','creator','members'] + +class TopicGroupPermissionsSerializer(serializers.ModelSerializer): + class Meta: + model = TopicGroupPermission + fields = "__all__" + +class TopicPopulateTopicGroupPermissionsSerializer(serializers.ModelSerializer): + group_permissions = TopicGroupPermissionsSerializer(many=True) + class Meta: + model = Topic + fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','creator','group_permissions'] \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index 68591c5..f704418 100644 --- a/api/urls.py +++ b/api/urls.py @@ -8,39 +8,42 @@ path('token',auth.authorization_view), path("accounts",account.all_accounts_view), - path("accounts/",account.one_creator_view), - path("accounts//daily-submissions",account.get_daily_submission), - path("accounts//password",account.change_password), + path("accounts/",account.one_creator_view), + path("accounts//daily-submissions",account.get_daily_submission), + path("accounts//password",account.change_password), - path('accounts//problems',problem.all_problems_creator_view), - path('accounts//problems/',problem.one_problem_creator_view), - path("accounts//problems//submissions",submission.account_problem_submission_view), - path("accounts//topics//problems//submissions",submission.topic_account_problem_submission_view), + path('accounts//problems',problem.all_problems_creator_view), + path('accounts//problems/',problem.one_problem_creator_view), + path("accounts//problems//submissions",submission.account_problem_submission_view), + path("accounts//topics//problems//submissions",submission.topic_account_problem_submission_view), - path('accounts//collections',collection.all_collections_creator_view), - path('accounts//collections/',collection.one_collection_creator_view), + path('accounts//collections',collection.all_collections_creator_view), + path('accounts//collections/',collection.one_collection_creator_view), - path('accounts//topics',topic.all_topics_creator_view), - path('accounts//topics/',topic.one_topic_creator_view), + path('accounts//topics',topic.all_topics_creator_view), + path('accounts//topics/',topic.one_topic_creator_view), - path('accounts//groups',group.all_groups_creator_view), + path('accounts//access/topics',topic.all_topics_access_view), + + path('accounts//groups',group.all_groups_creator_view), path('problems',problem.all_problems_view), path('problems/validate',problem.validation_view), - path('problems/',problem.one_problem_view), - path('topics//problems//accounts/',problem.problem_in_topic_account_view), + path('problems/',problem.one_problem_view), + path('topics//problems//accounts/',problem.problem_in_topic_account_view), path('collections',collection.all_collections_view), - path('collections/',collection.one_collection_view), - path('collections//problems/',collection.collection_problems_view), + path('collections/',collection.one_collection_view), + path('collections//problems/',collection.collection_problems_view), path('topics',topic.all_topics_view), - path('topics/',topic.one_topic_view), - path('topics//access',topic.account_access), - path('topics//collections/',topic.topic_collections_view), + path('topics/',topic.one_topic_view), + path('topics//access',topic.account_access), + path('topics//collections/',topic.topic_collections_view), + path('topics//groups',topic.topic_groups_view), - path('groups/',group.one_group_view), - path('groups//members',group.group_members_view), + path('groups/',group.one_group_view), + path('groups//members',group.group_members_view), path('submissions',submission.all_submission_view), diff --git a/api/views/account.py b/api/views/account.py index d9f4caa..41785b9 100644 --- a/api/views/account.py +++ b/api/views/account.py @@ -31,7 +31,7 @@ def change_password(request,account_id): return Response({'message':"Your password has been changed"}) @api_view([GET]) -def get_daily_submission(request,account_id:int): +def get_daily_submission(request,account_id:str): submissions = Submission.objects.filter(account_id=account_id) serializes = SubmissionSerializer(submissions,many=True) diff --git a/api/views/collection.py b/api/views/collection.py index 1213b1c..e66c8cc 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -20,14 +20,14 @@ @api_view([POST,GET]) -def all_collections_creator_view(request,account_id:int): +def all_collections_creator_view(request,account_id:str): if request.method == POST: return create_collection(account_id,request) if request.method == GET: return get_all_collections_by_account(account_id) @api_view([GET,PUT,DELETE]) -def one_collection_creator_view(request,collection_id:int): +def one_collection_creator_view(request,collection_id:str): if request.method == GET: return get_collection(collection_id) if request.method == PUT: @@ -40,7 +40,7 @@ def all_collections_view(request): return get_all_collections(request) @api_view([GET,PUT,DELETE]) -def one_collection_view(request,collection_id:int): +def one_collection_view(request,collection_id:str): if request.method == GET: return get_collection(collection_id) if request.method == PUT: @@ -49,7 +49,7 @@ def one_collection_view(request,collection_id:int): return delete_collection(collection_id) @api_view([PUT]) -def collection_problems_view(request,collection_id:int,method:str): +def collection_problems_view(request,collection_id:str,method:str): collection = Collection.objects.get(collection_id=collection_id) diff --git a/api/views/group.py b/api/views/group.py index e9d95d3..9e2aa0d 100644 --- a/api/views/group.py +++ b/api/views/group.py @@ -15,7 +15,7 @@ from ..controllers.group.get_all_groups_by_account import get_all_groups_by_account @api_view([POST,GET]) -def all_groups_creator_view(request,account_id:int): +def all_groups_creator_view(request,account_id:str): account = Account.objects.get(account_id=account_id) if request.method == POST: return create_group(account,request) @@ -23,7 +23,7 @@ def all_groups_creator_view(request,account_id:int): return get_all_groups_by_account(account,request) @api_view([PUT,DELETE,GET]) -def one_group_view(request,group_id:int): +def one_group_view(request,group_id:str): group = Group.objects.get(group_id=group_id) if request.method == PUT: return update_group(group,request) @@ -33,7 +33,7 @@ def one_group_view(request,group_id:int): return get_group(group,request) @api_view([PUT]) -def group_members_view(request,group_id:int): +def group_members_view(request,group_id:str): group = Group.objects.get(group_id=group_id) if request.method == PUT: return update_members_to_group(group,request) \ No newline at end of file diff --git a/api/views/problem.py b/api/views/problem.py index 8c7224b..d42fb6c 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -28,7 +28,7 @@ def all_problems_creator_view(request,account_id): return get_all_problems_by_account(account_id) @api_view([GET,PUT,DELETE]) -def one_problem_creator_view(problem_id:int,request): +def one_problem_creator_view(problem_id:str,request): if request.method == GET: return get_problem(problem_id) elif request.method == PUT: @@ -58,6 +58,6 @@ def validation_view(request): return validate_program(request) @api_view([GET]) -def problem_in_topic_account_view(request,account_id:int,topic_id:int,problem_id:int): +def problem_in_topic_account_view(request,account_id:str,topic_id:str,problem_id:str): if request.method == GET: return get_problem_in_topic_with_best_submission(account_id,topic_id,problem_id) \ No newline at end of file diff --git a/api/views/submission.py b/api/views/submission.py index 5973897..4672259 100644 --- a/api/views/submission.py +++ b/api/views/submission.py @@ -37,5 +37,5 @@ def topic_account_problem_submission_view(request,topic_id,account_id,problem_id return get_submissions_by_account_problem_in_topic(account_id,problem_id,topic_id) # @api_view([GET]) -# def submission_account_problem_view(request,account_id:int,problem_id:int): +# def submission_account_problem_view(request,account_id:str,problem_id:str): # return get_submissions_by_account_problem(account_id,problem_id) \ No newline at end of file diff --git a/api/views/topic.py b/api/views/topic.py index b8932e3..ecaf583 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -18,6 +18,8 @@ from ..controllers.topic.get_all_topics_by_account import * from ..controllers.topic.update_collections_to_topic import * from ..controllers.topic.get_topic_public import * +from ..controllers.topic.update_groups_permission_to_topic import * +from ..controllers.topic.get_all_accessed_topics_by_account import * @api_view([POST,GET]) @parser_classes([MultiPartParser,FormParser]) @@ -28,7 +30,7 @@ def all_topics_creator_view(request,account_id :int): return get_all_topics_by_account(account_id,request) @api_view([GET,PUT,DELETE]) -def one_topic_creator_view(request,account_id:int,topic_id:int): +def one_topic_creator_view(request,account_id:str,topic_id:str): if request.method == GET: return get_topic(topic_id) elif request.method == PUT: @@ -41,7 +43,7 @@ def all_topics_view(request): return get_all_topics(request) @api_view([GET,PUT,DELETE]) -def one_topic_view(request,topic_id:int): +def one_topic_view(request,topic_id:str): if request.method == GET: return get_topic_public(topic_id,request) elif request.method == PUT: @@ -50,7 +52,7 @@ def one_topic_view(request,topic_id:int): return delete_topic(topic_id) @api_view([PUT]) -def topic_collections_view(request,topic_id:int,method:str): +def topic_collections_view(request,topic_id:str,method:str): topic = Topic.objects.get(topic_id=topic_id) @@ -62,7 +64,7 @@ def topic_collections_view(request,topic_id:int,method:str): return update_collections_to_topic(topic,request) @api_view([POST,PUT]) -def account_access(request,topic_id:int): +def account_access(request,topic_id:str): topic = Topic.objects.get(topic_id=topic_id) target_accounts = Account.objects.filter(account_id__in=request.data['account_ids']) @@ -86,3 +88,13 @@ def account_access(request,topic_id:int): topicAccountAccesses = TopicAccountAccess.objects.filter(account_id__in=request.data['account_ids']) topicAccountAccesses.delete() return Response(status=status.HTTP_204_NO_CONTENT) + +@api_view([PUT]) +def topic_groups_view(request,topic_id:str): + topic = Topic.objects.get(topic_id=topic_id) + return update_groups_permission_to_topic(topic,request) + +@api_view([GET]) +def all_topics_access_view(request,account_id:str): + account = Account.objects.get(account_id=account_id) + return get_all_accessed_topics_by_account(account) \ No newline at end of file From c92efc5ddcae5f3bedaa8de57bc09e8a6e7a841b Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 31 Dec 2023 20:24:50 +0700 Subject: [PATCH 46/61] Get topics by accessible --- api/controllers/problem/get_all_problems.py | 4 ++-- .../submission/get_submission_by_quries.py | 12 ++++++------ .../topic/get_all_accessed_topics_by_account.py | 4 ++-- .../topic/update_groups_permission_to_topic.py | 2 ++ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/api/controllers/problem/get_all_problems.py b/api/controllers/problem/get_all_problems.py index 58a0a98..2737a20 100644 --- a/api/controllers/problem/get_all_problems.py +++ b/api/controllers/problem/get_all_problems.py @@ -13,13 +13,13 @@ def get_all_problems(request): get_private = int(request.query_params.get("private",0)) get_deactive = int(request.query_params.get("deactive",0)) - account_id = int(request.query_params.get("account_id",0)) + account_id = str(request.query_params.get("account_id","")) if not get_private: problem = problem.filter(is_private=False) if not get_deactive: problem = problem.filter(is_active=True) - if account_id != 0: + if account_id != "": problem = problem.filter(creator_id=account_id) problem = problem.order_by('-problem_id') diff --git a/api/controllers/submission/get_submission_by_quries.py b/api/controllers/submission/get_submission_by_quries.py index 216233e..7fb5401 100644 --- a/api/controllers/submission/get_submission_by_quries.py +++ b/api/controllers/submission/get_submission_by_quries.py @@ -12,20 +12,20 @@ def get_submission_by_quries(request): submissions = Submission.objects.all() # Query params - problem_id = int(request.query_params.get("problem_id", 0)) - account_id = int(request.query_params.get("account_id", 0)) - topic_id = int(request.query_params.get("topic_id", 0)) + problem_id = str(request.query_params.get("problem_id", "")) + account_id = str(request.query_params.get("account_id", "")) + topic_id = str(request.query_params.get("topic_id", "")) passed = int(request.query_params.get("passed", -1)) sort_score = int(request.query_params.get("sort_score", 0)) sort_date = int(request.query_params.get("sort_date", 0)) start = int(request.query_params.get("start", -1)) end = int(request.query_params.get("end", -1)) - if problem_id != 0: + if problem_id != "": submissions = submissions.filter(problem_id=problem_id) - if account_id != 0: + if account_id != "": submissions = submissions.filter(account_id=account_id) - if topic_id != 0: + if topic_id != "": submissions = submissions.filter(problem__topic_id=topic_id) if passed == 0: diff --git a/api/controllers/topic/get_all_accessed_topics_by_account.py b/api/controllers/topic/get_all_accessed_topics_by_account.py index 019b175..28753e0 100644 --- a/api/controllers/topic/get_all_accessed_topics_by_account.py +++ b/api/controllers/topic/get_all_accessed_topics_by_account.py @@ -10,9 +10,9 @@ def get_all_accessed_topics_by_account(account:Account): groups = [gm.group for gm in GroupMember.objects.filter(account=account)] - accessedTopics = TopicGroupPermission.objects.filter(group__in=groups).distinct() + accessedTopics = TopicGroupPermission.objects.filter(group__in=groups,permission_view_topics=True).distinct() topics = [at.topic for at in accessedTopics] serialize = TopicSerializer(topics,many=True) - return Response({'topics':serialize.data},status=status.HTTP_204_NO_CONTENT) + return Response({'topics':serialize.data},status=status.HTTP_200_OK) diff --git a/api/controllers/topic/update_groups_permission_to_topic.py b/api/controllers/topic/update_groups_permission_to_topic.py index 5831898..608791b 100644 --- a/api/controllers/topic/update_groups_permission_to_topic.py +++ b/api/controllers/topic/update_groups_permission_to_topic.py @@ -9,6 +9,8 @@ from ...serializers import * def update_groups_permission_to_topic(topic:Topic,request): + + TopicGroupPermission.objects.filter(topic=topic).delete() topic_group_permissions = [] for group_request in request.data['groups']: From 422745d763e56fd570a135a59f6160096d1b3c73 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 3 Jan 2024 15:27:26 +0700 Subject: [PATCH 47/61] TopicPopulateTopicCollectionPopulateCollection --- api/controllers/topic/get_topic.py | 3 ++- api/serializers.py | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py index 6a17ce1..d09be37 100644 --- a/api/controllers/topic/get_topic.py +++ b/api/controllers/topic/get_topic.py @@ -11,7 +11,8 @@ def get_topic(topic_id:str): topic = Topic.objects.get(topic_id=topic_id) topic.collections = TopicCollection.objects.filter(topic_id=topic_id) - serialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(topic) + topic.group_permissions = TopicGroupPermission.objects.filter(topic=topic) + serialize = TopicPopulateTopicCollectionPopulateCollectionAndTopicGroupPermissionPopulateGroupSerializer(topic) return Response(serialize.data,status=status.HTTP_200_OK) diff --git a/api/serializers.py b/api/serializers.py index 0f63c90..2fd3d9a 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -199,7 +199,8 @@ class TopicPopulateTopicCollectionPopulateCollectionSerializer(serializers.Model collections = TopicCollectionPopulateCollectionSerializer(many=True) class Meta: model = Topic - fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','creator','collections'] + fields = "__all__" + include = ['collections'] class TopicPopulateTopicCollectionPopulateCollectionProblemPopulateProblemSerializer(serializers.ModelSerializer): @@ -250,15 +251,31 @@ class GroupPopulateGroupMemberPopulateAccountSecureSerializer(serializers.ModelS members = GroupMemberPopulateAccountSecureSerializer(many=True) class Meta: model = Group - fields = ['group_id','name','description','color','created_date','updated_date','creator','members'] + fields = "__all__" + include = ['members'] class TopicGroupPermissionsSerializer(serializers.ModelSerializer): class Meta: model = TopicGroupPermission fields = "__all__" +class TopicGroupPermissionPopulateGroupSerializer(serializers.ModelSerializer): + group = GroupSerializer() + class Meta: + model = TopicGroupPermission + fields = "__all__" + class TopicPopulateTopicGroupPermissionsSerializer(serializers.ModelSerializer): group_permissions = TopicGroupPermissionsSerializer(many=True) class Meta: model = Topic - fields = ['topic_id','name','description','image_url','is_active','is_private','created_date','updated_date','creator','group_permissions'] \ No newline at end of file + fields = "__all__" + include = ['group_permissions'] + +class TopicPopulateTopicCollectionPopulateCollectionAndTopicGroupPermissionPopulateGroupSerializer(serializers.ModelSerializer): + collections = TopicCollectionPopulateCollectionSerializer(many=True) + group_permissions = TopicGroupPermissionPopulateGroupSerializer(many=True) + class Meta: + model = Topic + fields = "__all__" + include = ['collections','group_permissions'] From d7f2297d7dddfb9f294c086e9b91bc88268a6903 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 3 Jan 2024 22:45:46 +0700 Subject: [PATCH 48/61] Migration to main account --- ..._admin_remove_collection_owner_and_more.py | 6 ++-- api/sandbox/section1/runner.cpp | 28 +++++++++++++++++-- api/views/script.py | 11 ++++---- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py b/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py index 2638044..94d36f3 100644 --- a/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py +++ b/api/migrations/0029_remove_account_is_admin_remove_collection_owner_and_more.py @@ -30,19 +30,19 @@ class Migration(migrations.Migration): migrations.AddField( model_name='collection', name='creator', - field=models.ForeignKey(db_column='creator_id', default=1, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), preserve_default=False, ), migrations.AddField( model_name='problem', name='creator', - field=models.ForeignKey(db_column='creator_id', default=1, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), preserve_default=False, ), migrations.AddField( model_name='topic', name='creator', - field=models.ForeignKey(db_column='creator_id', default=1, on_delete=django.db.models.deletion.CASCADE, to='api.account'), + field=models.ForeignKey(db_column='creator_id', default=4, on_delete=django.db.models.deletion.CASCADE, to='api.account'), preserve_default=False, ), ] diff --git a/api/sandbox/section1/runner.cpp b/api/sandbox/section1/runner.cpp index 2999e16..e03836d 100644 --- a/api/sandbox/section1/runner.cpp +++ b/api/sandbox/section1/runner.cpp @@ -1,6 +1,28 @@ -#include +#include + + + using namespace std; -int main() { - cout << "Hello World!\n"; + + + + +void rec(int t){ + + cout << "HEllo"; + return rec(t-1); + +} + + + +int main(){ + + // int t; cin >> t; + + rec(5); + + return 0; + } \ No newline at end of file diff --git a/api/views/script.py b/api/views/script.py index afc396b..bfc5b45 100644 --- a/api/views/script.py +++ b/api/views/script.py @@ -6,7 +6,7 @@ from rest_framework import status from django.forms.models import model_to_dict from ..serializers import * - +from ..controllers.script.generate_submission_score import generate_submission_score # @api_view([POST]) # def run_script(request): @@ -51,8 +51,9 @@ @api_view([POST]) def run_script(request): - collections = Collection.objects.all() - for collection in collections: - collection.description = '[{"id":"1","type":"p","children":[{"text":"Just course"}]}]' - collection.save() + # collections = Collection.objects.all() + # for collection in collections: + # collection.description = '[{"id":"1","type":"p","children":[{"text":"Just course"}]}]' + # collection.save() + generate_submission_score(request) return Response({'message': 'Success!'},status=status.HTTP_201_CREATED) From fbc227102e80284a95bff3d5a2aea1fa49a4a87a Mon Sep 17 00:00:00 2001 From: KanonKC Date: Wed, 3 Jan 2024 22:51:33 +0700 Subject: [PATCH 49/61] Removed runner code --- api/sandbox/section1/runner.c | 1 - api/sandbox/section1/runner.cpp | 28 ---------------------------- 2 files changed, 29 deletions(-) delete mode 100644 api/sandbox/section1/runner.c delete mode 100644 api/sandbox/section1/runner.cpp diff --git a/api/sandbox/section1/runner.c b/api/sandbox/section1/runner.c deleted file mode 100644 index bf28f2e..0000000 --- a/api/sandbox/section1/runner.c +++ /dev/null @@ -1 +0,0 @@ -n = int(input('N: '));print(2/) \ No newline at end of file diff --git a/api/sandbox/section1/runner.cpp b/api/sandbox/section1/runner.cpp deleted file mode 100644 index e03836d..0000000 --- a/api/sandbox/section1/runner.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - - - -using namespace std; - - - - - -void rec(int t){ - - cout << "HEllo"; - return rec(t-1); - -} - - - -int main(){ - - // int t; cin >> t; - - rec(5); - - return 0; - -} \ No newline at end of file From 40ad8746329cb18a1669ff207d5735ce07d577b0 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 4 Jan 2024 22:47:33 +0700 Subject: [PATCH 50/61] Update topic apis --- api/controllers/topic/delete_topic.py | 4 ++-- .../topic/get_all_topics_by_account.py | 18 +++++++++++++----- api/controllers/topic/get_topic.py | 5 ++--- api/controllers/topic/update_topic.py | 4 +--- api/permissions/topic.py | 6 ++++++ api/views/topic.py | 14 ++++++++++---- 6 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 api/permissions/topic.py diff --git a/api/controllers/topic/delete_topic.py b/api/controllers/topic/delete_topic.py index 74938fc..6d1db33 100644 --- a/api/controllers/topic/delete_topic.py +++ b/api/controllers/topic/delete_topic.py @@ -8,7 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def delete_topic(topic_id:str): - topic = Topic.objects.get(topic_id=topic_id) +def delete_topic(topic:Topic): + topic = Topic.objects.get(topic=topic) topic.delete() return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/api/controllers/topic/get_all_topics_by_account.py b/api/controllers/topic/get_all_topics_by_account.py index 5d71a84..49ce8c8 100644 --- a/api/controllers/topic/get_all_topics_by_account.py +++ b/api/controllers/topic/get_all_topics_by_account.py @@ -8,17 +8,25 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_all_topics_by_account(account_id:str,request): - topics = Topic.objects.filter(creator_id=account_id).order_by('-updated_date') +def populated_collections(topics:Topic): topicCollections = TopicCollection.objects.filter(topic__in=topics) - populated_topics = [] for topic in topics: topic.collections = topicCollections.filter(topic=topic) populated_topics.append(topic) + return populated_topics + +def get_all_topics_by_account(account:Account,request): + personalTopics = Topic.objects.filter(creator=account).order_by('-updated_date') + populatedPersonalTopics = populated_collections(personalTopics) + personalSerialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(populatedPersonalTopics,many=True) - serialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(populated_topics,many=True) + # print(GroupMember.objects.all().values_list("group",flat=True)) + manageableTopics = Topic.objects.filter(topicgrouppermission__permission_manage_topics=True,topicgrouppermission__group__in=GroupMember.objects.all().values_list("group",flat=True)).order_by('-updated_date') + populatedmanageableTopics = populated_collections(manageableTopics) + manageableSerialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(populatedmanageableTopics,many=True) return Response({ - 'topics': serialize.data + 'topics': personalSerialize.data, + 'manageable_topics': manageableSerialize.data },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py index d09be37..617898a 100644 --- a/api/controllers/topic/get_topic.py +++ b/api/controllers/topic/get_topic.py @@ -8,9 +8,8 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_topic(topic_id:str): - topic = Topic.objects.get(topic_id=topic_id) - topic.collections = TopicCollection.objects.filter(topic_id=topic_id) +def get_topic(topic:Topic): + topic.collections = TopicCollection.objects.filter(topic=topic) topic.group_permissions = TopicGroupPermission.objects.filter(topic=topic) serialize = TopicPopulateTopicCollectionPopulateCollectionAndTopicGroupPermissionPopulateGroupSerializer(topic) diff --git a/api/controllers/topic/update_topic.py b/api/controllers/topic/update_topic.py index f094c05..1d95c9f 100644 --- a/api/controllers/topic/update_topic.py +++ b/api/controllers/topic/update_topic.py @@ -8,9 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def update_topic(topic_id:str,request): - topic = Topic.objects.get(topic_id=topic_id) - +def update_topic(topic:Topic,request): topic_ser = TopicSerializer(topic,data=request.data,partial=True) if topic_ser.is_valid(): topic_ser.save() diff --git a/api/permissions/topic.py b/api/permissions/topic.py new file mode 100644 index 0000000..ee389cc --- /dev/null +++ b/api/permissions/topic.py @@ -0,0 +1,6 @@ +from ..models import * +def canManageTopic(topic:Topic,account:Account): + is_creator = topic.creator.account_id == account.account_id + has_permission = len(TopicGroupPermission.objects.filter(permission_manage_topics=True,topic=topic,group__in=[gm.group for gm in GroupMember.objects.filter(account=account)])) > 0 + print(TopicGroupPermission.objects.filter(topic=topic,group__in=[gm.group for gm in GroupMember.objects.filter(account=account)])) + return is_creator or has_permission \ No newline at end of file diff --git a/api/views/topic.py b/api/views/topic.py index ecaf583..f3cc177 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -20,23 +20,29 @@ from ..controllers.topic.get_topic_public import * from ..controllers.topic.update_groups_permission_to_topic import * from ..controllers.topic.get_all_accessed_topics_by_account import * +from ..permissions.topic import * @api_view([POST,GET]) @parser_classes([MultiPartParser,FormParser]) def all_topics_creator_view(request,account_id :int): + account = Account.objects.get(account_id=account_id) if request.method == POST: return create_topic(account_id,request) elif request.method == GET: - return get_all_topics_by_account(account_id,request) + return get_all_topics_by_account(account,request) @api_view([GET,PUT,DELETE]) def one_topic_creator_view(request,account_id:str,topic_id:str): + topic = Topic.objects.get(topic_id=topic_id) + account = Account.objects.get(account_id=account_id) + if not canManageTopic(topic,account): + return Response(status=status.HTTP_401_UNAUTHORIZED) if request.method == GET: - return get_topic(topic_id) + return get_topic(topic) elif request.method == PUT: - return update_topic(topic_id,request) + return update_topic(topic,request) elif request.method == DELETE: - return delete_topic(topic_id) + return delete_topic(topic) @api_view([GET]) def all_topics_view(request): From 1a74decc23d8272bf560a1972eb9105abd3aa134 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Fri, 5 Jan 2024 01:04:52 +0700 Subject: [PATCH 51/61] Get topic populate problems --- .../get_all_collections_by_account.py | 2 +- api/controllers/topic/get_topic.py | 9 ++++++-- api/serializers.py | 21 +++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/api/controllers/collection/get_all_collections_by_account.py b/api/controllers/collection/get_all_collections_by_account.py index be88a0b..4b3bd0a 100644 --- a/api/controllers/collection/get_all_collections_by_account.py +++ b/api/controllers/collection/get_all_collections_by_account.py @@ -17,7 +17,7 @@ def get_all_collections_by_account(account_id:str): con_probs = problemCollections.filter(collection=collection) serialize = CollectionSerializer(collection) collection_data = serialize.data - collection_data['problems'] = CollectionProblemPopulateProblemSecureSerializer(con_probs,many=True).data + collection_data['problems'] = CollectionProblemPopulateProblemSerializer(con_probs,many=True).data populated_collections.append(collection_data) diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py index 617898a..19d5f41 100644 --- a/api/controllers/topic/get_topic.py +++ b/api/controllers/topic/get_topic.py @@ -9,9 +9,14 @@ from ...serializers import * def get_topic(topic:Topic): - topic.collections = TopicCollection.objects.filter(topic=topic) topic.group_permissions = TopicGroupPermission.objects.filter(topic=topic) - serialize = TopicPopulateTopicCollectionPopulateCollectionAndTopicGroupPermissionPopulateGroupSerializer(topic) + + topic.collections = TopicCollection.objects.filter(topic=topic) + + for tp in topic.collections: + tp.collection.problems = CollectionProblem.objects.filter(collection=tp.collection) + + serialize = TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemAndTopicGroupPermissionPopulateGroupSerializer(topic) return Response(serialize.data,status=status.HTTP_200_OK) diff --git a/api/serializers.py b/api/serializers.py index 2fd3d9a..8073a6b 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -279,3 +279,24 @@ class Meta: model = Topic fields = "__all__" include = ['collections','group_permissions'] + +class CollectionPopulateCollectionProblemPopulateProblemSerializer(serializers.ModelSerializer): + problems = CollectionProblemPopulateProblemSerializer(many=True) + class Meta: + model = Collection + fields = "__all__" + +class TopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemSerializer(serializers.ModelSerializer): + collection = CollectionPopulateCollectionProblemPopulateProblemSerializer() + class Meta: + model = TopicCollection + fields = "__all__" + +class TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemAndTopicGroupPermissionPopulateGroupSerializer(serializers.ModelSerializer): + collections = TopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemSerializer(many=True) + group_permissions = TopicGroupPermissionPopulateGroupSerializer(many=True) + + class Meta: + model = Topic + fields = "__all__" + include = ['collections','group_permissions'] \ No newline at end of file From 5fdc9d2a6d2704f3b289b68ec4954f39a4b67763 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 6 Jan 2024 14:08:34 +0700 Subject: [PATCH 52/61] Collection permission --- api/controllers/collection/get_collection.py | 20 +++++-------- .../update_group_permissions_collection.py | 30 +++++++++++++++++++ api/serializers.py | 22 +++++++++++++- api/urls.py | 3 +- api/views/collection.py | 12 ++++++-- api/views/topic.py | 2 +- 6 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 api/controllers/collection/update_group_permissions_collection.py diff --git a/api/controllers/collection/get_collection.py b/api/controllers/collection/get_collection.py index b3e0a77..3a01e51 100644 --- a/api/controllers/collection/get_collection.py +++ b/api/controllers/collection/get_collection.py @@ -12,17 +12,13 @@ def get_collection(collection_id:str): collection = Collection.objects.get(collection_id=collection_id) # problems = Problem.objects.filter(collectionproblem__collection_id=collection_id) - collectionProblems = CollectionProblem.objects.filter(collection=collection).order_by('order') + collection.problems = CollectionProblem.objects.filter(collection=collection).order_by('order') + collection.group_permissions = CollectionGroupPermission.objects.filter(collection=collection) - collection_ser = CollectionSerializer(collection) - collectionProblems_ser = CollectionProblemPopulateProblemSecureSerializer(collectionProblems,many=True) - # populated_problems = [] - # for col_prob in collectionProblems: - # col_prob_serialize = CollectionProblemPopulateProblemSecureSerializer(col_prob) - # # prob_serialize = ProblemSerializer(col_prob.problem) - # populated_problems.append(col_prob_serialize.data) + # collection_ser = CollectionSerializer(collection) + # collectionProblems_ser = CollectionProblemPopulateProblemSecureSerializer(collectionProblems,many=True) - return Response({ - **collection_ser.data, - 'problems': collectionProblems_ser.data - } ,status=status.HTTP_200_OK) \ No newline at end of file + serializer = CollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupSerializer(collection) + + + return Response(serializer.data ,status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/collection/update_group_permissions_collection.py b/api/controllers/collection/update_group_permissions_collection.py new file mode 100644 index 0000000..d2d8061 --- /dev/null +++ b/api/controllers/collection/update_group_permissions_collection.py @@ -0,0 +1,30 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_group_permissions_collection(collection:Collection,request): + + CollectionGroupPermission.objects.filter(collection=collection).delete() + + collection_group_permissions = [] + for collection_request in request.data['groups']: + group = Group.objects.get(group_id=collection_request['group_id']) + collection_group_permissions.append( + CollectionGroupPermission( + collection=collection, + group=group, + **collection_request + )) + + CollectionGroupPermission.objects.bulk_create(collection_group_permissions) + + collection.group_permissions = collection_group_permissions + serialize = CollectionPopulateCollectionGroupPermissionsPopulateGroupSerializer(collection) + + return Response(serialize.data,status=status.HTTP_202_ACCEPTED) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 8073a6b..92816fc 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -299,4 +299,24 @@ class TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemPop class Meta: model = Topic fields = "__all__" - include = ['collections','group_permissions'] \ No newline at end of file + include = ['collections','group_permissions'] + +class CollectionGroupPermissionPopulateGroupSerializer(serializers.ModelSerializer): + group = GroupSerializer() + class Meta: + model = CollectionGroupPermission + fields = "__all__" +class CollectionPopulateCollectionGroupPermissionsPopulateGroupSerializer(serializers.ModelSerializer): + group_permissions = CollectionGroupPermissionPopulateGroupSerializer(many=True) + class Meta: + model = Collection + fields = "__all__" + include = ['group_permissions'] + +class CollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupSerializer(serializers.ModelSerializer): + problems = CollectionProblemPopulateProblemSerializer(many=True) + group_permissions = CollectionGroupPermissionPopulateGroupSerializer(many=True) + class Meta: + model = Collection + fields = "__all__" + include = ['problems','group_permissions'] \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index f704418..1e6aa11 100644 --- a/api/urls.py +++ b/api/urls.py @@ -19,9 +19,11 @@ path('accounts//collections',collection.all_collections_creator_view), path('accounts//collections/',collection.one_collection_creator_view), + path('accounts//collections//groups',collection.collection_groups_view), path('accounts//topics',topic.all_topics_creator_view), path('accounts//topics/',topic.one_topic_creator_view), + path('accounts//topics//groups',topic.topic_groups_view), path('accounts//access/topics',topic.all_topics_access_view), @@ -40,7 +42,6 @@ path('topics/',topic.one_topic_view), path('topics//access',topic.account_access), path('topics//collections/',topic.topic_collections_view), - path('topics//groups',topic.topic_groups_view), path('groups/',group.one_group_view), path('groups//members',group.group_members_view), diff --git a/api/views/collection.py b/api/views/collection.py index e66c8cc..3db6fcf 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -17,6 +17,8 @@ from ..controllers.collection.remove_problems_from_collection import * from ..controllers.collection.get_all_collections_by_account import * from ..controllers.collection.update_problems_to_collection import * +from ..controllers.collection.update_group_permissions_collection import * + @api_view([POST,GET]) @@ -27,7 +29,7 @@ def all_collections_creator_view(request,account_id:str): return get_all_collections_by_account(account_id) @api_view([GET,PUT,DELETE]) -def one_collection_creator_view(request,collection_id:str): +def one_collection_creator_view(request,account_id:int,collection_id:str): if request.method == GET: return get_collection(collection_id) if request.method == PUT: @@ -58,4 +60,10 @@ def collection_problems_view(request,collection_id:str,method:str): if method == "remove": return remove_problems_from_collection(collection,request) if method == "update": - return update_problems_to_collection(collection,request) \ No newline at end of file + return update_problems_to_collection(collection,request) + +@api_view([PUT]) +def collection_groups_view(request,account_id:int,collection_id:str): + collection = Collection.objects.get(collection_id=collection_id) + if request.method == PUT: + return update_group_permissions_collection(collection,request) \ No newline at end of file diff --git a/api/views/topic.py b/api/views/topic.py index f3cc177..55be2bf 100644 --- a/api/views/topic.py +++ b/api/views/topic.py @@ -96,7 +96,7 @@ def account_access(request,topic_id:str): return Response(status=status.HTTP_204_NO_CONTENT) @api_view([PUT]) -def topic_groups_view(request,topic_id:str): +def topic_groups_view(request,account_id:int,topic_id:str): topic = Topic.objects.get(topic_id=topic_id) return update_groups_permission_to_topic(topic,request) From 0f584e712fa8ce73a16bf5bb33726e0edb62d7c6 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sun, 7 Jan 2024 16:07:03 +0700 Subject: [PATCH 53/61] Public collections show only permitted collections --- .../get_all_collections_by_account.py | 24 ++++++++++++------- api/controllers/group/create_group.py | 2 ++ .../group/get_all_groups_by_account.py | 5 ++++ .../topic/get_all_topics_by_account.py | 2 +- api/controllers/topic/get_topic_public.py | 8 ++++++- api/serializers.py | 9 ++++++- 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/api/controllers/collection/get_all_collections_by_account.py b/api/controllers/collection/get_all_collections_by_account.py index 4b3bd0a..7cd16fb 100644 --- a/api/controllers/collection/get_all_collections_by_account.py +++ b/api/controllers/collection/get_all_collections_by_account.py @@ -8,19 +8,27 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_all_collections_by_account(account_id:str): - collections = Collection.objects.filter(creator=account_id).order_by('-updated_date') +def populated_problems(collections: Collection): problemCollections = CollectionProblem.objects.filter(collection__in=collections) populated_collections = [] for collection in collections: - con_probs = problemCollections.filter(collection=collection) - serialize = CollectionSerializer(collection) - collection_data = serialize.data - collection_data['problems'] = CollectionProblemPopulateProblemSerializer(con_probs,many=True).data + collection.problems = problemCollections.filter(collection=collection) + populated_collections.append(collection) - populated_collections.append(collection_data) + return populated_collections + +def get_all_collections_by_account(account:Account): + + collections = Collection.objects.filter(creator=account).order_by('-updated_date') + collections = populated_problems(collections) + serialize = CollectionPopulateCollectionProblemsPopulateProblemSerializer(collections,many=True) + + manageableCollections = Collection.objects.filter(collectiongrouppermission__permission_manage_collections=True,collectiongrouppermission__group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True)).order_by('-updated_date') + manageableCollections = populated_problems(manageableCollections) + manageableSerialize = CollectionPopulateCollectionProblemsPopulateProblemSerializer(manageableCollections,many=True) return Response({ - 'collections': populated_collections + 'collections': serialize.data, + 'manageable_collections': manageableSerialize.data },status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/group/create_group.py b/api/controllers/group/create_group.py index 4211b3a..d4e734d 100644 --- a/api/controllers/group/create_group.py +++ b/api/controllers/group/create_group.py @@ -9,6 +9,8 @@ from ...serializers import * def create_group(account:Account,request): + + # print(request.headers["Authorization"]) serialize = GroupSerializer(data={ 'creator':account.account_id, diff --git a/api/controllers/group/get_all_groups_by_account.py b/api/controllers/group/get_all_groups_by_account.py index c3fee84..b9b1f05 100644 --- a/api/controllers/group/get_all_groups_by_account.py +++ b/api/controllers/group/get_all_groups_by_account.py @@ -10,6 +10,11 @@ def get_all_groups_by_account(account:Account,request): + print("GET ALL") + + # Get request headers + headers = request.headers + groups = Group.objects.filter(creator=account).order_by('-updated_date') populate_members = request.GET.get('populate_members',False) diff --git a/api/controllers/topic/get_all_topics_by_account.py b/api/controllers/topic/get_all_topics_by_account.py index 49ce8c8..417424f 100644 --- a/api/controllers/topic/get_all_topics_by_account.py +++ b/api/controllers/topic/get_all_topics_by_account.py @@ -22,7 +22,7 @@ def get_all_topics_by_account(account:Account,request): personalSerialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(populatedPersonalTopics,many=True) # print(GroupMember.objects.all().values_list("group",flat=True)) - manageableTopics = Topic.objects.filter(topicgrouppermission__permission_manage_topics=True,topicgrouppermission__group__in=GroupMember.objects.all().values_list("group",flat=True)).order_by('-updated_date') + manageableTopics = Topic.objects.filter(topicgrouppermission__permission_manage_topics=True,topicgrouppermission__group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True)).order_by('-updated_date') populatedmanageableTopics = populated_collections(manageableTopics) manageableSerialize = TopicPopulateTopicCollectionPopulateCollectionSerializer(populatedmanageableTopics,many=True) diff --git a/api/controllers/topic/get_topic_public.py b/api/controllers/topic/get_topic_public.py index b05513e..0961df4 100644 --- a/api/controllers/topic/get_topic_public.py +++ b/api/controllers/topic/get_topic_public.py @@ -14,10 +14,16 @@ def get_topic_public(topic_id:str,request): topic = Topic.objects.get(topic_id=topic_id) account = Account.objects.get(account_id=account_id) - topicCollections = TopicCollection.objects.filter(topic=topic) + topicCollections = TopicCollection.objects.filter(topic=topic,collection__in=CollectionGroupPermission.objects.filter(group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True),permission_view_collections=True).values_list("collection",flat=True)) for tp in topicCollections: # tp.collection.problems = CollectionProblem.objects.filter(collection=tp.collection) + + # viewPermission = CollectionGroupPermission.objects.filter(collection=tp.collection,group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True),permission_view_collections=True) + # print(len(viewPermission)) + # if len(viewPermission) == 0: + # tp.collection.problems = [] + # continue collectionProblems = CollectionProblem.objects.filter(collection=tp.collection) for cp in collectionProblems: try: diff --git a/api/serializers.py b/api/serializers.py index 92816fc..6f0bcd2 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -319,4 +319,11 @@ class CollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermi class Meta: model = Collection fields = "__all__" - include = ['problems','group_permissions'] \ No newline at end of file + include = ['problems','group_permissions'] + +class CollectionPopulateCollectionProblemsPopulateProblemSerializer(serializers.ModelSerializer): + problems = CollectionProblemPopulateProblemSerializer(many=True) + class Meta: + model = Collection + fields = "__all__" + include = ['problems'] \ No newline at end of file From 288a1eb0f2d61b7ddb8286e9b26c991cb9da62d4 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Tue, 9 Jan 2024 03:01:23 +0700 Subject: [PATCH 54/61] Get topic populate for collection group permissions --- .../update_group_permissions_collection.py | 2 ++ api/controllers/topic/get_topic.py | 3 ++- api/serializers.py | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/api/controllers/collection/update_group_permissions_collection.py b/api/controllers/collection/update_group_permissions_collection.py index d2d8061..58577ab 100644 --- a/api/controllers/collection/update_group_permissions_collection.py +++ b/api/controllers/collection/update_group_permissions_collection.py @@ -12,6 +12,8 @@ def update_group_permissions_collection(collection:Collection,request): CollectionGroupPermission.objects.filter(collection=collection).delete() + print(request.data['groups']) + collection_group_permissions = [] for collection_request in request.data['groups']: group = Group.objects.get(group_id=collection_request['group_id']) diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py index 19d5f41..d8f2b39 100644 --- a/api/controllers/topic/get_topic.py +++ b/api/controllers/topic/get_topic.py @@ -15,8 +15,9 @@ def get_topic(topic:Topic): for tp in topic.collections: tp.collection.problems = CollectionProblem.objects.filter(collection=tp.collection) + tp.collection.group_permissions = CollectionGroupPermission.objects.filter(collection=tp.collection) - serialize = TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemPopulateProblemAndTopicGroupPermissionPopulateGroupSerializer(topic) + serialize = TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupAndTopicGroupPermissionPopulateGroupSerializer(topic) return Response(serialize.data,status=status.HTTP_200_OK) diff --git a/api/serializers.py b/api/serializers.py index 6f0bcd2..289b4dd 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -326,4 +326,18 @@ class CollectionPopulateCollectionProblemsPopulateProblemSerializer(serializers. class Meta: model = Collection fields = "__all__" - include = ['problems'] \ No newline at end of file + include = ['problems'] + +class TopicCollectionPopulateCollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupSerializer(serializers.ModelSerializer): + collection = CollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupSerializer() + class Meta: + model = TopicCollection + fields = "__all__" +class TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupAndTopicGroupPermissionPopulateGroupSerializer(serializers.ModelSerializer): + collections = TopicCollectionPopulateCollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupSerializer(many=True) + group_permissions = TopicGroupPermissionPopulateGroupSerializer(many=True) + + class Meta: + model = Topic + fields = "__all__" + include = ['collections','group_permissions'] \ No newline at end of file From 355bdf48971ee75f519a94678ee04c5cb2e5904e Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 11 Jan 2024 01:47:06 +0700 Subject: [PATCH 55/61] Get problem included group permissions --- api/controllers/problem/get_problem.py | 25 ++++++++++++++++--------- api/serializers.py | 19 ++++++++++++++++++- api/views/problem.py | 5 +++-- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/api/controllers/problem/get_problem.py b/api/controllers/problem/get_problem.py index 664a957..0f30ab8 100644 --- a/api/controllers/problem/get_problem.py +++ b/api/controllers/problem/get_problem.py @@ -8,13 +8,20 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_problem(problem_id:str): - try: - problem = Problem.objects.get(problem_id=problem_id) - except Problem.DoesNotExist: - return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) - testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) - problem_serialize = ProblemPopulateAccountSerializer(problem) - testcases_serialize = TestcaseSerializer(testcases,many=True) - return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_200_OK) +def get_problem(problem:Problem): + # try: + # problem = Problem.objects.get(problem_id=problem_id) + # except Problem.DoesNotExist: + # return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) + # testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) + # problem_serialize = ProblemPopulateAccountSerializer(problem) + # testcases_serialize = TestcaseSerializer(testcases,many=True) + + problem.testcases = Testcase.objects.filter(problem=problem,deprecated=False) + problem.group_permissions = ProblemGroupPermission.objects.filter(problem=problem) + + serialize = ProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupSerializer(problem) + + + return Response(serialize.data,status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/serializers.py b/api/serializers.py index 289b4dd..c4f8154 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -56,6 +56,8 @@ class Meta: model = Problem fields = "__all__" + + class TopicCollectionSerializer(serializers.ModelSerializer): class Meta: model = TopicCollection @@ -340,4 +342,19 @@ class TopicPopulateTopicCollectionPopulateCollectionPopulateCollectionProblemsPo class Meta: model = Topic fields = "__all__" - include = ['collections','group_permissions'] \ No newline at end of file + include = ['collections','group_permissions'] + +class ProblemGroupPermissionsPopulateGroupSerializer(serializers.ModelSerializer): + group = GroupSerializer() + class Meta: + model = ProblemGroupPermission + fields = "__all__" + +class ProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupSerializer(serializers.ModelSerializer): + creator = AccountSecureSerializer() + group_permissions = ProblemGroupPermissionsPopulateGroupSerializer(many=True) + testcases = TestcaseSerializer(many=True) + class Meta: + model = Problem + fields = "__all__" + include = ['creator','group_permissions','testcases'] \ No newline at end of file diff --git a/api/views/problem.py b/api/views/problem.py index d42fb6c..732c6af 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -28,9 +28,10 @@ def all_problems_creator_view(request,account_id): return get_all_problems_by_account(account_id) @api_view([GET,PUT,DELETE]) -def one_problem_creator_view(problem_id:str,request): +def one_problem_creator_view(request,problem_id:str,account_id:str): + problem = Problem.objects.get(problem_id=problem_id) if request.method == GET: - return get_problem(problem_id) + return get_problem(problem) elif request.method == PUT: return update_problem(problem_id,request) elif request.method == DELETE: From 2ebb12d221fc6a9b4d5e81898f58f49c2f966069 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 11 Jan 2024 10:20:03 +0700 Subject: [PATCH 56/61] Manage problem permissions api --- .../problem/get_all_problems_by_account.py | 16 ++++++---- .../update_group_permission_to_problem.py | 30 +++++++++++++++++++ api/urls.py | 1 + api/views/problem.py | 9 +++++- 4 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 api/controllers/problem/update_group_permission_to_problem.py diff --git a/api/controllers/problem/get_all_problems_by_account.py b/api/controllers/problem/get_all_problems_by_account.py index 27dd562..d6210d6 100644 --- a/api/controllers/problem/get_all_problems_by_account.py +++ b/api/controllers/problem/get_all_problems_by_account.py @@ -8,11 +8,17 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_all_problems_by_account(account_id:str): - problems = Problem.objects.filter(creator=account_id).order_by('-updated_date') +def get_all_problems_by_account(account:Account): + personalProblems = Problem.objects.filter(creator=account).order_by('-updated_date') + for problem in personalProblems: + problem.testcases = Testcase.objects.filter(problem=problem,deprecated=False) - for problem in problems: + manageableProblems = Problem.objects.filter(problemgrouppermission__permission_manage_problems=True,problemgrouppermission__group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True)).order_by('-updated_date') + for problem in manageableProblems: problem.testcases = Testcase.objects.filter(problem=problem,deprecated=False) - problem_ser = ProblemPopulateTestcaseSerializer(problems,many=True) - return Response({"problems":problem_ser.data},status=status.HTTP_200_OK) \ No newline at end of file + # problem_ser = ProblemPopulateTestcaseSerializer(problems,many=True) + personalSerialize = ProblemPopulateTestcaseSerializer(personalProblems,many=True) + manageableSerialize = ProblemPopulateTestcaseSerializer(manageableProblems,many=True) + + return Response({"problems":personalSerialize.data,"manageable_problems":manageableSerialize.data},status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/problem/update_group_permission_to_problem.py b/api/controllers/problem/update_group_permission_to_problem.py new file mode 100644 index 0000000..7002fda --- /dev/null +++ b/api/controllers/problem/update_group_permission_to_problem.py @@ -0,0 +1,30 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def update_group_permission_to_problem(problem:Problem,request): + ProblemGroupPermission.objects.filter(problem=problem).delete() + + problem_group_permissions = [] + for group_request in request.data['groups']: + group = Group.objects.get(group_id=group_request['group_id']) + problem_group_permissions.append( + ProblemGroupPermission( + problem=problem, + group=group, + **group_request + )) + + ProblemGroupPermission.objects.bulk_create(problem_group_permissions) + + problem.group_permissions = problem_group_permissions + problem.testcases = Testcase.objects.filter(problem=problem) + + serialize = ProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupSerializer(problem) + return Response(serialize.data,status=status.HTTP_202_ACCEPTED) \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index 1e6aa11..f4c9a13 100644 --- a/api/urls.py +++ b/api/urls.py @@ -14,6 +14,7 @@ path('accounts//problems',problem.all_problems_creator_view), path('accounts//problems/',problem.one_problem_creator_view), + path('accounts//problems//groups',problem.problem_group_view), path("accounts//problems//submissions",submission.account_problem_submission_view), path("accounts//topics//problems//submissions",submission.topic_account_problem_submission_view), diff --git a/api/views/problem.py b/api/views/problem.py index 732c6af..69439fd 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -18,6 +18,7 @@ from ..controllers.problem.validate_program import * from ..controllers.problem.get_all_problem_with_best_submission import * from ..controllers.problem.get_problem_in_topic_with_best_submission import * +from ..controllers.problem.update_group_permission_to_problem import * # Create your views here. @api_view([POST,GET]) @@ -61,4 +62,10 @@ def validation_view(request): @api_view([GET]) def problem_in_topic_account_view(request,account_id:str,topic_id:str,problem_id:str): if request.method == GET: - return get_problem_in_topic_with_best_submission(account_id,topic_id,problem_id) \ No newline at end of file + return get_problem_in_topic_with_best_submission(account_id,topic_id,problem_id) + +@api_view([PUT]) +def problem_group_view(request,account_id:int,problem_id:int): + problem = Problem.objects.get(problem_id=problem_id) + if request.method == PUT: + return update_group_permission_to_problem(problem,request) \ No newline at end of file From 6fcafa8a30f61eeaa00e8e1b57013af5e3c429fe Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 11 Jan 2024 12:41:23 +0700 Subject: [PATCH 57/61] Get problems in collection populated problem groups permissions --- api/controllers/collection/get_collection.py | 13 ++++++------- api/controllers/topic/get_topic.py | 2 +- api/serializers.py | 18 +++++++++++++++++- api/views/collection.py | 3 ++- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/api/controllers/collection/get_collection.py b/api/controllers/collection/get_collection.py index 3a01e51..8e87013 100644 --- a/api/controllers/collection/get_collection.py +++ b/api/controllers/collection/get_collection.py @@ -8,17 +8,16 @@ from django.forms.models import model_to_dict from ...serializers import * -def get_collection(collection_id:str): +def get_collection(collection:Collection): - collection = Collection.objects.get(collection_id=collection_id) - # problems = Problem.objects.filter(collectionproblem__collection_id=collection_id) collection.problems = CollectionProblem.objects.filter(collection=collection).order_by('order') collection.group_permissions = CollectionGroupPermission.objects.filter(collection=collection) - - # collection_ser = CollectionSerializer(collection) - # collectionProblems_ser = CollectionProblemPopulateProblemSecureSerializer(collectionProblems,many=True) - serializer = CollectionPopulateCollectionProblemsPopulateProblemAndCollectionGroupPermissionsPopulateGroupSerializer(collection) + for cp in collection.problems: + cp.problem.testcases = Testcase.objects.filter(problem=cp.problem,deprecated=False) + cp.problem.group_permissions = ProblemGroupPermission.objects.filter(problem=cp.problem) + + serializer = CollectionPopulateCollectionProblemsPopulateProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupAndCollectionGroupPermissionsPopulateGroupSerializer(collection) return Response(serializer.data ,status=status.HTTP_200_OK) \ No newline at end of file diff --git a/api/controllers/topic/get_topic.py b/api/controllers/topic/get_topic.py index d8f2b39..53f6e86 100644 --- a/api/controllers/topic/get_topic.py +++ b/api/controllers/topic/get_topic.py @@ -11,7 +11,7 @@ def get_topic(topic:Topic): topic.group_permissions = TopicGroupPermission.objects.filter(topic=topic) - topic.collections = TopicCollection.objects.filter(topic=topic) + topic.collections = TopicCollection.objects.filter(topic=topic).order_by('order') for tp in topic.collections: tp.collection.problems = CollectionProblem.objects.filter(collection=tp.collection) diff --git a/api/serializers.py b/api/serializers.py index c4f8154..45e83e5 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -323,6 +323,8 @@ class Meta: fields = "__all__" include = ['problems','group_permissions'] + + class CollectionPopulateCollectionProblemsPopulateProblemSerializer(serializers.ModelSerializer): problems = CollectionProblemPopulateProblemSerializer(many=True) class Meta: @@ -357,4 +359,18 @@ class ProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupS class Meta: model = Problem fields = "__all__" - include = ['creator','group_permissions','testcases'] \ No newline at end of file + include = ['creator','group_permissions','testcases'] + + +class CollectionProblemsPopulateProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupSerializer(serializers.ModelSerializer): + problem = ProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupSerializer() + class Meta: + model = CollectionProblem + fields = "__all__" +class CollectionPopulateCollectionProblemsPopulateProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupAndCollectionGroupPermissionsPopulateGroupSerializer(serializers.ModelSerializer): + problems = CollectionProblemsPopulateProblemPopulateAccountAndTestcasesAndProblemGroupPermissionsPopulateGroupSerializer(many=True) + group_permissions = CollectionGroupPermissionPopulateGroupSerializer(many=True) + class Meta: + model = Collection + fields = "__all__" + include = ['problems','group_permissions'] \ No newline at end of file diff --git a/api/views/collection.py b/api/views/collection.py index 3db6fcf..661644d 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -30,8 +30,9 @@ def all_collections_creator_view(request,account_id:str): @api_view([GET,PUT,DELETE]) def one_collection_creator_view(request,account_id:int,collection_id:str): + collection = Collection.objects.get(collection_id=collection_id) if request.method == GET: - return get_collection(collection_id) + return get_collection(collection) if request.method == PUT: return update_collection(collection_id,request) if request.method == DELETE: From b55a676be6cc589bdd509f406305bd9762acc14e Mon Sep 17 00:00:00 2001 From: KanonKC Date: Thu, 11 Jan 2024 14:02:39 +0700 Subject: [PATCH 58/61] Get topic public can check permission at problem level --- api/controllers/topic/get_topic_public.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/controllers/topic/get_topic_public.py b/api/controllers/topic/get_topic_public.py index 0961df4..bf948ec 100644 --- a/api/controllers/topic/get_topic_public.py +++ b/api/controllers/topic/get_topic_public.py @@ -24,7 +24,8 @@ def get_topic_public(topic_id:str,request): # if len(viewPermission) == 0: # tp.collection.problems = [] # continue - collectionProblems = CollectionProblem.objects.filter(collection=tp.collection) + collectionProblems = CollectionProblem.objects.filter(collection=tp.collection,problem__in=ProblemGroupPermission.objects.filter(group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True),permission_view_problems=True).values_list("problem",flat=True)) + for cp in collectionProblems: try: best_submission = BestSubmission.objects.get(problem=cp.problem,account=account,topic=topic) From 15b11f956ef38b23da5b18cc19b1f61b16055df9 Mon Sep 17 00:00:00 2001 From: KanonKC Date: Fri, 12 Jan 2024 20:20:13 +0700 Subject: [PATCH 59/61] Update delete api --- .../collection/update_collection.py | 3 +-- api/controllers/problem/create_problem.py | 3 ++- api/controllers/problem/delete_problem.py | 10 +++---- api/controllers/problem/get_problem_public.py | 14 ++++++++++ api/controllers/problem/update_problem.py | 26 ++++++------------- api/controllers/topic/delete_topic.py | 1 - .../get_all_accessed_topics_by_account.py | 3 ++- api/controllers/topic/get_topic_public.py | 21 +++++++++++++-- .../0052_problem_allowed_languages.py | 18 +++++++++++++ api/models.py | 1 + api/serializers.py | 19 +++++++++----- api/views/collection.py | 4 +-- api/views/problem.py | 9 ++++--- 13 files changed, 91 insertions(+), 41 deletions(-) create mode 100644 api/controllers/problem/get_problem_public.py create mode 100644 api/migrations/0052_problem_allowed_languages.py diff --git a/api/controllers/collection/update_collection.py b/api/controllers/collection/update_collection.py index aa2df34..ae33e25 100644 --- a/api/controllers/collection/update_collection.py +++ b/api/controllers/collection/update_collection.py @@ -8,8 +8,7 @@ from django.forms.models import model_to_dict from ...serializers import * -def update_collection(collection_id:str,request): - collection = Collection.objects.get(collection_id=collection_id) +def update_collection(collection:Collection,request): collection.name = request.data.get('name',collection.name) collection.description = request.data.get('description',collection.description) diff --git a/api/controllers/problem/create_problem.py b/api/controllers/problem/create_problem.py index 16fb7a5..efcf4f6 100644 --- a/api/controllers/problem/create_problem.py +++ b/api/controllers/problem/create_problem.py @@ -22,7 +22,8 @@ def create_problem(account_id:str,request): title = request.data['title'], description = request.data['description'], solution = request.data['solution'], - time_limit = request.data['time_limit'] + time_limit = request.data['time_limit'], + allowed_languages = request.data['allowed_languages'], ) problem.save() diff --git a/api/controllers/problem/delete_problem.py b/api/controllers/problem/delete_problem.py index bcc75f2..fe057f1 100644 --- a/api/controllers/problem/delete_problem.py +++ b/api/controllers/problem/delete_problem.py @@ -8,11 +8,11 @@ from django.forms.models import model_to_dict from ...serializers import * -def delete_problem(problem_id:str): - try: - problem = Problem.objects.get(problem_id=problem_id) - except Problem.DoesNotExist: - return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) +def delete_problem(problem:Problem): + # try: + # problem = Problem.objects.get(problem_id=problem_id) + # except Problem.DoesNotExist: + # return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) testcases = Testcase.objects.filter(problem_id=problem_id) problem.delete() diff --git a/api/controllers/problem/get_problem_public.py b/api/controllers/problem/get_problem_public.py new file mode 100644 index 0000000..8dd5e6a --- /dev/null +++ b/api/controllers/problem/get_problem_public.py @@ -0,0 +1,14 @@ +from api.utility import passwordEncryption +from rest_framework.response import Response +from rest_framework.decorators import api_view +from api.sandbox.grader import PythonGrader +from ...constant import GET,POST,PUT,DELETE +from ...models import * +from rest_framework import status +from django.forms.models import model_to_dict +from ...serializers import * + +def get_problem_public(problem:Problem): + serialize = ProblemPopulateAccountSecureSerializer(problem) + return Response(serialize.data,status=status.HTTP_200_OK) + \ No newline at end of file diff --git a/api/controllers/problem/update_problem.py b/api/controllers/problem/update_problem.py index d60f98a..cd4a1a5 100644 --- a/api/controllers/problem/update_problem.py +++ b/api/controllers/problem/update_problem.py @@ -9,14 +9,12 @@ from ...serializers import * from django.utils import timezone -def update_problem(problem_id:str,request): - try: - problem = Problem.objects.get(problem_id=problem_id) - except Problem.DoesNotExist: - return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) - testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) - - print("AAA") +def update_problem(problem:Problem,request): + # try: + # problem = Problem.objects.get(problem_id=problem_id) + # except Problem.DoesNotExist: + # return Response({'detail': "Problem doesn't exist!"},status=status.HTTP_404_NOT_FOUND) + testcases = Testcase.objects.filter(problem=problem,deprecated=False) problem.title = request.data.get("title",problem.title) problem.language = request.data.get("language",problem.language) @@ -24,50 +22,42 @@ def update_problem(problem_id:str,request): problem.solution = request.data.get("solution",problem.solution) problem.time_limit = request.data.get("time_limit",problem.time_limit) problem.is_private = request.data.get("is_private",problem.is_private) + problem.allowed_languages = request.data.get("allowed_languages",problem.allowed_languages) problem.updated_date = timezone.now() - print("BBB") - if 'testcases' in request.data: running_result = PythonGrader(problem.solution,request.data['testcases'],1,1.5).generate_output() # if not running_result.runnable: # return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) - print("ZZZZZ") for testcase in testcases: testcase.deprecated = True testcase.save() - print("ZZZZZ") testcase_result = [] for unit in running_result.data: - print("YYYYY") testcase2 = Testcase( problem = problem, input = unit.input, output = unit.output, runtime_status = unit.runtime_status ) - print("YYYYY",testcase2.testcase_id) testcase2.save() - print("YYYYY") testcase_result.append(testcase2) problem.save() - print("ZZZZZ") problem_serialize = ProblemSerializer(problem) testcases_serialize = TestcaseSerializer(testcase_result,many=True) return Response({**problem_serialize.data,'testcases': testcases_serialize.data},status=status.HTTP_201_CREATED) if 'solution' in request.data: - testcases = Testcase.objects.filter(problem_id=problem_id,deprecated=False) + testcases = Testcase.objects.filter(problem=problem,deprecated=False) program_input = [i.input for i in testcases] running_result = PythonGrader(problem.solution,program_input,1,1.5).generate_output() if not running_result.runnable: return Response({'detail': 'Error during editing. Your code may has an error/timeout!'},status=status.HTTP_406_NOT_ACCEPTABLE) - print("CCC") problem.save() problem_serialize = ProblemSerializer(problem) return Response(problem_serialize.data,status=status.HTTP_201_CREATED) diff --git a/api/controllers/topic/delete_topic.py b/api/controllers/topic/delete_topic.py index 6d1db33..622c052 100644 --- a/api/controllers/topic/delete_topic.py +++ b/api/controllers/topic/delete_topic.py @@ -9,6 +9,5 @@ from ...serializers import * def delete_topic(topic:Topic): - topic = Topic.objects.get(topic=topic) topic.delete() return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/api/controllers/topic/get_all_accessed_topics_by_account.py b/api/controllers/topic/get_all_accessed_topics_by_account.py index 28753e0..68a92fc 100644 --- a/api/controllers/topic/get_all_accessed_topics_by_account.py +++ b/api/controllers/topic/get_all_accessed_topics_by_account.py @@ -7,10 +7,11 @@ from rest_framework import status from django.forms.models import model_to_dict from ...serializers import * +from django.db.models import Q def get_all_accessed_topics_by_account(account:Account): groups = [gm.group for gm in GroupMember.objects.filter(account=account)] - accessedTopics = TopicGroupPermission.objects.filter(group__in=groups,permission_view_topics=True).distinct() + accessedTopics = TopicGroupPermission.objects.filter(Q(group__in=groups) & (Q(permission_view_topics=True) | Q(permission_manage_topics=True))).distinct() topics = [at.topic for at in accessedTopics] serialize = TopicSerializer(topics,many=True) diff --git a/api/controllers/topic/get_topic_public.py b/api/controllers/topic/get_topic_public.py index bf948ec..36476b2 100644 --- a/api/controllers/topic/get_topic_public.py +++ b/api/controllers/topic/get_topic_public.py @@ -7,6 +7,7 @@ from rest_framework import status from django.forms.models import model_to_dict from ...serializers import * +from django.db.models import Q def get_topic_public(topic_id:str,request): @@ -14,7 +15,17 @@ def get_topic_public(topic_id:str,request): topic = Topic.objects.get(topic_id=topic_id) account = Account.objects.get(account_id=account_id) - topicCollections = TopicCollection.objects.filter(topic=topic,collection__in=CollectionGroupPermission.objects.filter(group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True),permission_view_collections=True).values_list("collection",flat=True)) + + + topicCollections = TopicCollection.objects.filter( + topic=topic, + collection__in= + CollectionGroupPermission.objects.filter( + Q(group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True)) & + ( + Q(permission_view_collections=True) | Q(permission_manage_collections=True) + ) + ).values_list("collection",flat=True)) for tp in topicCollections: # tp.collection.problems = CollectionProblem.objects.filter(collection=tp.collection) @@ -24,7 +35,13 @@ def get_topic_public(topic_id:str,request): # if len(viewPermission) == 0: # tp.collection.problems = [] # continue - collectionProblems = CollectionProblem.objects.filter(collection=tp.collection,problem__in=ProblemGroupPermission.objects.filter(group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True),permission_view_problems=True).values_list("problem",flat=True)) + collectionProblems = CollectionProblem.objects.filter( + collection=tp.collection, + problem__in=ProblemGroupPermission.objects.filter( + Q(group__in=GroupMember.objects.filter(account=account).values_list("group",flat=True)) & + (Q(permission_view_problems=True) | + Q(permission_manage_problems=True)) + ).values_list("problem",flat=True)) for cp in collectionProblems: try: diff --git a/api/migrations/0052_problem_allowed_languages.py b/api/migrations/0052_problem_allowed_languages.py new file mode 100644 index 0000000..7f940c1 --- /dev/null +++ b/api/migrations/0052_problem_allowed_languages.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2024-01-12 05:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0051_alter_account_account_id_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='problem', + name='allowed_languages', + field=models.CharField(blank=True, default='', max_length=1000), + ), + ] diff --git a/api/models.py b/api/models.py index 1f45db5..e30c9a1 100644 --- a/api/models.py +++ b/api/models.py @@ -43,6 +43,7 @@ class Problem(models.Model): created_date = models.DateTimeField(default=timezone.now) updated_date = models.DateTimeField(default=timezone.now) sharing = models.BooleanField(default=False,blank=True) + allowed_languages = models.CharField(max_length=1000,blank=True,default="") class Testcase(models.Model): testcase_id = models.CharField(primary_key=True,blank=True,default=generate_uuid4_hex,max_length=32) diff --git a/api/serializers.py b/api/serializers.py index 45e83e5..a4f9030 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -48,7 +48,7 @@ class Meta: class ProblemSecureSerializer(serializers.ModelSerializer): class Meta: model = Problem - fields = ['problem_id','title','description','is_active','is_private','updated_date','created_date'] + exclude = ['solution','submission_regex','is_private','is_active','sharing'] class ProblemPopulateAccountSerializer(serializers.ModelSerializer): creator = AccountSecureSerializer() @@ -57,6 +57,13 @@ class Meta: fields = "__all__" +class ProblemPopulateAccountSecureSerializer(serializers.ModelSerializer): + creator = AccountSecureSerializer() + class Meta: + model = Problem + exclude = ['solution','submission_regex','is_private','is_active','sharing'] + + class TopicCollectionSerializer(serializers.ModelSerializer): class Meta: @@ -140,11 +147,11 @@ class Meta: 'testcases' ] -class ProblemPopulateAccountSecureSerializer(serializers.ModelSerializer): - creator = AccountSecureSerializer() - class Meta: - model = Problem - fields = ['problem_id','title','description','creator'] +# class ProblemPopulateAccountSecureSerializer(serializers.ModelSerializer): +# creator = AccountSecureSerializer() +# class Meta: +# model = Problem +# fields = ['problem_id','title','description','creator'] class SubmissionPoplulateProblemSecureSerializer(serializers.ModelSerializer): problem = ProblemPopulateAccountSecureSerializer() diff --git a/api/views/collection.py b/api/views/collection.py index 661644d..424050c 100644 --- a/api/views/collection.py +++ b/api/views/collection.py @@ -34,9 +34,9 @@ def one_collection_creator_view(request,account_id:int,collection_id:str): if request.method == GET: return get_collection(collection) if request.method == PUT: - return update_collection(collection_id,request) + return update_collection(collection,request) if request.method == DELETE: - return delete_collection(collection_id) + return delete_collection(collection) @api_view([GET]) def all_collections_view(request): diff --git a/api/views/problem.py b/api/views/problem.py index 69439fd..7016010 100644 --- a/api/views/problem.py +++ b/api/views/problem.py @@ -19,6 +19,8 @@ from ..controllers.problem.get_all_problem_with_best_submission import * from ..controllers.problem.get_problem_in_topic_with_best_submission import * from ..controllers.problem.update_group_permission_to_problem import * +from ..controllers.problem.get_problem_public import * + # Create your views here. @api_view([POST,GET]) @@ -34,9 +36,9 @@ def one_problem_creator_view(request,problem_id:str,account_id:str): if request.method == GET: return get_problem(problem) elif request.method == PUT: - return update_problem(problem_id,request) + return update_problem(problem,request) elif request.method == DELETE: - return delete_problem(problem_id) + return delete_problem(problem) @api_view([GET,DELETE]) def all_problems_view(request): @@ -47,8 +49,9 @@ def all_problems_view(request): @api_view([GET,PUT,DELETE]) def one_problem_view(request,problem_id: int): + problem = Problem.objects.get(problem_id=problem_id) if request.method == GET: - return get_problem(problem_id) + return get_problem_public(problem) elif request.method == PUT: return update_problem(problem_id,request) elif request.method == DELETE: From 6456f5282878425c0eb85f53e2e7dede54698bde Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 13 Jan 2024 17:10:06 +0700 Subject: [PATCH 60/61] manual distinct in get accessed topics by account --- .../topic/get_all_accessed_topics_by_account.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/controllers/topic/get_all_accessed_topics_by_account.py b/api/controllers/topic/get_all_accessed_topics_by_account.py index 68a92fc..8d6cd87 100644 --- a/api/controllers/topic/get_all_accessed_topics_by_account.py +++ b/api/controllers/topic/get_all_accessed_topics_by_account.py @@ -11,8 +11,12 @@ def get_all_accessed_topics_by_account(account:Account): groups = [gm.group for gm in GroupMember.objects.filter(account=account)] - accessedTopics = TopicGroupPermission.objects.filter(Q(group__in=groups) & (Q(permission_view_topics=True) | Q(permission_manage_topics=True))).distinct() - topics = [at.topic for at in accessedTopics] + accessedTopics = TopicGroupPermission.objects.filter(Q(group__in=groups) & (Q(permission_view_topics=True) | Q(permission_manage_topics=True))) + + topics = [] + for at in accessedTopics: + if at.topic not in topics: + topics.append(at.topic) serialize = TopicSerializer(topics,many=True) From eaeae9a89cbb24e10195181cb3ae17da4ce29c6f Mon Sep 17 00:00:00 2001 From: KanonKC Date: Sat, 13 Jan 2024 17:24:55 +0700 Subject: [PATCH 61/61] Update default allowed language --- api/views/script.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/views/script.py b/api/views/script.py index bfc5b45..63aebd4 100644 --- a/api/views/script.py +++ b/api/views/script.py @@ -55,5 +55,9 @@ def run_script(request): # for collection in collections: # collection.description = '[{"id":"1","type":"p","children":[{"text":"Just course"}]}]' # collection.save() - generate_submission_score(request) + # generate_submission_score(request) + problems = Problem.objects.all() + for problem in problems: + problem.allowed_languages = "python,c,cpp" + problem.save() return Response({'message': 'Success!'},status=status.HTTP_201_CREATED)