// ChallengeByKey loads a challenge by key. func ChallengeByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } key, err := datastore.DecodeKey(mux.Vars(r)["key"]) if err != nil { return http.StatusInternalServerError, err } var challenge model.Challenge err = datastore.Get(ctx, key, &challenge) if err != nil { return http.StatusInternalServerError, err } e := json.NewEncoder(w) if parent := p.UserKey.Parent(); parent == nil { // The current user is a coder so we must also create a result. e.Encode(challenge.Key(key)) } else { // TODO(pbochis): If a company representativemakes the request // we also include Tasks in the response. e.Encode(challenge.Key(key)) } return http.StatusOK, nil }
func GetCompanyByUser(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, 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 { return http.StatusUnauthorized, nil } // The account is associated with a company, so we return it. var company model.Company if err := datastore.Get(ctx, u.Company, &company); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(company.Key(u.Company)) return http.StatusOK, nil }
func Tasks(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 } // User is a coder if p.UserKey.Parent() == nil { return http.StatusUnauthorized, nil } var codeTasks model.CodeTasks codeTaskKeys, err := model.NewQueryForCodeTask(). GetAll(ctx, &codeTasks) if err != nil { return http.StatusInternalServerError, err } tasks := make([]model.KeyedTask, len(codeTasks)) for i := range codeTasks { tasks[i] = model.KeyedTask{ Task: &codeTasks[i].Task, Key: codeTaskKeys[i], } } json.NewEncoder(w).Encode(tasks) return http.StatusOK, nil }
func Tasks(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { 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, err } // User is a coder if u.Company == nil { return http.StatusUnauthorized, nil } switch r.Method { case "GET": return getAllTasks(ctx, w, r) case "POST": return createTask(ctx, w, r) default: return http.StatusMethodNotAllowed, nil } }
// AccessTokens will create new AccessTokens for the user. func AccessTokens(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 body model.AccessToken if err = json.NewDecoder(r.Body).Decode(&body); err != nil { return http.StatusBadRequest, err } value, err := p.IssueToken(ctx, &body) var result = struct { Value string Creation time.Time Expiry time.Time Description string }{ Value: value, Creation: body.Creation, Expiry: body.Expiry, Description: body.Description, } json.NewEncoder(w).Encode(result) return }
// PostSubmission creates a new submission. func PostSubmission(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 } resultKey, err := datastore.DecodeKey(mux.Vars(r)["resultKey"]) if !util.HasParent(p.UserKey, resultKey) { return http.StatusBadRequest, errors.New("cannot submit answer for other users") } taskKey, err := datastore.DecodeKey(mux.Vars(r)["taskKey"]) // Note: When more task kinds are added, see controllers.CreateFinalResult. switch taskKey.Kind() { case model.CodeTaskKind: return runner.HandleCodeSubmission(ctx, w, r, resultKey, taskKey) // TODO(victorbalan, flowlo): Use correct kind when possible. case "QuestionTask": return http.StatusInternalServerError, errors.New("question submissions are not yet implemented") default: return http.StatusBadRequest, errors.New("Unknown submission kind.") } }
func Tasks(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, 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 } // User is a coder if u.Company == nil { return http.StatusUnauthorized, nil } var tasks model.Tasks taskKeys, err := model.NewQueryForTask(). GetAll(ctx, &tasks) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(tasks.Key(taskKeys)) return http.StatusOK, nil }
func putCookie(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } token := &model.Token{ Description: "Login from " + r.RemoteAddr, } value, err := p.IssueToken(ctx, token) if err != nil { return http.StatusInternalServerError, err } http.SetCookie(w, &http.Cookie{ Name: "token", Value: value, Secure: !appengine.IsDevAppServer(), HttpOnly: true, Expires: token.Expiry, }) w.Write([]byte("OK")) 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) }
// GetChallengesForCompany queries all the challenges defined by a company. func GetChallengesForCompany(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } _, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } key, err := datastore.DecodeKey(mux.Vars(r)["key"]) if err != nil { return http.StatusInternalServerError, err } var challenges model.Challenges keys, err := model.NewQueryForChallenge(). Ancestor(key). GetAll(ctx, &challenges) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(challenges.Key(keys)) return http.StatusOK, nil }
func GetProfileForUser(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { _, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var userKey *datastore.Key if userKey, err = datastore.DecodeKey(mux.Vars(r)["key"]); err != nil { return http.StatusInternalServerError, err } var profiles []model.Profile keys, err := model.NewQueryForProfile(). Ancestor(userKey). Limit(1). GetAll(ctx, &profiles) if err != nil { return http.StatusInternalServerError, err } if len(keys) != 1 { return http.StatusNotFound, nil } json.NewEncoder(w).Encode(profiles[0].Key(keys[0])) return }
func GetTestResultsForSubmission(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } // TODO(victorbalan): Check if user is company or if user is parent of result // else return http.StatusUnauthorized _, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } submissionKey, err := datastore.DecodeKey(mux.Vars(r)["key"]) if err != nil { return http.StatusNotFound, err } keys, err := datastore.NewQuery(""). Ancestor(submissionKey). Filter("__key__ >", submissionKey). KeysOnly(). GetAll(ctx, nil) if err != nil { return http.StatusInternalServerError, err } if len(keys) == 0 { json.NewEncoder(w).Encode([]string{}) return http.StatusOK, nil } switch keys[0].Kind() { case model.JunitTestResultKind: var results model.JunitTestResults _, err = datastore.NewQuery(keys[0].Kind()). Ancestor(submissionKey). GetAll(ctx, &results) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(results) case model.DiffTestResultKind: var results model.DiffTestResults _, err = datastore.NewQuery(keys[0].Kind()). Ancestor(submissionKey). GetAll(ctx, &results) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(results) default: w.Write([]byte("[]")) } return http.StatusOK, nil }
// CreateChallenge will put a new entity of kind Challenge to Datastore. func CreateChallenge(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 u model.User if err := datastore.Get(ctx, p.User, &u); err != nil { return http.StatusInternalServerError, err } if u.Company == nil { return http.StatusUnauthorized, nil } var body = struct { model.Assignment Tasks []string }{} if err = json.NewDecoder(r.Body).Decode(&body); err != nil { return http.StatusBadRequest, err } keys := make([]*datastore.Key, len(body.Tasks)) for i := range body.Tasks { key, err := datastore.DecodeKey(body.Tasks[i]) if err != nil { return http.StatusInternalServerError, err } keys[i] = key } challenge := model.Challenge{ Assignment: body.Assignment, Resulter: int64(logic.Average), Tasks: keys, } key, err := challenge.PutWithParent(ctx, u.Company) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(challenge.Key(key)) return http.StatusOK, nil }
func User(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } switch r.Method { case "POST": return createUser(ctx, w, r) case "GET": return getUsers(p, ctx, w, r) default: return http.StatusMethodNotAllowed, nil } }
func GetChallengesForProfile(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } _, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var profileKey *datastore.Key if profileKey, err = datastore.DecodeKey(mux.Vars(r)["key"]); err != nil { return http.StatusInternalServerError, err } q := model.NewQueryForResult(). Ancestor(profileKey) if finished := r.URL.Query()["finished"]; len(finished) > 0 && finished[0] == "true" { q = q.Filter("Finished >", time.Time{}) } if order := r.URL.Query()["order"]; len(order) > 0 && order[0] != "" { q = q.Order(order[0]) } if limitQuery := r.URL.Query()["limit"]; len(limitQuery) > 0 { if limit, err := strconv.Atoi(limitQuery[0]); err != nil { return http.StatusInternalServerError, err } else { q = q.Limit(limit) } } var results model.Results if _, err = q.GetAll(ctx, &results); err != nil { return http.StatusInternalServerError, err } challengeKeys := make([]*datastore.Key, len(results)) for i, val := range results { challengeKeys[i] = val.Challenge } challenges := make(model.Challenges, len(challengeKeys)) if err = datastore.GetMulti(ctx, challengeKeys, challenges); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(challenges.Key(challengeKeys)) 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 }
// 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 WhoAmI(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var user model.User if err := datastore.Get(ctx, p.UserKey, &user); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(user.Key(p.UserKey)) return http.StatusOK, nil }
func GetUser(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { _, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var userKey *datastore.Key if userKey, err = datastore.DecodeKey(mux.Vars(r)["key"]); err != nil { return http.StatusInternalServerError, err } var user model.User if err = datastore.Get(ctx, userKey, &user); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(user.Key(userKey)) return }
func GetCompanyByUser(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if !util.CheckMethod(r, "GET") { return http.StatusMethodNotAllowed, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } key := p.UserKey.Parent() if key == nil { return http.StatusUnauthorized, nil } // The account is associated with a company, so we return it. var company model.Company if err := datastore.Get(ctx, key, &company); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(company.Key(key)) return http.StatusOK, nil }
func GetSubmissionByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } // TODO(victorbalan): Check if user is company or if user is parent of result // else return http.StatusUnauthorized _, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } submissionKey, err := datastore.DecodeKey(mux.Vars(r)["key"]) if err != nil { return http.StatusNotFound, err } var submission model.Submission if err = datastore.Get(ctx, submissionKey, &submission); err != nil { return } codeFilesURLs, err := util.ExposeMultiURL(ctx, submission.Code.Bucket, submission.Code.Name) if err != nil { return http.StatusInternalServerError, err } s := struct { Time time.Time CodeURLs []string Language string }{ Time: submission.Time, Language: submission.Language, CodeURLs: codeFilesURLs, } json.NewEncoder(w).Encode(s) return http.StatusOK, nil }
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 }
func GetSubmissionsForResult(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } // TODO(victorbalan): Check if user is company or if user is parent of result // else return http.StatusUnauthorized _, 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 } taskKey, err := datastore.DecodeKey(mux.Vars(r)["taskKey"]) if err != nil { return http.StatusNotFound, err } var submissions model.Submissions var keys []*datastore.Key keys, err = model.NewQueryForSubmission(). Ancestor(resultKey). Filter("Task =", taskKey). Order("Time"). GetAll(ctx, &submissions) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(submissions.Key(keys)) 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") } }
// 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 }
// 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 }
// 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 }
// 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 }
// Invitation handles the creation of a new invitation and sends an e-mail to // the user. func Invitation(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "POST" { return http.StatusMethodNotAllowed, nil } if err := initInvitationTemplate(); err != nil { return http.StatusInternalServerError, err } 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 } cKey := u.Company if cKey == nil { return http.StatusUnauthorized, nil } var company model.Company if err = datastore.Get(ctx, cKey, &company); err != nil { return http.StatusInternalServerError, err } var params = struct { Address, Challenge string }{} if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { return http.StatusBadRequest, err } address, err := mail.ParseAddress(params.Address) if err != nil { return http.StatusBadRequest, err } challengeKey, err := datastore.DecodeKey(params.Challenge) if err != nil { return http.StatusBadRequest, err } var challenge model.Challenge if err := datastore.Get(ctx, challengeKey, &challenge); err != nil { // TODO(flowlo): Actually look into err. If it is just something like // "not found", an internal server error is not appropriate. return http.StatusInternalServerError, err } // TODO(flowlo): Check whether the parent of the current user is the // parent of the challenge (if any), and check whether the challenge // even exists. var users model.Users keys, err := model.NewQueryForUser(). Filter("Address=", address.Address). Limit(1). GetAll(ctx, &users) if err != nil { return http.StatusInternalServerError, err } var key *datastore.Key var user model.User if len(keys) == 1 { key = keys[0] user = users[0] } else { user = model.User{Address: *address} key, err = user.Put(ctx, nil) if err != nil { return http.StatusInternalServerError, err } profile := model.Profile{} if _, err = profile.PutWithParent(ctx, key); err != nil { return http.StatusInternalServerError, err } } // NOTE: We are creating a new, orphaned Passenger here, because a // Passenger can only issue tokens for the encapsulated user. np := passenger.Passenger{ User: key, } now := time.Now() token := &model.Token{ Creation: now, Expiry: now.Add(time.Hour * 24 * 365), Description: "Initialization Token", } value, err := np.IssueToken(ctx, token) if err != nil { return http.StatusInternalServerError, err } query := base64.URLEncoding.EncodeToString([]byte(params.Challenge + ":" + value)) i := model.Invitation{ User: key, } // If we're on dev, generate a URL that will point at the dev instance, not // production. // TODO(flowlo): Move this magic constant somewhere to be configured, as port // 6060 is no official thing. prefix := "https://app.cod.uno" if appengine.IsDevAppServer() { prefix = "http://*****:*****@cod.uno>", To: []string{user.Address.String()}, Subject: "We challenge you!", Body: buf.String(), }); err != nil { return http.StatusInternalServerError, err } key, err = i.PutWithParent(ctx, cKey) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(i.Key(key)) return http.StatusOK, nil }