package handlers
import (
"fmt"
"html/template"
"strconv"
"strings"
"github.com/gofiber/fiber/v2"
"polar/internal/git"
"polar/internal/repo"
"polar/internal/web/middleware"
"polar/internal/web/views"
)
type ReleaseViewItem struct {
repo.Release
BodyHTML template.HTML
}
func (h *Handler) RepoReleasesPage(c *fiber.Ctx) error {
r, diskPath, err := h.loadAuthorizedRepo(c, false)
if err != nil {
return nil
}
if !r.EnableReleases {
return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
}
releases, _ := h.repoSvc.ListReleases(c.UserContext(), r.ID)
tags, _ := git.ListTags(c.UserContext(), diskPath)
var releaseItems []ReleaseViewItem
for _, rel := range releases {
rendered := views.RenderMarkdown([]byte(rel.Body))
releaseItems = append(releaseItems, ReleaseViewItem{
Release: rel,
BodyHTML: rendered,
})
}
viewer := middleware.CurrentUser(c)
data := h.baseData(c, h.tr(c, "releases.title")+" · "+r.OwnerUsername+"/"+r.Name)
data["Repo"] = r
data["Ref"] = r.DefaultBranch
data["ActiveTab"] = "releases"
data["CanWrite"] = h.repoSvc.CanWrite(c.UserContext(), r, viewer)
data["CloneURL"] = h.cloneURL(c, r.OwnerUsername, r.Name)
data["Releases"] = releaseItems
data["TagCount"] = len(tags)
return h.render(c, fiber.StatusOK, "releases", data)
}
func (h *Handler) RepoNewReleasePage(c *fiber.Ctx) error {
r, diskPath, err := h.loadAuthorizedRepo(c, true)
if err != nil {
return nil
}
if !r.EnableReleases {
return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
}
tags, _ := git.ListTags(c.UserContext(), diskPath)
branches, _ := git.ListBranches(c.UserContext(), diskPath)
selectedTag := strings.TrimSpace(c.Query("tag"))
viewer := middleware.CurrentUser(c)
data := h.baseData(c, h.tr(c, "releases.new")+" · "+r.OwnerUsername+"/"+r.Name)
data["Repo"] = r
data["Ref"] = r.DefaultBranch
data["ActiveTab"] = "releases"
data["CanWrite"] = h.repoSvc.CanWrite(c.UserContext(), r, viewer)
data["CloneURL"] = h.cloneURL(c, r.OwnerUsername, r.Name)
data["Tags"] = tags
data["Branches"] = branches
data["SelectedTag"] = selectedTag
return h.render(c, fiber.StatusOK, "release_new", data)
}
func (h *Handler) RepoNewReleaseSubmit(c *fiber.Ctx) error {
r, diskPath, err := h.loadAuthorizedRepo(c, true)
if err != nil {
return nil
}
if !r.EnableReleases {
return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
}
u := middleware.CurrentUser(c)
tagName := strings.TrimSpace(c.FormValue("tag_name"))
title := strings.TrimSpace(c.FormValue("title"))
body := strings.TrimSpace(c.FormValue("body"))
targetRef := strings.TrimSpace(c.FormValue("target_ref"))
if targetRef == "" {
targetRef = r.DefaultBranch
}
isPrerelease := c.FormValue("is_prerelease") == "true" || c.FormValue("is_prerelease") == "on" || c.FormValue("is_prerelease") == "1"
if tagName == "" {
h.setFlashT(c, "flash.release_tag_empty")
return c.Redirect(fmt.Sprintf("/%s/%s/releases/new", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
}
// Create git tag if it doesn't exist yet
existingTags, _ := git.ListTags(c.UserContext(), diskPath)
tagExists := false
for _, t := range existingTags {
if t == tagName {
tagExists = true
break
}
}
if !tagExists {
if err := git.CreateTag(c.UserContext(), diskPath, tagName, targetRef, title); err != nil {
h.setFlashT(c, "flash.release_tag_failed", err.Error())
return c.Redirect(fmt.Sprintf("/%s/%s/releases/new", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
}
}
if _, err := h.repoSvc.CreateRelease(c.UserContext(), r.ID, u.ID, tagName, title, body, false, isPrerelease); err != nil {
h.setFlashT(c, "flash.release_create_failed", err.Error())
return c.Redirect(fmt.Sprintf("/%s/%s/releases/new", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
}
h.repoSvc.TouchUpdatedAt(c.UserContext(), r.ID)
h.setFlashT(c, "flash.release_published", tagName)
return c.Redirect(fmt.Sprintf("/%s/%s/releases", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
}
func (h *Handler) RepoDeleteReleaseSubmit(c *fiber.Ctx) error {
r, _, err := h.loadAuthorizedRepo(c, true)
if err != nil {
return nil
}
if !r.EnableReleases {
return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
}
relID, _ := strconv.ParseInt(c.Params("id"), 10, 64)
if err := h.repoSvc.DeleteRelease(c.UserContext(), relID); err != nil {
h.setFlashT(c, "flash.release_delete_failed", err.Error())
} else {
h.setFlashT(c, "flash.release_deleted")
}
return c.Redirect(fmt.Sprintf("/%s/%s/releases", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
}