@@ -133,3 +133,108 @@ def test_activity_day_changes_at_six_am_kst_and_streaks_are_server_calculated(se
133133 {"date" : yesterday .isoformat (), "count" : 1 },
134134 {"date" : today .isoformat (), "count" : 1 },
135135 ])
136+
137+
138+ class ProfileProblemAPITest (APITestCase ):
139+
140+ def setUp (self ):
141+ self .create_school_fixtures (college_id = 1 , college_name = "Test" , department_id = 1 , department_name = "Test" )
142+ self .user = self .create_user (email = "problem@test.com" , username = "problem" , password = "test1234!" )
143+ problem_data = copy .deepcopy (DEFAULT_PROBLEM_DATA )
144+ problem_data ["_id" ] = "PROFILE-PROBLEM-1"
145+ self .problem = ProblemCreateTestBase .add_problem (problem_data , self .user )
146+ self .url = self .reverse ("profile_problem_api" )
147+
148+ def create_submission (self , result , created_at ):
149+ submission = Submission .objects .create (
150+ user_id = self .user .id ,
151+ username = self .user .username ,
152+ problem = self .problem ,
153+ code = "print(1)" ,
154+ language = "Python3" ,
155+ result = result ,
156+ )
157+ Submission .objects .filter (id = submission .id ).update (create_time = created_at )
158+ return submission
159+
160+ def test_returns_all_problem_submissions_in_latest_order (self ):
161+ current_timezone = timezone .get_current_timezone ()
162+ base_time = timezone .make_aware (datetime .datetime (2026 , 6 , 25 , 12 , 0 ), current_timezone )
163+ older_submission = self .create_submission (JudgeStatus .WRONG_ANSWER , base_time )
164+ latest_submission = self .create_submission (JudgeStatus .ACCEPTED , base_time + datetime .timedelta (minutes = 5 ))
165+
166+ response = self .client .get (self .url , {"username" : self .user .username })
167+
168+ self .assertSuccess (response )
169+ data = response .data ["data" ]
170+ self .assertEqual (len (data ), 2 )
171+ self .assertEqual (data [0 ]["submissionId" ], latest_submission .id )
172+ self .assertEqual (data [0 ]["id" ], self .problem ._id )
173+ self .assertEqual (data [0 ]["serviceDate" ], base_time .date ().isoformat ())
174+ self .assertEqual (data [0 ]["serviceMonth" ], "2026-06" )
175+ self .assertEqual (data [0 ]["status" ], JudgeStatus .ACCEPTED )
176+ self .assertEqual (data [1 ]["submissionId" ], older_submission .id )
177+ self .assertEqual (data [1 ]["id" ], self .problem ._id )
178+ self .assertEqual (data [1 ]["status" ], JudgeStatus .WRONG_ANSWER )
179+
180+ def test_returns_service_date_by_six_am_kst_boundary (self ):
181+ before_boundary = datetime .datetime (2026 , 6 , 26 , 20 , 59 , tzinfo = datetime .timezone .utc )
182+ after_boundary = datetime .datetime (2026 , 6 , 26 , 21 , 0 , tzinfo = datetime .timezone .utc )
183+ self .create_submission (JudgeStatus .ACCEPTED , before_boundary )
184+ self .create_submission (JudgeStatus .ACCEPTED , after_boundary )
185+
186+ response = self .client .get (self .url , {"username" : self .user .username })
187+
188+ self .assertSuccess (response )
189+ data = response .data ["data" ]
190+ self .assertEqual (data [0 ]["serviceDate" ], "2026-06-27" )
191+ self .assertEqual (data [0 ]["serviceMonth" ], "2026-06" )
192+ self .assertEqual (data [1 ]["serviceDate" ], "2026-06-26" )
193+ self .assertEqual (data [1 ]["serviceMonth" ], "2026-06" )
194+
195+ def test_filters_problem_field_by_numeric_or_string_value (self ):
196+ current_timezone = timezone .get_current_timezone ()
197+ created_at = timezone .make_aware (datetime .datetime (2026 , 6 , 25 , 12 , 0 ), current_timezone )
198+ self .create_submission (JudgeStatus .ACCEPTED , created_at )
199+
200+ numeric_response = self .client .get (self .url , {"username" : self .user .username , "field" : "0" })
201+ string_response = self .client .get (self .url , {"username" : self .user .username , "field" : "implementation" })
202+
203+ self .assertSuccess (numeric_response )
204+ self .assertSuccess (string_response )
205+ self .assertEqual (numeric_response .data ["data" ], string_response .data ["data" ])
206+ self .assertEqual (len (string_response .data ["data" ]), 1 )
207+
208+ def test_invalid_problem_field_filter_returns_api_error (self ):
209+ response = self .client .get (self .url , {"username" : self .user .username , "field" : "unknown" })
210+
211+ self .assertFailed (response , "Invalid field" )
212+
213+ def test_missing_username_returns_api_error (self ):
214+ response = self .client .get (self .url )
215+
216+ self .assertFailed (response , "username is required" )
217+
218+ def test_unknown_username_returns_api_error (self ):
219+ response = self .client .get (self .url , {"username" : "missing" })
220+
221+ self .assertFailed (response , "User does not exist" )
222+
223+ def test_invalid_problem_status_filter_returns_api_error (self ):
224+ response = self .client .get (self .url , {"username" : self .user .username , "status" : "unknown" })
225+
226+ self .assertFailed (response , "Invalid status" )
227+
228+ def test_failed_status_filter_excludes_pending_submissions (self ):
229+ current_timezone = timezone .get_current_timezone ()
230+ base_time = timezone .make_aware (datetime .datetime (2026 , 6 , 25 , 12 , 0 ), current_timezone )
231+ self .create_submission (JudgeStatus .WRONG_ANSWER , base_time )
232+ self .create_submission (JudgeStatus .PENDING , base_time + datetime .timedelta (minutes = 1 ))
233+ self .create_submission (JudgeStatus .JUDGING , base_time + datetime .timedelta (minutes = 2 ))
234+
235+ response = self .client .get (self .url , {"username" : self .user .username , "status" : "Failed" })
236+
237+ self .assertSuccess (response )
238+ data = response .data ["data" ]
239+ self .assertEqual (len (data ), 1 )
240+ self .assertEqual (data [0 ]["status" ], JudgeStatus .WRONG_ANSWER )
0 commit comments