コード例 #1
0
ファイル: say.go プロジェクト: antifuchs/saypi
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 {
		panic(err) // I believe this is unreachable
	}

	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.Error(ctx, w, http.StatusBadRequest, uerr)
		return
	}

	mood.Name = name
	mood.UserDefined = true

	err = c.repo.SetMood(userID, &mood)
	if err == errBuiltinMood {
		respond.Error(ctx, w, http.StatusBadRequest, usererrors.ActionNotAllowed{
			Action: fmt.Sprintf("update built-in mood %s", name),
		})
		return
	} else if err != nil {
		panic(err)
	}

	respond.Data(ctx, w, http.StatusOK, mood)
}
コード例 #2
0
ファイル: auth.go プロジェクト: antifuchs/saypi
// 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.Error(ctx, w, http.StatusUnauthorized, usererrors.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.Error(ctx, w, http.StatusUnauthorized, usererrors.AuthInvalid{})
		}
	})
}
コード例 #3
0
ファイル: say.go プロジェクト: antifuchs/saypi
func respondCursorNotFound(ctx context.Context, w http.ResponseWriter, args listArgs) {
	var cursorParam string
	if args.After == "" {
		cursorParam = "ending_before"
	} else {
		cursorParam = "starting_after"
	}

	respond.Error(ctx, w, http.StatusBadRequest, usererrors.InvalidParams{{
		Params:  []string{cursorParam},
		Message: "must refer to an existing object",
	}})
}
コード例 #4
0
ファイル: say.go プロジェクト: antifuchs/saypi
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.Error(ctx, w, http.StatusBadRequest, usererrors.ActionNotAllowed{
			Action: fmt.Sprintf("delete built-in mood %s", name),
		})
		return
	} else if err != nil {
		panic(err)
	}

	w.WriteHeader(http.StatusNoContent)
}
コード例 #5
0
ファイル: say.go プロジェクト: antifuchs/saypi
func (c *Controller) CreateConversation(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	userID := mustUserID(ctx)

	heading := r.PostFormValue("heading")
	if cnt := utf8.RuneCountInString(heading); cnt > maxHeadingLength {
		respond.Error(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 {
		panic(err)
	}

	respond.Data(ctx, w, http.StatusOK, convo)
}
コード例 #6
0
ファイル: say.go プロジェクト: antifuchs/saypi
func (c *Controller) ListConversations(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	userID := mustUserID(ctx)
	lArgs, uerr := getListArgs(r)
	if uerr != nil {
		respond.Error(ctx, w, http.StatusBadRequest, uerr)
		return
	}

	convos, hasMore, err := c.repo.ListConversations(userID, lArgs)
	if err == errCursorNotFound {
		respondCursorNotFound(ctx, w, lArgs)
		return
	} else if err != nil {
		panic(err)
	}

	respond.Data(ctx, w, http.StatusOK, listRes{
		Cursor:  convos[len(convos)-1].ID,
		Type:    "conversation",
		HasMore: hasMore,
		Data:    convos,
	})
}
コード例 #7
0
ファイル: say.go プロジェクト: antifuchs/saypi
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),
		})
	}

	// Sanitize null bytes for the database
	moodName := strings.Replace(r.PostFormValue("mood"), "\x00", "", -1)
	text := strings.Replace(r.PostFormValue("text"), "\x00", "", -1)

	if moodName == "" {
		moodName = "default"
	}

	mood, err := c.repo.GetMood(userID, moodName)
	if err != nil {
		panic(err)
	}
	if mood == nil {
		uerr = append(uerr, usererrors.InvalidParamsEntry{
			Params:  []string{"mood"},
			Message: fmt.Sprintf("%q does not exist", moodName),
		})
	}

	if uerr != nil {
		respond.Error(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 {
		panic(err)
	}

	line.Output, err = c.renderLine(&line)
	if err != nil {
		panic(err)
	}

	respond.Data(ctx, w, http.StatusOK, line)
}