diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index 68d4031e37..95b4302d05 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -121,6 +121,21 @@ curl -X POST http://localhost:8083/tests \ }' ``` +`PUT /tests/{questionDocRefId}` + +To update an existing test case from an existing question, run the following command: + +```bash +curl -X PUT http://localhost:8083/tests/{questionDocRefId} \ +-H "Content-Type: application/json" \ +-d '{ +"visibleTestCases": "2\nhello\nolleh\nHannah\nhannaH", +"hiddenTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba" +}' +``` + +```bash + `POST /tests/{questionDocRefId}/execute` To execute test cases via a question ID without custom test cases, run the following command, with custom code and language: diff --git a/apps/execution-service/handlers/create.go b/apps/execution-service/handlers/create.go index 5b9839fc04..a81422b898 100644 --- a/apps/execution-service/handlers/create.go +++ b/apps/execution-service/handlers/create.go @@ -40,6 +40,21 @@ func (s *Service) CreateTest(w http.ResponseWriter, r *http.Request) { return } + // Check if a test already exists for the question + iter := s.Client.Collection("tests").Where("questionDocRefId", "==", test.QuestionDocRefId).Documents(ctx) + for { + _, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + http.Error(w, "Error fetching test", http.StatusInternalServerError) + return + } + http.Error(w, "Test already exists for the question", http.StatusConflict) + return + } + // Save test to Firestore docRef, _, err := s.Client.Collection("tests").Add(ctx, map[string]interface{}{ "questionDocRefId": test.QuestionDocRefId, diff --git a/apps/execution-service/handlers/update.go b/apps/execution-service/handlers/update.go new file mode 100644 index 0000000000..1636456f96 --- /dev/null +++ b/apps/execution-service/handlers/update.go @@ -0,0 +1,92 @@ +package handlers + +import ( + "cloud.google.com/go/firestore" + "encoding/json" + "execution-service/models" + "execution-service/utils" + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" + "net/http" +) + +func (s *Service) UpdateTest(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // get param questionDocRefId + questionDocRefId := chi.URLParam(r, "questionDocRefId") + + var test models.Test + if err := utils.DecodeJSONBody(w, r, &test); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Only test cases will be updated + // Validate test case format with default validation + if _, err := utils.ValidateTestCaseFormat(test.VisibleTestCases, utils.GetDefaultValidation(), + utils.GetDefaultValidation()); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if _, err := utils.ValidateTestCaseFormat(test.HiddenTestCases, utils.GetDefaultValidation(), + utils.GetDefaultValidation()); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Update test in Firestore + docRef := s.Client.Collection("tests").Where("questionDocRefId", "==", questionDocRefId).Limit(1).Documents(ctx) + doc, err := docRef.Next() + if err != nil { + if err == iterator.Done { + http.Error(w, "Test not found", http.StatusNotFound) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer docRef.Stop() + + // Update database + updates := []firestore.Update{ + {Path: "visibleTestCases", Value: test.VisibleTestCases}, + {Path: "hiddenTestCases", Value: test.HiddenTestCases}, + {Path: "updatedAt", Value: firestore.ServerTimestamp}, + } + _, err = doc.Ref.Update(ctx, updates) + if err != nil { + http.Error(w, "Error updating test", http.StatusInternalServerError) + return + } + + // Get data + doc, err = doc.Ref.Get(ctx) + if err != nil { + if err != iterator.Done { + http.Error(w, "Test not found", http.StatusNotFound) + return + } + http.Error(w, "Failed to get test", http.StatusInternalServerError) + return + } + + // Map data + if err = doc.DataTo(&test); err != nil { + http.Error(w, "Failed to map test data", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(test) +} + +// Manual test cases + +//curl -X PUT http://localhost:8083/tests/sampleDocRefId123 \ +//-H "Content-Type: application/json" \ +//-d '{ +//"visibleTestCases": "2\nhello\nolleh\nHannah\nhannaH", +//"hiddenTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba" +//}' diff --git a/apps/execution-service/main.go b/apps/execution-service/main.go index 1173bfe2ff..3b79fbf527 100644 --- a/apps/execution-service/main.go +++ b/apps/execution-service/main.go @@ -90,7 +90,7 @@ func registerRoutes(r *chi.Mux, service *handlers.Service) { // Re: UpdateTest, DeleteTest // Current: Unused, since testcases are executed within service and not exposed // Future extension: can be read by admin to view testcases - //r.Put("/", service.UpdateTest) + r.Put("/", service.UpdateTest) //r.Delete("/", service.DeleteTest) r.Get("/", service.ReadVisibleTests) r.Post("/execute", service.ExecuteVisibleAndCustomTests)