func (c *Controller) SetMood(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) name := pat.Param(ctx, "mood") var mood Mood r.ParseForm() err := decoder.Decode(&mood, r.PostForm) if err != nil { respond.InternalError(ctx, w, err) return } mood.Eyes = strings.Replace(mood.Eyes, "\x00", "", -1) mood.Tongue = strings.Replace(mood.Tongue, "\x00", "", -1) var uerr usererrors.InvalidParams if !(mood.Eyes == "" || utf8.RuneCountInString(mood.Eyes) == 2) { uerr = append(uerr, usererrors.InvalidParamsEntry{ Params: []string{"eyes"}, Message: "must be a string containing two characters", }) } if !(mood.Tongue == "" || utf8.RuneCountInString(mood.Tongue) == 2) { uerr = append(uerr, usererrors.InvalidParamsEntry{ Params: []string{"tongue"}, Message: "must be a string containing two characters", }) } if uerr != nil { respond.UserError(ctx, w, http.StatusBadRequest, uerr) return } mood.Name = name mood.UserDefined = true err = c.repo.SetMood(userID, &mood) if err == errBuiltinMood { respond.UserError(ctx, w, http.StatusBadRequest, usererrors.ActionNotAllowed{ Action: fmt.Sprintf("update built-in mood %s", name), }) return } else if err != nil { respond.InternalError(ctx, w, err) return } respond.Data(ctx, w, http.StatusOK, mood) }
func (c *Controller) ListMoods(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) lArgs, uerr := getListArgs(r) if uerr != nil { respond.UserError(ctx, w, http.StatusBadRequest, uerr) return } moods, hasMore, err := c.repo.ListMoods(userID, lArgs) if err == errCursorNotFound { respondCursorNotFound(ctx, w, lArgs) return } else if err != nil { respond.InternalError(ctx, w, err) return } respond.Data(ctx, w, http.StatusOK, listRes{ Cursor: moods[len(moods)-1].Name, Type: "mood", HasMore: hasMore, Data: moods, }) }
// WrapC wraps a handler and only passes requests with valid Bearer authorization. func (c *Controller) WrapC(inner goji.Handler) goji.Handler { return goji.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { auth := r.Header.Get("Authorization") if !strings.HasPrefix(auth, "Bearer ") { respond.UserError(ctx, w, http.StatusUnauthorized, BearerAuthRequired{}) return } auth = strings.TrimPrefix(auth, "Bearer ") if user := c.getUser(auth); user != nil { ctx = context.WithValue(ctx, ctxKey, user) reqlog.SetContext(ctx, "user_id", user.ID) inner.ServeHTTPC(ctx, w, r) } else { respond.UserError(ctx, w, http.StatusUnauthorized, usererrors.AuthInvalid{}) } }) }
func (c *Controller) DeleteMood(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) name := pat.Param(ctx, "mood") if err := c.repo.DeleteMood(userID, name); err == errBuiltinMood { respond.UserError(ctx, w, http.StatusBadRequest, usererrors.ActionNotAllowed{ Action: fmt.Sprintf("delete built-in mood %s", name), }) } else if err == errRecordNotFound { respond.NotFound(ctx, w, r) } else if conflict, ok := err.(conflictErr); ok { respond.UserError(ctx, w, http.StatusBadRequest, usererrors.ActionNotAllowed{ Action: fmt.Sprintf("delete a mood associated with %d conversation lines", len(conflict.IDs)), }) } else if err != nil { respond.InternalError(ctx, w, err) } else { w.WriteHeader(http.StatusNoContent) } }
func respondCursorNotFound(ctx context.Context, w http.ResponseWriter, args listArgs) { var cursorParam string if args.After == "" { cursorParam = "ending_before" } else { cursorParam = "starting_after" } respond.UserError(ctx, w, http.StatusBadRequest, usererrors.InvalidParams{{ Params: []string{cursorParam}, Message: "must refer to an existing object", }}) }
func (c *Controller) CreateConversation(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) heading := strings.Replace(r.PostFormValue("heading"), "\x00", "", -1) if cnt := utf8.RuneCountInString(heading); cnt > maxHeadingLength { respond.UserError(ctx, w, http.StatusBadRequest, usererrors.InvalidParams{{ Params: []string{"heading"}, Message: fmt.Sprintf("must be a string of less than %d characters", maxHeadingLength), }}) return } convo, err := c.repo.NewConversation(userID, heading) if err != nil { respond.InternalError(ctx, w, err) return } respond.Data(ctx, w, http.StatusOK, convo) }
// TODO: use gorilla schema here func (c *Controller) CreateLine(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) convoID := pat.Param(ctx, "conversation") var uerr usererrors.InvalidParams var think bool switch r.PostFormValue("think") { case "", "false": think = false case "true": think = true default: uerr = append(uerr, usererrors.InvalidParamsEntry{ Params: []string{"think"}, Message: "must be either 'true' or 'false'", }) } animal := r.PostFormValue("animal") if animal == "" { animal = "default" } if _, ok := c.cows[animal]; !ok { uerr = append(uerr, usererrors.InvalidParamsEntry{ Params: []string{"animal"}, Message: fmt.Sprintf("%q does not exist", animal), }) } text := strings.Replace(r.PostFormValue("text"), "\x00", "", -1) if cnt := utf8.RuneCountInString(text); cnt > maxTextLength { respond.UserError(ctx, w, http.StatusBadRequest, usererrors.InvalidParams{{ Params: []string{"text"}, Message: fmt.Sprintf("must be a string of less than %d characters", maxTextLength), }}) return } moodName := strings.Replace(r.PostFormValue("mood"), "\x00", "", -1) if moodName == "" { moodName = "default" } mood, err := c.repo.GetMood(userID, moodName) if err != nil { respond.InternalError(ctx, w, err) return } if mood == nil { uerr = append(uerr, usererrors.InvalidParamsEntry{ Params: []string{"mood"}, Message: fmt.Sprintf("%q does not exist", moodName), }) } if uerr != nil { respond.UserError(ctx, w, http.StatusBadRequest, uerr) return } line := Line{ Animal: animal, Think: think, MoodName: moodName, Text: text, mood: mood, } if err := c.repo.InsertLine(userID, convoID, &line); err == sql.ErrNoRows { // The underlying conversation does not exist respond.NotFound(ctx, w, r) } else if err != nil { respond.InternalError(ctx, w, err) return } line.Output, err = c.renderLine(&line) if err != nil { respond.InternalError(ctx, w, err) return } respond.Data(ctx, w, http.StatusOK, line) }