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) }