package stacks import ( "database/sql" "fmt" "net/http" "os" . "screenmark/screenmark/.gen/haystack/haystack/model" "screenmark/screenmark/middleware" "screenmark/screenmark/models" "strings" "github.com/charmbracelet/log" "github.com/go-chi/chi/v5" ) type StackHandler struct { logger *log.Logger stackModel models.ListModel } func (h *StackHandler) getAllStacks(w http.ResponseWriter, r *http.Request) { ctx := r.Context() userID, err := middleware.GetUserID(ctx, h.logger, w) if err != nil { return } lists, err := h.stackModel.List(ctx, userID) if err != nil { h.logger.Warn("could not get stacks", "err", err) w.WriteHeader(http.StatusBadRequest) return } middleware.WriteJsonOrError(h.logger, lists, w) } func (h *StackHandler) getStackItems(w http.ResponseWriter, r *http.Request) { ctx := r.Context() _, err := middleware.GetUserID(ctx, h.logger, w) if err != nil { return } listID, err := middleware.GetPathParamID(h.logger, "listID", w, r) if err != nil { return } // TODO: must check for permission here. lists, err := h.stackModel.ListItems(ctx, listID) if err != nil { h.logger.Warn("could not get list items", "err", err) w.WriteHeader(http.StatusBadRequest) return } middleware.WriteJsonOrError(h.logger, lists, w) } type EditStack struct { Hello string `json:"hello"` } func (h *StackHandler) editStack(req EditStack, w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } func (h *StackHandler) deleteStack(w http.ResponseWriter, r *http.Request) { ctx := r.Context() userID, err := middleware.GetUserID(ctx, h.logger, w) if err != nil { return } listID, err := middleware.GetPathParamID(h.logger, "listID", w, r) if err != nil { return } err = h.stackModel.Delete(ctx, listID, userID) if err != nil { h.logger.Warn("could not delete stack", "err", err) w.WriteHeader(http.StatusBadRequest) return } w.WriteHeader(http.StatusOK) } type CreateStackBody struct { Title string `json:"title"` // We want a regular string because AI will take care of creating these for us. Fields string `json:"fields"` } func (h *StackHandler) createStack(body CreateStackBody, w http.ResponseWriter, r *http.Request) { ctx := r.Context() userID, err := middleware.GetUserID(ctx, h.logger, w) if err != nil { return } // Convert fields string to basic schema items // For now, create a simple schema item for each field var schemaItems []SchemaItems if body.Fields != "" { fields := strings.Split(body.Fields, ",") for i, field := range fields { field = strings.TrimSpace(field) if field != "" { schemaItems = append(schemaItems, SchemaItems{ Item: field, Value: "", Description: fmt.Sprintf("Field %d: %s", i+1, field), }) } } } // Use empty description for now since the API doesn't provide one _, err = h.stackModel.Save(ctx, userID, body.Title, "", schemaItems) if err != nil { h.logger.Warn("could not save stack", "err", err) w.WriteHeader(http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (h *StackHandler) CreateRoutes(r chi.Router) { h.logger.Info("Mounting stack router") r.Group(func(r chi.Router) { r.Use(middleware.ProtectedRoute) r.Use(middleware.SetJson) r.Get("/", h.getAllStacks) r.Get("/{listID}", h.getStackItems) r.Post("/", middleware.WithValidatedPost(h.createStack)) r.Patch("/{listID}", middleware.WithValidatedPost(h.editStack)) r.Delete("/{listID}", h.deleteStack) }) } func CreateStackHandler(db *sql.DB) StackHandler { stackModel := models.NewListModel(db) logger := log.New(os.Stdout).WithPrefix("Stacks") return StackHandler{ logger, stackModel, } }