package controllers
import (
"encoding/json"
"net/http"
"strconv"
"theskyscape.com/repo/skydeck/models"
"theskyscape.com/repo/skykit"
)
func Gallery() (string, skykit.Handler) {
return "gallery", &GalleryController{}
}
type GalleryController struct {
skykit.Controller
}
func (c *GalleryController) Setup(app *skykit.Application) {
c.Controller.Setup(app)
// Public routes (no auth required)
http.Handle("GET /{$}", c.Serve("home.html", nil))
http.Handle("GET /deck/{id}", c.Serve("view.html", nil))
http.Handle("GET /deck/{id}/present", c.Serve("present.html", nil))
// API routes
http.HandleFunc("GET /api/gallery", c.Protect(c.listPublished, nil))
http.HandleFunc("GET /api/gallery/{id}", c.Protect(c.getPublished, nil))
http.HandleFunc("POST /api/gallery/{id}/fork", c.Protect(c.forkDeck, c.requireAuth))
}
func (c GalleryController) Handle(r *http.Request) skykit.Handler {
c.Request = r
return &c
}
// requireAuth middleware for fork
func (c *GalleryController) requireAuth(app *skykit.Application, w http.ResponseWriter, r *http.Request) bool {
user, err := app.Users.Authenticate(r)
if err != nil || user == nil {
jsonError(w, "unauthorized", http.StatusUnauthorized)
return false
}
return true
}
// Template methods
// FeaturedDecks returns recent published decks for the homepage
func (c *GalleryController) FeaturedDecks() []*models.Deck {
decks, _ := models.ListPublishedDecks(12, 0)
return decks
}
// ViewedDeck returns the deck being viewed
func (c *GalleryController) ViewedDeck() *models.Deck {
id := c.PathValue("id")
if id == "" {
return nil
}
deck, err := models.Decks.Get(id)
if err != nil {
return nil
}
if !deck.IsPublished {
return nil
}
// Increment view count
deck.IncrementViewCount()
return deck
}
// ViewedDeckContent returns the parsed content of the viewed deck
func (c *GalleryController) ViewedDeckContent() *models.DeckContent {
deck := c.ViewedDeck()
if deck == nil {
return nil
}
content, _ := deck.ParseContent()
return content
}
// IsOwner checks if the current user owns the viewed deck
func (c *GalleryController) IsOwner() bool {
user, err := c.Users.Authenticate(c.Request)
if err != nil || user == nil {
return false
}
deck := c.ViewedDeck()
if deck == nil {
return false
}
return deck.OwnerID == user.ID
}
// API handlers
func (c *GalleryController) listPublished(w http.ResponseWriter, r *http.Request) {
// Pagination
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
if page < 1 {
page = 1
}
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
if limit < 1 || limit > 50 {
limit = 20
}
offset := (page - 1) * limit
decks, err := models.ListPublishedDecks(limit, offset)
if err != nil {
jsonError(w, err.Error(), http.StatusInternalServerError)
return
}
jsonSuccess(w, decks)
}
func (c *GalleryController) getPublished(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
deck, err := models.Decks.Get(id)
if err != nil {
jsonError(w, "deck not found", http.StatusNotFound)
return
}
if !deck.IsPublished {
jsonError(w, "deck not found", http.StatusNotFound)
return
}
// Increment view count
deck.IncrementViewCount()
jsonSuccess(w, deck)
}
func (c *GalleryController) forkDeck(w http.ResponseWriter, r *http.Request) {
user, _ := c.Users.Authenticate(r)
id := r.PathValue("id")
// Get the original deck
deck, err := models.Decks.Get(id)
if err != nil {
jsonError(w, "deck not found", http.StatusNotFound)
return
}
if !deck.IsPublished {
jsonError(w, "deck not found", http.StatusNotFound)
return
}
// Fork it
fork, err := deck.Fork(user.ID, user.Name, user.Handle, user.Avatar)
if err != nil {
jsonError(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(fork)
}
Add rich text formatting and block styling to editor
Pitch decks to help promote Skyscape Apps