Goit

Simple and lightweight Git web server
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

Goit/src/repo/edit.go (214 lines, 6.6 KiB) -rw-r--r-- file download

c2c5250 Jakob Wakeling 2023-12-12 09:13:37
0
// Copyright (C) 2023, Jakob Wakeling
c2c5250 Jakob Wakeling 2023-12-12 09:13:37
1
// All rights reserved.
c2c5250 Jakob Wakeling 2023-12-12 09:13:37
2
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
3
package repo
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
4
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
5
import (
edde491 Jakob Wakeling 2023-09-07 21:47:49
6
	"errors"
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
7
	"fmt"
b804701 Jakob Wakeling 2023-11-27 23:52:28
8
	"html/template"
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
9
	"log"
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
10
	"net/http"
08dff9a Jakob Wakeling 2023-11-07 21:03:04
11
	"path/filepath"
23b01c4 Jakob Wakeling 2023-08-26 14:44:52
12
	"slices"
f9225e6 Jakob Wakeling 2023-12-18 23:58:22
13
	"strings"
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
14
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
15
	"github.com/Jamozed/Goit/src/cron"
945fd71 Jakob Wakeling 2023-11-05 15:39:31
16
	"github.com/Jamozed/Goit/src/goit"
28a8f13 Jakob Wakeling 2023-12-25 19:52:40
17
	"github.com/Jamozed/Goit/src/util"
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
18
	"github.com/go-chi/chi/v5"
edde491 Jakob Wakeling 2023-09-07 21:47:49
19
	"github.com/go-git/go-git/v5"
edde491 Jakob Wakeling 2023-09-07 21:47:49
20
	"github.com/go-git/go-git/v5/plumbing"
b804701 Jakob Wakeling 2023-11-27 23:52:28
21
	"github.com/gorilla/csrf"
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
22
)
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
23
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
24
func HandleEdit(w http.ResponseWriter, r *http.Request) {
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
25
	auth, user, err := goit.Auth(w, r, true)
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
26
	if err != nil {
f9225e6 Jakob Wakeling 2023-12-18 23:58:22
27
		log.Println("[/repo/edit]", err.Error())
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
28
		goit.HttpError(w, http.StatusInternalServerError)
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
29
		return
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
30
	}
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
31
f9225e6 Jakob Wakeling 2023-12-18 23:58:22
32
	if !auth {
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
33
		goit.HttpError(w, http.StatusNotFound)
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
34
		return
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
35
	}
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
36
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
37
	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
38
	if err != nil {
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
39
		log.Println("[/repo/edit]", err.Error())
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
40
		goit.HttpError(w, http.StatusInternalServerError)
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
41
		return
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
42
	} else if repo == nil || (!auth || repo.OwnerId != user.Id) {
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
43
		goit.HttpError(w, http.StatusNotFound)
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
44
		return
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
45
	}
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
46
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
47
	owner, err := goit.GetUser(repo.OwnerId)
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
48
	if err != nil {
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
49
		log.Println("[/repo/edit]", err.Error())
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
50
		goit.HttpError(w, http.StatusInternalServerError)
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
51
		return
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
52
	} else if owner == nil {
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
53
		log.Println("[/repo/edit]", repo.Id, "is owned by a nonexistent user")
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
54
		/* TODO have admin adopt the orphaned repository */
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
55
		owner = &goit.User{}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
56
	}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
57
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
58
	data := struct {
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
59
		HeaderFields
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
60
		Title string
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
61
988a708 Jakob Wakeling 2023-10-23 23:05:22
62
		Edit struct {
778d467 Jakob Wakeling 2024-01-17 18:29:55
63
			Id, Owner, Name, Description        string
778d467 Jakob Wakeling 2024-01-17 18:29:55
64
			DefaultBranch, Upstream, Visibility string
778d467 Jakob Wakeling 2024-01-17 18:29:55
65
			IsMirror                            bool
778d467 Jakob Wakeling 2024-01-17 18:29:55
66
			Message                             string
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
67
		}
988a708 Jakob Wakeling 2023-10-23 23:05:22
68
988a708 Jakob Wakeling 2023-10-23 23:05:22
69
		Transfer struct{ Owner, Message string }
988a708 Jakob Wakeling 2023-10-23 23:05:22
70
		Delete   struct{ Message string }
b804701 Jakob Wakeling 2023-11-27 23:52:28
71
b804701 Jakob Wakeling 2023-11-27 23:52:28
72
		CsrfField template.HTML
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
73
	}{
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
74
		Title:        "Repository - Edit",
2e13a8c Jakob Wakeling 2023-12-23 19:40:09
75
		HeaderFields: GetHeaderFields(auth, user, repo, r.Host),
b804701 Jakob Wakeling 2023-11-27 23:52:28
76
b804701 Jakob Wakeling 2023-11-27 23:52:28
77
		CsrfField: csrf.TemplateField(r),
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
78
	}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
79
988a708 Jakob Wakeling 2023-10-23 23:05:22
80
	data.Edit.Id = fmt.Sprint(repo.Id)
988a708 Jakob Wakeling 2023-10-23 23:05:22
81
	data.Edit.Owner = owner.FullName + " (" + owner.Name + ")[" + fmt.Sprint(owner.Id) + "]"
988a708 Jakob Wakeling 2023-10-23 23:05:22
82
	data.Edit.Name = repo.Name
988a708 Jakob Wakeling 2023-10-23 23:05:22
83
	data.Edit.Description = repo.Description
28a8f13 Jakob Wakeling 2023-12-25 19:52:40
84
	data.Edit.DefaultBranch = repo.DefaultBranch
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
85
	data.Edit.Upstream = repo.Upstream
778d467 Jakob Wakeling 2024-01-17 18:29:55
86
	data.Edit.Visibility = repo.Visibility.String()
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
87
	data.Edit.IsMirror = repo.IsMirror
edde491 Jakob Wakeling 2023-09-07 21:47:49
88
08dff9a Jakob Wakeling 2023-11-07 21:03:04
89
	gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true))
edde491 Jakob Wakeling 2023-09-07 21:47:49
90
	if err != nil {
b227a68 Jakob Wakeling 2023-10-05 17:51:04
91
		log.Println("[/repo/edit]", err.Error())
edde491 Jakob Wakeling 2023-09-07 21:47:49
92
		goit.HttpError(w, http.StatusInternalServerError)
edde491 Jakob Wakeling 2023-09-07 21:47:49
93
		return
edde491 Jakob Wakeling 2023-09-07 21:47:49
94
	}
edde491 Jakob Wakeling 2023-09-07 21:47:49
95
edde491 Jakob Wakeling 2023-09-07 21:47:49
96
	ref, err := gr.Head()
b227a68 Jakob Wakeling 2023-10-05 17:51:04
97
	if err != nil && !errors.Is(err, plumbing.ErrReferenceNotFound) {
b227a68 Jakob Wakeling 2023-10-05 17:51:04
98
		log.Println("[/repo/edit]", err.Error())
edde491 Jakob Wakeling 2023-09-07 21:47:49
99
		goit.HttpError(w, http.StatusInternalServerError)
edde491 Jakob Wakeling 2023-09-07 21:47:49
100
		return
edde491 Jakob Wakeling 2023-09-07 21:47:49
101
	}
edde491 Jakob Wakeling 2023-09-07 21:47:49
102
b227a68 Jakob Wakeling 2023-10-05 17:51:04
103
	if ref != nil {
b4b291e Jakob Wakeling 2023-12-23 17:05:01
104
		if readme, _ := findPattern(gr, ref, readmePattern); readme != "" {
08dff9a Jakob Wakeling 2023-11-07 21:03:04
105
			data.Readme = filepath.Join("/", repo.Name, "file", readme)
b227a68 Jakob Wakeling 2023-10-05 17:51:04
106
		}
b4b291e Jakob Wakeling 2023-12-23 17:05:01
107
		if licence, _ := findPattern(gr, ref, licencePattern); licence != "" {
08dff9a Jakob Wakeling 2023-11-07 21:03:04
108
			data.Licence = filepath.Join("/", repo.Name, "file", licence)
b227a68 Jakob Wakeling 2023-10-05 17:51:04
109
		}
edde491 Jakob Wakeling 2023-09-07 21:47:49
110
	}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
111
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
112
	if r.Method == http.MethodPost {
988a708 Jakob Wakeling 2023-10-23 23:05:22
113
		switch r.FormValue("action") {
988a708 Jakob Wakeling 2023-10-23 23:05:22
114
		case "edit":
988a708 Jakob Wakeling 2023-10-23 23:05:22
115
			data.Edit.Name = r.FormValue("reponame")
988a708 Jakob Wakeling 2023-10-23 23:05:22
116
			data.Edit.Description = r.FormValue("description")
28a8f13 Jakob Wakeling 2023-12-25 19:52:40
117
			data.Edit.DefaultBranch = util.If(r.FormValue("branch") == "", "master", r.FormValue("branch"))
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
118
			data.Edit.Upstream = r.FormValue("upstream")
778d467 Jakob Wakeling 2024-01-17 18:29:55
119
			data.Edit.Visibility = r.FormValue("visibility")
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
120
			data.Edit.IsMirror = r.FormValue("mirror") == "mirror"
988a708 Jakob Wakeling 2023-10-23 23:05:22
121
988a708 Jakob Wakeling 2023-10-23 23:05:22
122
			if data.Edit.Name == "" {
988a708 Jakob Wakeling 2023-10-23 23:05:22
123
				data.Edit.Message = "Name cannot be empty"
efb68c3 Jakob Wakeling 2023-12-06 20:37:06
124
			} else if slices.Contains(goit.Reserved, data.Edit.Name) || !goit.IsLegal(data.Name) {
efb68c3 Jakob Wakeling 2023-12-06 20:37:06
125
				data.Edit.Message = "Name \"" + data.Edit.Name + "\" is illegal"
988a708 Jakob Wakeling 2023-10-23 23:05:22
126
			} else if exists, err := goit.RepoExists(data.Edit.Name); err != nil {
988a708 Jakob Wakeling 2023-10-23 23:05:22
127
				log.Println("[/repo/edit]", err.Error())
988a708 Jakob Wakeling 2023-10-23 23:05:22
128
				goit.HttpError(w, http.StatusInternalServerError)
988a708 Jakob Wakeling 2023-10-23 23:05:22
129
				return
f9225e6 Jakob Wakeling 2023-12-18 23:58:22
130
			} else if exists && !strings.EqualFold(data.Edit.Name, repo.Name) {
988a708 Jakob Wakeling 2023-10-23 23:05:22
131
				data.Edit.Message = "Name \"" + data.Edit.Name + "\" is taken"
463cf58 Jakob Wakeling 2023-11-22 23:25:37
132
			} else if len(data.Edit.Description) > 256 {
463cf58 Jakob Wakeling 2023-11-22 23:25:37
133
				data.Edit.Message = "Description cannot exceed 256 characters"
778d467 Jakob Wakeling 2024-01-17 18:29:55
134
			} else if visibility := goit.VisibilityFromString(data.Edit.Visibility); visibility == -1 {
778d467 Jakob Wakeling 2024-01-17 18:29:55
135
				data.Edit.Message = "Visibility \"" + data.Edit.Visibility + "\" is invalid"
988a708 Jakob Wakeling 2023-10-23 23:05:22
136
			} else if err := goit.UpdateRepo(repo.Id, goit.Repo{
28a8f13 Jakob Wakeling 2023-12-25 19:52:40
137
				Name: data.Edit.Name, Description: data.Edit.Description, DefaultBranch: data.Edit.DefaultBranch,
778d467 Jakob Wakeling 2024-01-17 18:29:55
138
				Upstream: data.Edit.Upstream, Visibility: visibility, IsMirror: data.Edit.IsMirror,
988a708 Jakob Wakeling 2023-10-23 23:05:22
139
			}); err != nil {
988a708 Jakob Wakeling 2023-10-23 23:05:22
140
				log.Println("[/repo/edit]", err.Error())
988a708 Jakob Wakeling 2023-10-23 23:05:22
141
				goit.HttpError(w, http.StatusInternalServerError)
988a708 Jakob Wakeling 2023-10-23 23:05:22
142
				return
988a708 Jakob Wakeling 2023-10-23 23:05:22
143
			} else {
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
144
				if (data.Edit.Upstream == "" && repo.Upstream != "") || !data.Edit.IsMirror {
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
145
					goit.Cron.RemoveFor(repo.Id)
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
146
					goit.Cron.Update()
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
147
				} else if data.Edit.Upstream != "" && data.Edit.IsMirror &&
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
148
					(data.Edit.Upstream != repo.Upstream || !repo.IsMirror) {
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
149
					goit.Cron.RemoveFor(repo.Id)
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
150
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
151
					goit.Cron.Add(repo.Id, cron.Immediate, func() {
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
152
						if err := goit.Pull(repo.Id); err != nil {
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
153
							log.Println("[cron:import]", err.Error())
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
154
						}
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
155
						log.Println("[cron:import] imported", data.Name)
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
156
					})
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
157
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
158
					goit.Cron.Add(repo.Id, cron.Daily, func() {
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
159
						if err := goit.Pull(repo.Id); err != nil {
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
160
							log.Println("[cron:mirror]", err.Error())
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
161
						}
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
162
						log.Println("[cron:mirror] updated", data.Edit.Name)
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
163
					})
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
164
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
165
					goit.Cron.Update()
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
166
				}
fc3cc2f Jakob Wakeling 2023-12-16 17:51:02
167
988a708 Jakob Wakeling 2023-10-23 23:05:22
168
				http.Redirect(w, r, "/"+data.Edit.Name+"/edit", http.StatusFound)
988a708 Jakob Wakeling 2023-10-23 23:05:22
169
				return
988a708 Jakob Wakeling 2023-10-23 23:05:22
170
			}
988a708 Jakob Wakeling 2023-10-23 23:05:22
171
988a708 Jakob Wakeling 2023-10-23 23:05:22
172
		case "transfer":
988a708 Jakob Wakeling 2023-10-23 23:05:22
173
			data.Transfer.Owner = r.FormValue("owner")
988a708 Jakob Wakeling 2023-10-23 23:05:22
174
988a708 Jakob Wakeling 2023-10-23 23:05:22
175
			if data.Transfer.Owner == "" {
988a708 Jakob Wakeling 2023-10-23 23:05:22
176
				data.Transfer.Message = "New owner cannot be empty"
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
177
			} else if u, err := goit.GetUserByName(data.Transfer.Owner); err != nil {
988a708 Jakob Wakeling 2023-10-23 23:05:22
178
				log.Println("[/repo/edit]", err.Error())
988a708 Jakob Wakeling 2023-10-23 23:05:22
179
				goit.HttpError(w, http.StatusInternalServerError)
988a708 Jakob Wakeling 2023-10-23 23:05:22
180
				return
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
181
			} else if u == nil {
988a708 Jakob Wakeling 2023-10-23 23:05:22
182
				data.Transfer.Message = "User \"" + data.Transfer.Owner + "\" does not exist"
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
183
			} else if err := goit.ChownRepo(repo.Id, u.Id); err != nil {
988a708 Jakob Wakeling 2023-10-23 23:05:22
184
				log.Println("[/repo/edit]", err.Error())
988a708 Jakob Wakeling 2023-10-23 23:05:22
185
				goit.HttpError(w, http.StatusInternalServerError)
988a708 Jakob Wakeling 2023-10-23 23:05:22
186
				return
988a708 Jakob Wakeling 2023-10-23 23:05:22
187
			} else {
3c55d1d Jakob Wakeling 2023-11-27 21:07:45
188
				log.Println("User", user.Id, "transferred repo", repo.Id, "ownership to", u.Id)
988a708 Jakob Wakeling 2023-10-23 23:05:22
189
				http.Redirect(w, r, "/"+data.Edit.Name, http.StatusFound)
988a708 Jakob Wakeling 2023-10-23 23:05:22
190
				return
988a708 Jakob Wakeling 2023-10-23 23:05:22
191
			}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
192
988a708 Jakob Wakeling 2023-10-23 23:05:22
193
		case "delete":
988a708 Jakob Wakeling 2023-10-23 23:05:22
194
			var reponame = r.FormValue("reponame")
988a708 Jakob Wakeling 2023-10-23 23:05:22
195
988a708 Jakob Wakeling 2023-10-23 23:05:22
196
			if reponame != repo.Name {
988a708 Jakob Wakeling 2023-10-23 23:05:22
197
				data.Delete.Message = "Input does not match the repository name"
988a708 Jakob Wakeling 2023-10-23 23:05:22
198
			} else if err := goit.DelRepo(repo.Id); err != nil {
988a708 Jakob Wakeling 2023-10-23 23:05:22
199
				log.Println("[/repo/edit]", err.Error())
988a708 Jakob Wakeling 2023-10-23 23:05:22
200
				goit.HttpError(w, http.StatusInternalServerError)
988a708 Jakob Wakeling 2023-10-23 23:05:22
201
				return
988a708 Jakob Wakeling 2023-10-23 23:05:22
202
			} else {
988a708 Jakob Wakeling 2023-10-23 23:05:22
203
				http.Redirect(w, r, "/", http.StatusFound)
988a708 Jakob Wakeling 2023-10-23 23:05:22
204
				return
988a708 Jakob Wakeling 2023-10-23 23:05:22
205
			}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
206
		}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
207
	}
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
208
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
209
	if err := goit.Tmpl.ExecuteTemplate(w, "repo/edit", data); err != nil {
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
210
		log.Println("[/repo/edit]", err.Error())
ceeeb52 Jakob Wakeling 2023-08-19 12:11:35
211
	}
4a22b95 Jakob Wakeling 2023-08-14 20:57:25
212
}
213