package api import ( "errors" "io" "net/http" "github.com/gin-gonic/gin" ) // getPublicGarden serves the read-only /full payload for a garden addressed by a // public share token. It sits OUTSIDE requireAuth — the token itself is the // capability — so a logged-out visitor can open a shared link without ever being // bounced to /login or the OIDC flow. An unknown or disabled token is a 404. func (h *handlers) getPublicGarden(c *gin.Context) { full, err := h.svc.PublicGarden(c.Request.Context(), c.Param("token")) if err != nil { writeServiceError(c, err) return } // The token is a capability in the URL: keep the response out of any shared // proxy cache, and always serve the live garden (the owner may have edited or // revoked it since the last view). c.Header("Cache-Control", "no-store") c.JSON(http.StatusOK, full) } // getShareLink reports the garden's public-link state (and, to the owner, the // current token) so the share dialog can show/copy the URL. Owner only. func (h *handlers) getShareLink(c *gin.Context) { id, ok := parseIDParam(c, "id") if !ok { return } link, err := h.svc.GetPublicShareLink(c.Request.Context(), mustActor(c).ID, id) if err != nil { writeServiceError(c, err) return } c.JSON(http.StatusOK, link) } // createShareLink enables the public link (idempotent) or, with {"rotate":true}, // issues a fresh token that invalidates the previous URL. Owner only. The body is // optional — a missing/malformed one just means enable-without-rotate. func (h *handlers) createShareLink(c *gin.Context) { id, ok := parseIDParam(c, "id") if !ok { return } var req struct { Rotate bool `json:"rotate"` } // The body is optional (an empty body means enable-without-rotate), but a // present-yet-malformed body is a client error, not a silent enable. if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) { writeAPIError(c, http.StatusBadRequest, "INVALID_INPUT", "invalid request body") return } link, err := h.svc.EnablePublicShareLink(c.Request.Context(), mustActor(c).ID, id, req.Rotate) if err != nil { writeServiceError(c, err) return } c.JSON(http.StatusOK, link) } // deleteShareLink disables the public link. Owner only; idempotent. func (h *handlers) deleteShareLink(c *gin.Context) { id, ok := parseIDParam(c, "id") if !ok { return } if err := h.svc.DisablePublicShareLink(c.Request.Context(), mustActor(c).ID, id); err != nil { writeServiceError(c, err) return } c.JSON(http.StatusOK, gin.H{"enabled": false}) }