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, }) }
func (c *Controller) CreateUser(ctx context.Context, w http.ResponseWriter, r *http.Request) { id := make([]byte, idLen) if _, err := rand.Read(id); err != nil { respond.InternalError(ctx, w, err) return } mac := hmac.New(sha256.New, c.secret) if _, err := mac.Write(id); err != nil { respond.InternalError(ctx, w, err) return } msg := mac.Sum(id) res := struct { ID string `json:"id"` }{base64.URLEncoding.EncodeToString(msg)} respond.Data(ctx, w, http.StatusOK, res) }
func (c *Controller) DeleteConversation(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) convoID := pat.Param(ctx, "conversation") if err := c.repo.DeleteConversation(userID, convoID); err == errRecordNotFound { respond.NotFound(ctx, w, r) } else if err != nil { respond.InternalError(ctx, w, err) return } w.WriteHeader(http.StatusNoContent) }
func (c *Controller) GetUser(ctx context.Context, w http.ResponseWriter, r *http.Request) { id := pat.Param(ctx, "id") if id == "" { respond.InternalError(ctx, w, errors.New("GetUser called without an `id` URL Var")) return } if c.getUser(id) != nil { w.WriteHeader(204) } else { respond.NotFound(ctx, w, r) } }
func (c *Controller) GetLine(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) convoID := pat.Param(ctx, "conversation") lineID := pat.Param(ctx, "line") line, err := c.repo.GetLine(userID, convoID, lineID) if err != nil { respond.InternalError(ctx, w, err) return } if line == nil { respond.NotFound(ctx, w, r) return } line.Output, err = c.renderLine(line) if err != nil { respond.InternalError(ctx, w, err) return } respond.Data(ctx, w, http.StatusOK, line) }
func (c *Controller) GetConversation(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) convoID := pat.Param(ctx, "conversation") convo, err := c.repo.GetConversation(userID, convoID) if err != nil { respond.InternalError(ctx, w, err) return } if convo == nil { respond.NotFound(ctx, w, r) return } for i, Line := range convo.Lines { convo.Lines[i].Output, err = c.renderLine(&Line) if err != nil { respond.InternalError(ctx, w, err) return } } respond.Data(ctx, w, http.StatusOK, convo) }
func (c *Controller) GetMood(ctx context.Context, w http.ResponseWriter, r *http.Request) { userID := mustUserID(ctx) name := pat.Param(ctx, "mood") res, err := c.repo.GetMood(userID, name) if err != nil { respond.InternalError(ctx, w, err) return } if res == nil { respond.NotFound(ctx, w, r) return } respond.Data(ctx, w, http.StatusOK, res) }
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) }
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) } }
// 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) }