func TestsByTaskKey(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { _, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } taskKey, err := datastore.DecodeKey(mux.Vars(r)["key"]) if err != nil { return http.StatusInternalServerError, err } var tests model.Tests var testKeys []*datastore.Key if testKeys, err = model.NewQueryForTest().Ancestor(taskKey).GetAll(ctx, &tests); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(tests.Key(testKeys)) return http.StatusOK, nil }
// PostSubmission creates a new submission. func PostSubmission(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "POST" { return http.StatusMethodNotAllowed, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { return http.StatusBadRequest, err } if !strings.HasPrefix(mediaType, "multipart/") { return http.StatusUnsupportedMediaType, nil } resultKey, err := datastore.DecodeKey(mux.Vars(r)["resultKey"]) if err != nil { return http.StatusNotFound, err } if !util.HasParent(p.User, resultKey) { return http.StatusBadRequest, errors.New("cannot submit answer for other users") } taskKey, err := datastore.DecodeKey(mux.Vars(r)["taskKey"]) if err != nil { return http.StatusNotFound, err } if err := r.ParseMultipartForm(16 << 20); err != nil { return http.StatusBadRequest, err } files, ok := r.MultipartForm.File["files"] if !ok { return http.StatusBadRequest, errors.New("missing files") } var task model.Task if err = datastore.Get(ctx, taskKey, &task); err != nil { return http.StatusNotFound, err } // Furthermore, the name of the GCS object is derived from the of the // encapsulating Submission. To avoid race conditions, allocate an ID. low, _, err := datastore.AllocateIDs(ctx, model.SubmissionKind, resultKey, 1) if err != nil { return http.StatusInternalServerError, err } submissionKey := datastore.NewKey(ctx, model.SubmissionKind, "", low, resultKey) storedCode := model.StoredObject{ Bucket: util.SubmissionBucket(), Name: nameObject(submissionKey) + "/Code/", } submission := model.Submission{ Task: taskKey, Time: time.Now(), Language: detectLanguage(files), Code: storedCode, } if _, err = datastore.Put(ctx, submissionKey, &submission); err != nil { return http.StatusInternalServerError, err } var tests model.Tests testKeys, err := model.NewQueryForTest(). Ancestor(taskKey). GetAll(ctx, &tests) if err != nil { return http.StatusInternalServerError, err } prrs, pwrs := multiPipe(len(tests)) go maketar(pwrs, files) for i, t := range tests { go func(i int, t model.Test) { if err := test.Tester(t.Tester).Call(ctx, *t.Key(testKeys[i]), *submission.Key(submissionKey), prrs[i]); err != nil { log.Warningf(ctx, "%s", err) } }(i, t) } if err := upload(util.CloudContext(ctx), storedCode.Bucket, storedCode.Name, files); err != nil { return http.StatusInternalServerError, err } return http.StatusOK, nil }
// PostSubmission creates a new submission. func PostSubmission(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "POST" { return http.StatusMethodNotAllowed, nil } var body = struct { Code string Language string }{} if err := json.NewDecoder(r.Body).Decode(&body); err != nil { return http.StatusBadRequest, err } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } resultKey, err := datastore.DecodeKey(mux.Vars(r)["resultKey"]) if err != nil { return http.StatusNotFound, err } if !util.HasParent(p.User, resultKey) { return http.StatusBadRequest, errors.New("cannot submit answer for other users") } taskKey, err := datastore.DecodeKey(mux.Vars(r)["taskKey"]) if err != nil { return http.StatusNotFound, err } var task model.Task if err = datastore.Get(ctx, taskKey, &task); err != nil { return http.StatusInternalServerError, err } // Furthermore, the name of the GCS object is derived from the of the // encapsulating Submission. To avoid race conditions, allocate an ID. low, _, err := datastore.AllocateIDs(ctx, model.SubmissionKind, resultKey, 1) if err != nil { return http.StatusInternalServerError, err } submissionKey := datastore.NewKey(ctx, model.SubmissionKind, "", low, resultKey) submission := model.Submission{ Task: taskKey, Time: time.Now(), } if body.Code != "" { submission.Code, err = store(ctx, submissionKey, body.Code, body.Language) if err != nil { return http.StatusInternalServerError, err } submission.Language = body.Language } // Set the submission in stone. if _, err = datastore.Put(ctx, submissionKey, &submission); err != nil { return http.StatusInternalServerError, err } var tests model.Tests _, err = model.NewQueryForTest(). Ancestor(taskKey). GetAll(ctx, &tests) if err != nil { return http.StatusInternalServerError, err } for _, t := range tests { if err := test.Tester(t.Tester).Call(ctx, t.Params, *submission.Key(submissionKey)); err != nil { log.Warningf(ctx, "%s", err) continue } } // TODO(flowlo): Return something meaningful. return http.StatusOK, nil }