func AddTaskHandler(w http.ResponseWriter, r *http.Request, task AddTaskVars) { if !ctfeutil.UserHasEditRights(r) { skutil.ReportError(w, r, fmt.Errorf("Must have google or chromium account to add tasks"), "") return } if task.IsAdminTask() && !ctfeutil.UserHasAdminRights(r) { skutil.ReportError(w, r, fmt.Errorf("Must be admin to add admin tasks; contact rmistry@"), "") return } w.Header().Set("Content-Type", "application/json") if err := json.NewDecoder(r.Body).Decode(&task); err != nil { skutil.ReportError(w, r, err, fmt.Sprintf("Failed to add %T task", task)) return } defer skutil.Close(r.Body) task.GetAddTaskCommonVars().Username = login.LoggedInAs(r) task.GetAddTaskCommonVars().TsAdded = ctutil.GetCurrentTs() if len(task.GetAddTaskCommonVars().Username) > 255 { skutil.ReportError(w, r, fmt.Errorf("Username is too long, limit 255 bytes"), "") return } if _, err := AddTask(task); err != nil { skutil.ReportError(w, r, err, fmt.Sprintf("Failed to insert %T task", task)) return } }
// Returns true if the given task can be deleted by the logged-in user; otherwise false and an error // describing the problem. func canDeleteTask(task Task, r *http.Request) (bool, error) { if !ctfeutil.UserHasAdminRights(r) { username := login.LoggedInAs(r) taskUser := task.GetCommonCols().Username if taskUser != username { return false, fmt.Errorf("Task is owned by %s but you are logged in as %s", taskUser, username) } } if task.GetCommonCols().TsStarted.Valid && !task.GetCommonCols().TsCompleted.Valid { return false, fmt.Errorf("Cannot delete currently running tasks.") } return true, nil }
func DeleteTaskHandler(prototype Task, w http.ResponseWriter, r *http.Request) { if !ctfeutil.UserHasEditRights(r) { skutil.ReportError(w, r, fmt.Errorf("Must have google or chromium account to delete tasks"), "") return } w.Header().Set("Content-Type", "application/json") vars := struct{ Id int64 }{} if err := json.NewDecoder(r.Body).Decode(&vars); err != nil { skutil.ReportError(w, r, err, "Failed to parse delete request") return } defer skutil.Close(r.Body) requireUsernameMatch := !ctfeutil.UserHasAdminRights(r) username := login.LoggedInAs(r) // Put all conditions in delete request; only if the delete fails, do a select to determine the cause. deleteQuery := fmt.Sprintf("DELETE FROM %s WHERE id = ? AND (ts_started IS NULL OR ts_completed IS NOT NULL)", prototype.TableName()) binds := []interface{}{vars.Id} if requireUsernameMatch { deleteQuery += " AND username = ?" binds = append(binds, username) } result, err := db.DB.Exec(deleteQuery, binds...) if err != nil { skutil.ReportError(w, r, err, "Failed to delete") return } // Check result to ensure that the row was deleted. if rowsDeleted, _ := result.RowsAffected(); rowsDeleted == 1 { glog.Infof("%s task with ID %d deleted by %s", prototype.GetTaskName(), vars.Id, username) return } // The code below determines the reason that no rows were deleted. rowQuery := fmt.Sprintf("SELECT * FROM %s WHERE id = ?", prototype.TableName()) data, err := prototype.Select(rowQuery, vars.Id) if err != nil { skutil.ReportError(w, r, err, "Unable to validate request.") return } tasks := AsTaskSlice(data) if len(tasks) != 1 { // Row already deleted; return success. return } if ok, err := canDeleteTask(tasks[0], r); !ok { skutil.ReportError(w, r, err, "") } else { skutil.ReportError(w, r, fmt.Errorf("Failed to delete; reason unknown"), "") return } }
func UpdateTaskHandler(vars UpdateTaskVars, tableName string, w http.ResponseWriter, r *http.Request) { data, err := webhook.AuthenticateRequest(r) if err != nil { if data == nil { skutil.ReportError(w, r, err, "Failed to read update request") return } if !ctfeutil.UserHasAdminRights(r) { skutil.ReportError(w, r, err, "Failed authentication") return } } w.Header().Set("Content-Type", "application/json") if err := json.Unmarshal(data, &vars); err != nil { skutil.ReportError(w, r, err, fmt.Sprintf("Failed to parse %T update", vars)) return } defer skutil.Close(r.Body) if err := UpdateTask(vars, tableName); err != nil { skutil.ReportError(w, r, err, fmt.Sprintf("Failed to update %T task", vars)) return } }
func addTrybotTaskHandler(w http.ResponseWriter, r *http.Request) { data, err := webhook.AuthenticateRequest(r) if err != nil { if data == nil { skutil.ReportError(w, r, err, "Failed to read add request") return } if !ctfeutil.UserHasAdminRights(r) { skutil.ReportError(w, r, err, "Failed authentication") return } } trybotTask := TrybotTask{} if err := json.Unmarshal(data, &trybotTask); err != nil { skutil.ReportError(w, r, err, fmt.Sprintf("Failed to add %v trybot task", trybotTask)) return } task := &trybotTask.TaskVars // Add patch data to the task. detail, err := getCLDetail(trybotTask.Issue) if err != nil { skutil.ReportError(w, r, err, "") return } patchsetID, err := strconv.Atoi(trybotTask.PatchsetID) if err != nil { skutil.ReportError(w, r, err, "") return } patch, err := getCLPatch(detail, patchsetID) if err != nil { skutil.ReportError(w, r, err, "") return } clData, err := gatherCLData(detail, patch) if err != nil { skutil.ReportError(w, r, err, "") return } task.Description = fmt.Sprintf("Trybot run for http://codereview.chromium.org/%s#ps%s", clData["cl"], clData["patchset"]) if val, ok := clData["chromium_patch"]; ok { task.ChromiumPatch = val } if val, ok := clData["skia_patch"]; ok { task.SkiaPatch = val } task.GetAddTaskCommonVars().TsAdded = ctutil.GetCurrentTs() taskID, err := task_common.AddTask(task) if err != nil { skutil.ReportError(w, r, err, fmt.Sprintf("Failed to insert %T task", task)) return } w.Header().Set("Content-Type", "application/json") jsonResponse := map[string]interface{}{ "taskID": taskID, } if err := json.NewEncoder(w).Encode(jsonResponse); err != nil { skutil.ReportError(w, r, err, "Failed to encode JSON") return } }