rin
Публичный Open-source lightweight git hosting.
releases.go · 150 строк · 4.6 KB
Raw
1 package handlers
2
3 import (
4 "fmt"
5 "html/template"
6 "strconv"
7 "strings"
8
9 "github.com/gofiber/fiber/v2"
10
11 "polar/internal/git"
12 "polar/internal/repo"
13 "polar/internal/web/middleware"
14 "polar/internal/web/views"
15 )
16
17 type ReleaseViewItem struct {
18 repo.Release
19 BodyHTML template.HTML
20 }
21
22 func (h *Handler) RepoReleasesPage(c *fiber.Ctx) error {
23 r, diskPath, err := h.loadAuthorizedRepo(c, false)
24 if err != nil {
25 return nil
26 }
27 if !r.EnableReleases {
28 return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
29 }
30
31 releases, _ := h.repoSvc.ListReleases(c.UserContext(), r.ID)
32 tags, _ := git.ListTags(c.UserContext(), diskPath)
33
34 var releaseItems []ReleaseViewItem
35 for _, rel := range releases {
36 rendered := views.RenderMarkdown([]byte(rel.Body))
37 releaseItems = append(releaseItems, ReleaseViewItem{
38 Release: rel,
39 BodyHTML: rendered,
40 })
41 }
42
43 viewer := middleware.CurrentUser(c)
44 data := h.baseData(c, h.tr(c, "releases.title")+" · "+r.OwnerUsername+"/"+r.Name)
45 data["Repo"] = r
46 data["Ref"] = r.DefaultBranch
47 data["ActiveTab"] = "releases"
48 data["CanWrite"] = h.repoSvc.CanWrite(c.UserContext(), r, viewer)
49 data["CloneURL"] = h.cloneURL(c, r.OwnerUsername, r.Name)
50 data["Releases"] = releaseItems
51 data["TagCount"] = len(tags)
52
53 return h.render(c, fiber.StatusOK, "releases", data)
54 }
55
56 func (h *Handler) RepoNewReleasePage(c *fiber.Ctx) error {
57 r, diskPath, err := h.loadAuthorizedRepo(c, true)
58 if err != nil {
59 return nil
60 }
61 if !r.EnableReleases {
62 return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
63 }
64
65 tags, _ := git.ListTags(c.UserContext(), diskPath)
66 branches, _ := git.ListBranches(c.UserContext(), diskPath)
67 selectedTag := strings.TrimSpace(c.Query("tag"))
68
69 viewer := middleware.CurrentUser(c)
70 data := h.baseData(c, h.tr(c, "releases.new")+" · "+r.OwnerUsername+"/"+r.Name)
71 data["Repo"] = r
72 data["Ref"] = r.DefaultBranch
73 data["ActiveTab"] = "releases"
74 data["CanWrite"] = h.repoSvc.CanWrite(c.UserContext(), r, viewer)
75 data["CloneURL"] = h.cloneURL(c, r.OwnerUsername, r.Name)
76 data["Tags"] = tags
77 data["Branches"] = branches
78 data["SelectedTag"] = selectedTag
79
80 return h.render(c, fiber.StatusOK, "release_new", data)
81 }
82
83 func (h *Handler) RepoNewReleaseSubmit(c *fiber.Ctx) error {
84 r, diskPath, err := h.loadAuthorizedRepo(c, true)
85 if err != nil {
86 return nil
87 }
88 if !r.EnableReleases {
89 return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
90 }
91
92 u := middleware.CurrentUser(c)
93 tagName := strings.TrimSpace(c.FormValue("tag_name"))
94 title := strings.TrimSpace(c.FormValue("title"))
95 body := strings.TrimSpace(c.FormValue("body"))
96 targetRef := strings.TrimSpace(c.FormValue("target_ref"))
97 if targetRef == "" {
98 targetRef = r.DefaultBranch
99 }
100 isPrerelease := c.FormValue("is_prerelease") == "true" || c.FormValue("is_prerelease") == "on" || c.FormValue("is_prerelease") == "1"
101
102 if tagName == "" {
103 h.setFlashT(c, "flash.release_tag_empty")
104 return c.Redirect(fmt.Sprintf("/%s/%s/releases/new", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
105 }
106
107 // Create git tag if it doesn't exist yet
108 existingTags, _ := git.ListTags(c.UserContext(), diskPath)
109 tagExists := false
110 for _, t := range existingTags {
111 if t == tagName {
112 tagExists = true
113 break
114 }
115 }
116 if !tagExists {
117 if err := git.CreateTag(c.UserContext(), diskPath, tagName, targetRef, title); err != nil {
118 h.setFlashT(c, "flash.release_tag_failed", err.Error())
119 return c.Redirect(fmt.Sprintf("/%s/%s/releases/new", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
120 }
121 }
122
123 if _, err := h.repoSvc.CreateRelease(c.UserContext(), r.ID, u.ID, tagName, title, body, false, isPrerelease); err != nil {
124 h.setFlashT(c, "flash.release_create_failed", err.Error())
125 return c.Redirect(fmt.Sprintf("/%s/%s/releases/new", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
126 }
127
128 h.repoSvc.TouchUpdatedAt(c.UserContext(), r.ID)
129 h.setFlashT(c, "flash.release_published", tagName)
130 return c.Redirect(fmt.Sprintf("/%s/%s/releases", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
131 }
132
133 func (h *Handler) RepoDeleteReleaseSubmit(c *fiber.Ctx) error {
134 r, _, err := h.loadAuthorizedRepo(c, true)
135 if err != nil {
136 return nil
137 }
138 if !r.EnableReleases {
139 return h.renderErrorT(c, fiber.StatusNotFound, "err.not_found", "err.releases_disabled")
140 }
141
142 relID, _ := strconv.ParseInt(c.Params("id"), 10, 64)
143 if err := h.repoSvc.DeleteRelease(c.UserContext(), relID); err != nil {
144 h.setFlashT(c, "flash.release_delete_failed", err.Error())
145 } else {
146 h.setFlashT(c, "flash.release_deleted")
147 }
148
149 return c.Redirect(fmt.Sprintf("/%s/%s/releases", r.OwnerUsername, r.Name), fiber.StatusSeeOther)
150 }
151