Submission fixes, problem creation, refreshing towards next problem#102
Submission fixes, problem creation, refreshing towards next problem#102devsheth05 wants to merge 9 commits intomainfrom
Conversation
…ample size of 5 but easy change to csv of all problems)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This pull request implements a comprehensive set of fixes and features for submission handling, problem creation, and automatic progression to the next problem. The changes span across the RTC service, central service, and browser extension to create an end-to-end workflow for competitive programming sessions.
Changes:
- Refactored chat manager in RTC service to use map-based storage (string keys) instead of pointer-based maps for improved lookup performance
- Changed Room and Round IDs from UUID to string type throughout the system to support custom room codes
- Disabled Kafka integration (commented out) and added direct HTTP submission endpoint
- Implemented LeetCode submission detection in browser extension with automatic navigation to next problem
- Added seed generation script for populating problem database from LeetCode API
- Disabled authentication middleware for local development testing
Reviewed changes
Copilot reviewed 24 out of 31 changed files in this pull request and generated 32 comments.
Show a summary per file
| File | Description |
|---|---|
| rtc-service/servicesmanager/service.go | Added lazy room creation and changed user iteration to handle string-keyed maps |
| rtc-service/chatmanager/user.go | Changed UserList from map[*User]bool to map[string]*User |
| rtc-service/chatmanager/room.go | Refactored to use handle-based user lookups instead of pointer iteration |
| rtc-service/chatmanager/manager.go | Changed RoomsList to map[string]*Room for string-based room lookups |
| central-service/services/submission-queue.go | Disabled Kafka producer/consumer with extensive commented code |
| central-service/services/round.go | Changed RoomID from UUID to string, wrapped problem association in transaction |
| central-service/services/room.go | Added generateRoomCode function, new ProcessSubmissionSuccess method |
| central-service/services/problem.go | Added slug field support, simplified problem query logic |
| central-service/models/room.go | Changed Room.ID from uuid.UUID to string |
| central-service/models/round.go | Changed Round.RoomID from uuid.UUID to string |
| central-service/main.go | Disabled authentication middleware, added fake token for testing |
| central-service/controllers/submission.go | New submission controller for handling problem submissions |
| docker-compose.yml | Added rtc-service dependency, seed SQL mount, changed adminer port |
| bsg-frontend/extension/contentScript.js | Implemented LeetCode submission detection with DOM observation |
| bsg-frontend/extension/background.js | Added submission handling with auto-navigation and state persistence |
| bsg-frontend/extension/manifest.json | Added notifications permission and overwriteFetch.js |
| bsg-frontend/extension/overwriteFetch.js | New file intercepting LeetCode API responses |
| bsg-frontend/apps/extension/pages/room-choice.tsx | Backend integration for room/round creation |
| bsg-frontend/apps/extension/pages/_app.tsx | Complete room state management and chat UI |
| central-service/scripts/generate_seeds.py | New script for fetching and seeding LeetCode problems |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
central-service/main.go
Outdated
| //e.Use(userController.ValidateUserRequest) //temp disabled for testing | ||
| e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { | ||
| return func(c echo.Context) error { | ||
| // Create a fake auth token for testing | ||
| fakeToken := &auth.Token{ | ||
| UID: "test-user-123", | ||
| } | ||
| c.Set("authToken", fakeToken) | ||
| return next(c) | ||
| } | ||
| }) |
There was a problem hiding this comment.
The authentication middleware has been disabled and replaced with a fake token for testing purposes. This creates a critical security vulnerability as any request will be processed with a fake "test-user-123" UID, bypassing actual authentication checks. This should be re-enabled before merging to any environment that isn't strictly local development.
| @@ -122,32 +136,32 @@ func (egressQueueService *SubmissionEgressQueueService) ProcessSubmissionData(ra | |||
| } | |||
|
|
|||
| var scoreToAdd uint = 0 | |||
| var problem models.Problem | |||
| var lbUserID uint = 0 | |||
|
|
|||
| if payload.Verdict == constants.SUBMISSION_STATUS_ACCEPTED { | |||
| egressQueueService.db.First(&problem, submission.ProblemID) | |||
|
|
|||
| if submission.SubmissionOwnerType == "round_submissions" { | |||
| var roundSubmission models.RoundSubmission | |||
| err := egressQueueService.db.Preload("Round").Preload("RoundParticipant").First(&roundSubmission, submission.SubmissionOwnerID).Error | |||
| if err == nil { | |||
| scoreToAdd, _ = egressQueueService.roundService.DetermineScoreDeltaForUserBySubmission( | |||
| &problem, | |||
| &roundSubmission.RoundParticipant, | |||
| &roundSubmission.Round, | |||
| ) | |||
| var user models.User | |||
| if err := egressQueueService.db.Where("auth_id = ?", roundSubmission.RoundParticipant.ParticipantAuthID).First(&user).Error; err == nil { | |||
| lbUserID = user.ID | |||
| } | |||
| } | |||
| } else { | |||
| // honestly no clue when this would get hit | |||
| scoreToAdd = egressQueueService.roundService.problemAccessor.GetProblemAccessor().DetermineScoreForProblem(&problem) | |||
| lbUserID = uint(submission.SubmissionOwnerID) | |||
| } | |||
| var problem models.Problem | |||
| var lbUserID uint = 0 | |||
|
|
|||
| if payload.Verdict == constants.SUBMISSION_STATUS_ACCEPTED { | |||
| egressQueueService.db.First(&problem, submission.ProblemID) | |||
|
|
|||
| if submission.SubmissionOwnerType == "round_submissions" { | |||
| var roundSubmission models.RoundSubmission | |||
| err := egressQueueService.db.Preload("Round").Preload("RoundParticipant").First(&roundSubmission, submission.SubmissionOwnerID).Error | |||
| if err == nil { | |||
| scoreToAdd, _ = egressQueueService.roundService.DetermineScoreDeltaForUserBySubmission( | |||
| &problem, | |||
| &roundSubmission.RoundParticipant, | |||
| &roundSubmission.Round, | |||
| ) | |||
|
|
|||
| var user models.User | |||
| if err := egressQueueService.db.Where("auth_id = ?", roundSubmission.RoundParticipant.ParticipantAuthID).First(&user).Error; err == nil { | |||
| lbUserID = user.ID | |||
| } | |||
| } | |||
| } else { | |||
| // honestly no clue when this would get hit | |||
| scoreToAdd = egressQueueService.roundService.problemAccessor.GetProblemAccessor().DetermineScoreForProblem(&problem) | |||
| lbUserID = uint(submission.SubmissionOwnerID) | |||
| } | |||
|
|
|||
| if lbUserID != 0 { | |||
| var existingAcceptedCount int64 | |||
| @@ -156,15 +170,15 @@ func (egressQueueService *SubmissionEgressQueueService) ProcessSubmissionData(ra | |||
| Joins("LEFT JOIN round_submissions rs ON submissions.submission_owner_id = rs.id AND submissions.submission_owner_type = 'round_submissions'"). | |||
| Joins("LEFT JOIN round_participants rp ON rs.round_participant_id = rp.id"). | |||
| Joins("LEFT JOIN users u ON (u.id = submissions.submission_owner_id AND submissions.submission_owner_type = 'user') OR (u.auth_id = rp.participant_auth_id)"). | |||
| Where("submissions.problem_id = ? AND submissions.verdict = ? AND u.id = ? AND submissions.id <> ?", | |||
| Where("submissions.problem_id = ? AND submissions.verdict = ? AND u.id = ? AND submissions.id <> ?", | |||
| submission.ProblemID, constants.SUBMISSION_STATUS_ACCEPTED, lbUserID, submission.ID). | |||
| Count(&existingAcceptedCount).Error | |||
|
|
|||
| if err == nil && existingAcceptedCount > 0 { | |||
| scoreToAdd = 0 | |||
| } | |||
| } | |||
| } | |||
| } | |||
|
|
|||
| // update verdict in database | |||
| result = egressQueueService.db.Model(&submission).Update("verdict", payload.Verdict) | |||
| @@ -195,28 +209,31 @@ func (egressQueueService *SubmissionEgressQueueService) ProcessSubmissionData(ra | |||
| } | |||
|
|
|||
| func (egressQueueService *SubmissionEgressQueueService) ListenForSubmissionData() { | |||
| run := true | |||
| msg_count := 0 | |||
| for run { | |||
| ev := egressQueueService.consumer.Poll(100) | |||
| switch e := ev.(type) { | |||
| case *kafka.Message: | |||
| msg_count += 1 | |||
| if msg_count % MIN_COMMIT_COUNT == 0 { | |||
| egressQueueService.consumer.Commit() | |||
| //Kafka consumer loop is disabled | |||
| /* | |||
| run := true | |||
| msg_count := 0 | |||
| for run { | |||
| ev := egressQueueService.consumer.Poll(100) | |||
| switch e := ev.(type) { | |||
| case *kafka.Message: | |||
| msg_count += 1 | |||
| if msg_count % MIN_COMMIT_COUNT == 0 { | |||
| egressQueueService.consumer.Commit() | |||
| } | |||
| err := egressQueueService.ProcessSubmissionData(e.Value) | |||
| if err != nil { | |||
| fmt.Printf("Error processing message at Kafka Egress Queue: %v\n", err) | |||
| } | |||
| case kafka.Error: | |||
| fmt.Printf("Error detected at Kafka Egress Consumer: %v\n", e) | |||
| run = false | |||
| default: | |||
| if e != nil { | |||
| fmt.Printf("Unexpected message at Kafka Egress Consumer: %v\n", e) | |||
| } | |||
| } | |||
| } | |||
| err := egressQueueService.ProcessSubmissionData(e.Value) | |||
| if err != nil { | |||
| fmt.Printf("Error processing message at Kafka Egress Queue: %v\n", err) | |||
| } | |||
| case kafka.Error: | |||
| fmt.Printf("Error detected at Kafka Egress Consumer: %v\n", e) | |||
| run = false | |||
| default: | |||
| if e != nil { | |||
| fmt.Printf("Unexpected message at Kafka Egress Consumer: %v\n", e) | |||
| } | |||
| } | |||
| } | |||
| egressQueueService.consumer.Close() | |||
| } No newline at end of file | |||
| egressQueueService.consumer.Close() | |||
| */ | |||
| } | |||
There was a problem hiding this comment.
Large blocks of commented-out Kafka code should be removed rather than commented out. This reduces code clutter and makes the codebase easier to maintain. If this code needs to be preserved for future reference, it should be documented in a separate design document or git history can be used to retrieve it.
| console.warn("⚠️ Firebase not initialized or user not logged in. Using dummy token for local development."); | ||
| return "dummy-token-123"; |
There was a problem hiding this comment.
The error handling when auth.currentUser is null defaults to using a "dummy-token-123" (line 168). In production environments, this should fail gracefully rather than proceeding with a fake token. Consider throwing an error or showing a login prompt instead of silently using a dummy token.
| console.warn("⚠️ Firebase not initialized or user not logged in. Using dummy token for local development."); | |
| return "dummy-token-123"; | |
| console.warn("⚠️ Firebase not initialized or user not logged in. Cannot obtain auth token."); | |
| throw new Error("User is not authenticated or Firebase is not initialized."); |
|
|
||
| // List of all chat users connected to RTC service. | ||
| type UserList map[*User]bool | ||
| // List of all chat users connected to RTC service. |
There was a problem hiding this comment.
The duplicate comment on line 4 "List of all chat users connected to RTC service." should be removed. It's redundant with the comment on line 3.
| // List of all chat users connected to RTC service. |
| // Update or add user to the room by their handle | ||
| r.Users[user.Handle] = user | ||
|
|
||
| logging.Info("Added: ", user.Handle, " to room: ", r.RoomID) | ||
| logging.Info("Added/Updated: ", user.Handle, " in room: ", r.RoomID) |
There was a problem hiding this comment.
The AddUser method now silently updates existing users instead of checking for duplicates and logging an error (lines 35-38). While this is a valid design choice, it changes the semantics - previously adding an existing user was treated as an error condition. Consider documenting this behavior change or restoring the duplicate check with a warning log to help with debugging.
| const containerRef = useRef<HTMLDivElement>(null) | ||
|
|
||
| // Initialize WebSocket Hook | ||
| const { messages, isConnected, joinRoom, sendChatMessage, addMessage } = useChatSocket(userProfile?.id); |
There was a problem hiding this comment.
Unused variable isConnected.
| const { messages, isConnected, joinRoom, sendChatMessage, addMessage } = useChatSocket(userProfile?.id); | |
| const { messages, joinRoom, sendChatMessage, addMessage } = useChatSocket(userProfile?.id); |
| const participants: Participant[] = currentRoom.options?.participants || [] | ||
|
|
There was a problem hiding this comment.
Unused variable participants.
| const participants: Participant[] = currentRoom.options?.participants || [] |
| // Track if we've already processed the current success state | ||
| let isCurrentlySuccess = false; | ||
| let lastSubmitTime = 0; | ||
|
|
||
| // Listen for clicks on the Submit button | ||
| document.addEventListener('click', (e) => { | ||
| const target = e.target; |
There was a problem hiding this comment.
Unused variable isCurrentlySuccess.
| // Track if we've already processed the current success state | |
| let isCurrentlySuccess = false; | |
| let lastSubmitTime = 0; | |
| // Listen for clicks on the Submit button | |
| document.addEventListener('click', (e) => { | |
| const target = e.target; | |
| // Track if we've already processed the current success state | |
| let lastSubmitTime = 0; | |
| // Listen for clicks on the Submit button | |
| document.addEventListener('click', (e) => { | |
| const target = e.target; |
| } | ||
|
|
||
| // Navigate to the first problem | ||
| if (shouldNavigate && firstProblemSlug) { |
There was a problem hiding this comment.
This use of variable 'shouldNavigate' always evaluates to true.
| import requests | ||
| import os | ||
| import csv | ||
| import io |
There was a problem hiding this comment.
Import of 'io' is not used.
| import io |
|
🔴 CRITICAL ISSUES IN PR #102
The PR adds FindRoomByCode() in the central service to support 5-character room codes, but the RTC service still uses the old room lookup logic. When the extension sends messages with a room code instead of UUID, RTC won't find the room properly. Impact: Room messages won't route correctly between clients.
Room model now has RoomCode field, but the Problem model is missing Slug and Difficulty fields that are being used in: problem.go: FindProblemBySlug() function
The backend changed from extracting auth via Firebase to expecting userAuthID as a string in context: // OLD: c.Get("authToken").(*auth.Token).UID Impact: All room operations will crash with type assertion panic.
CreateRound() signature changed from: CreateRound(params *RoundCreationParameters, roomID string) to: CreateRound(params *RoundCreationParameters, roomID uuid.UUID) parsedRoomID, err := uuid.Parse(roomID) // roomID is a string
Changed from storing rooms as: sm.Rooms[room] = true // room is *Room pointer (wrong key type!) to: sm.Rooms[room.RoomID] = room // room.RoomID is string
All Kafka code is commented out with // Kafka produce disabled, but main.go still calls: ingressQueue.MessageDeliveryHandler() // Spawned in goroutine
New SUBMISSION_SUCCESS message handler tries to POST to /api/submissions/ with Authorization header, but there's no guarantee the middleware to extract this token exists in the central service. Impact: Submission reporting endpoint will fail auth checks. Summary 3 compilation errors (type mismatches) ts from copilot, 10k changes are a lot, if you can resolve all of these, and then show me it runs and succeeds, then show me how to run it on my local, then i'll merge |
No description provided.