func createFinalResult(ctx context.Context, w http.ResponseWriter, resultKey *datastore.Key, result model.Result) (int, error) { go computeFinalScore(ctx, result) var challenge model.Challenge if err := datastore.Get(ctx, result.Challenge, &challenge); err != nil { return http.StatusInternalServerError, nil } var taskKey *datastore.Key for _, taskKey = range challenge.Tasks { switch taskKey.Kind() { case model.CodeTaskKind: var submissions model.CodeSubmissions keys, err := doQuery(ctx, model.NewQueryForCodeSubmission(), resultKey, taskKey, submissions) if err != nil { return http.StatusInternalServerError, nil } if len(keys) == 0 { // Most likely the authenticated user called this endpoint // before finishing the challenge return http.StatusUnauthorized, nil } result.FinalSubmissions = append(result.FinalSubmissions, keys[0]) //TODO(pbochis, vbalan, flowlo): Add more cases when more task kinds are added. default: return http.StatusBadRequest, errors.New("Unknown submission kind.") } } key, err := result.Save(ctx, resultKey) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(result.Key(key)) return http.StatusOK, nil }
// FinalSubmission makes the last submission final. func FinalSubmission(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } if r.Method != "POST" { return http.StatusMethodNotAllowed, nil } var resultKey *datastore.Key if resultKey, err = datastore.DecodeKey(mux.Vars(r)["resultKey"]); err != nil { return http.StatusInternalServerError, err } if !util.HasParent(p.UserKey, resultKey) { return http.StatusBadRequest, errors.New("cannot submit answer for other users") } var index int if index, err = strconv.Atoi(mux.Vars(r)["index"]); err != nil { return http.StatusInternalServerError, err } var submissionKey *datastore.Key if submissionKey, err = datastore.DecodeKey(mux.Vars(r)["submissionKey"]); err != nil { return http.StatusInternalServerError, err } var result model.Result if err = datastore.Get(ctx, resultKey, &result); err != nil { return http.StatusInternalServerError, err } result.FinalSubmissions[index] = submissionKey if _, err = result.Save(ctx, resultKey); err != nil { return http.StatusInternalServerError, err } w.Write([]byte("OK")) return }
// TaskByKey loads a task by key. func TaskByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { p, 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 } // User is a coder if p.UserKey.Parent() == nil { rk, err := datastore.DecodeKey(r.URL.Query()["result"][0]) if err != nil { return http.StatusInternalServerError, err } if !util.HasParent(p.UserKey, rk) { return http.StatusUnauthorized, nil } var result model.Result if err = datastore.Get(ctx, rk, &result); err != nil { return http.StatusInternalServerError, err } var challenge model.Challenge if err = datastore.Get(ctx, result.Challenge, &challenge); err != nil { return http.StatusInternalServerError, err } emptyTime := time.Time{} updateResult := false for i, val := range challenge.Tasks { if taskKey.Equal(val) && result.StartTimes[i] == emptyTime { result.StartTimes[i] = time.Now() updateResult = true break } } if updateResult { if _, err = result.Save(ctx, rk); err != nil { return http.StatusInternalServerError, err } } } switch taskKey.Kind() { case model.CodeTaskKind: var task model.CodeTask if err = datastore.Get(ctx, taskKey, &task); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(task.Key(taskKey)) return http.StatusOK, nil default: return http.StatusInternalServerError, errors.New("Not implemented") } }