func createFinalResult(ctx context.Context, w http.ResponseWriter, resultKey *datastore.Key, result model.Result) (int, error) { var challenge model.Challenge if err := datastore.Get(ctx, result.Challenge, &challenge); err != nil { return http.StatusInternalServerError, nil } result.Finished = time.Now() for i, taskKey := range challenge.Tasks { key, err := getLatestSubmissionKey(ctx, resultKey, taskKey) if err != nil { return http.StatusInternalServerError, err } result.FinalSubmissions[i] = key } key, err := result.Put(ctx, resultKey) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(result.Key(key)) go computeFinalScore(ctx, challenge, result, resultKey) return http.StatusOK, nil }
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 }
func GetResult(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if !util.CheckMethod(r, "GET") { return http.StatusMethodNotAllowed, nil } resultKey, err := datastore.DecodeKey(mux.Vars(r)["resultKey"]) if err != nil { return http.StatusBadRequest, err } var result model.Result if err := datastore.Get(ctx, resultKey, &result); err != nil { return http.StatusInternalServerError, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } if p.UserKey.Parent() != nil { json.NewEncoder(w).Encode(result.Key(resultKey)) return http.StatusOK, nil } if !util.HasParent(resultKey, p.UserKey) { return http.StatusUnauthorized, nil } return createFinalResult(ctx, w, resultKey, result) }
// FinalSubmission makes the last submission final. func FinalSubmission(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 } var resultKey *datastore.Key if resultKey, err = datastore.DecodeKey(mux.Vars(r)["resultKey"]); err != nil { return http.StatusInternalServerError, err } if !util.HasParent(p.User, 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 } if len(r.URL.Query()["submissionKey"]) == 0 { return http.StatusOK, nil } var submissionKey *datastore.Key if submissionKey, err = datastore.DecodeKey(r.URL.Query()["submissionKey"][0]); 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.Put(ctx, resultKey); err != nil { return http.StatusInternalServerError, err } w.Write([]byte("OK")) return }
func GetResult(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } resultKey, err := datastore.DecodeKey(mux.Vars(r)["resultKey"]) if err != nil { return http.StatusBadRequest, err } var result model.Result if err := datastore.Get(ctx, resultKey, &result); err != nil { return http.StatusInternalServerError, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var u model.User if err = datastore.Get(ctx, p.User, &u); err != nil { return http.StatusInternalServerError, nil } if u.Company == nil && !util.HasParent(p.User, resultKey) { return http.StatusUnauthorized, nil } if result.Finished.Equal(time.Time{}) { if util.HasParent(p.User, resultKey) { return createFinalResult(ctx, w, *result.Key(resultKey)) } var challenge model.Challenge if err := datastore.Get(ctx, result.Challenge, &challenge); err != nil { return http.StatusInternalServerError, err } if u.Company != nil && result.Started.Add(challenge.Duration).Before(time.Now()) { return createFinalResult(ctx, w, *result.Key(resultKey)) } } json.NewEncoder(w).Encode(result.Key(resultKey)) return http.StatusOK, nil }
func init() { RegisterResulter(Average, func(ctx context.Context, resultKey *datastore.Key) error { var result model.Result if err := datastore.Get(ctx, resultKey, &result); err != nil { return err } var challenge model.Challenge if err := datastore.Get(ctx, result.Challenge, &challenge); err != nil { return err } var tasks model.Tasks if err := datastore.GetMulti(ctx, challenge.Tasks, &tasks); err != nil { return err } weightSum := model.Skills{} // this could be SkillWeights, but would need more conversions average := model.Skills{} for i, task := range tasks { taskResult, err := Tasker(task.Tasker).Call(ctx, challenge.Tasks[i], resultKey.Parent().Parent()) if err != nil { return err } average = average.Add(taskResult.Mul(model.Skills(task.SkillWeights))) weightSum = weightSum.Add(model.Skills(task.SkillWeights)) } result.Skills = average.Div(weightSum) result.Computed = time.Now() _, err := result.Put(ctx, resultKey) return err }) }
// CreateResult saves a new result when a coder starts a challenge. func CreateResult(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if r.Method != "POST" { return http.StatusMethodNotAllowed, nil } var body = struct { ChallengeKey string }{} p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var profiles model.Profiles keys, err := model.NewQueryForProfile(). Ancestor(p.User). GetAll(ctx, &profiles) if len(keys) != 1 { return http.StatusInternalServerError, errors.New("Profile not found") } err = json.NewDecoder(r.Body).Decode(&body) if err != nil { return http.StatusBadRequest, err } key, err := datastore.DecodeKey(body.ChallengeKey) if err != nil { return http.StatusBadRequest, err } var results []model.Result resultKeys, err := model.NewQueryForResult(). Ancestor(keys[0]). Filter("Challenge = ", key). Limit(1). GetAll(ctx, &results) if err != nil { return http.StatusInternalServerError, err } if len(resultKeys) == 1 { json.NewEncoder(w).Encode(results[0].Key(resultKeys[0])) return http.StatusOK, nil } var challenge model.Challenge if err = datastore.Get(ctx, key, &challenge); err != nil { return http.StatusInternalServerError, err } result := model.Result{ Challenge: key, StartTimes: make([]time.Time, len(challenge.Tasks)), FinalSubmissions: make([]*datastore.Key, len(challenge.Tasks)), Started: time.Now(), } key, err = result.PutWithParent(ctx, keys[0]) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(result.Key(key)) return http.StatusOK, nil }
// 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 } var u model.User if err = datastore.Get(ctx, p.User, &u); err != nil { return http.StatusInternalServerError, nil } if len(r.URL.Query()["result"]) > 0 { rk, err := datastore.DecodeKey(r.URL.Query()["result"][0]) if err != nil { return http.StatusInternalServerError, err } if util.HasParent(p.User, rk) { 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) { if result.StartTimes[i].Equal(emptyTime) { result.StartTimes[i] = time.Now() updateResult = true break } } } if updateResult { if _, err = result.Put(ctx, rk); err != nil { return http.StatusInternalServerError, err } } } } var task model.Task if err = datastore.Get(ctx, taskKey, &task); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(task.Key(taskKey)) return http.StatusOK, nil }
// 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") } }