Skip to content
This repository was archived by the owner on Apr 26, 2021. It is now read-only.

Commit 5ea3142

Browse files
committed
Merge pull request #168 from ricardodani/master
Added support to update repository data
2 parents e2500d6 + cd662a7 commit 5ea3142

File tree

4 files changed

+219
-201
lines changed

4 files changed

+219
-201
lines changed

api/handler.go

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ func SetupRouter() *pat.Router {
6464
router.Post("/user", http.HandlerFunc(newUser))
6565
router.Delete("/user/{name}", http.HandlerFunc(removeUser))
6666
router.Delete("/repository/revoke", http.HandlerFunc(revokeAccess))
67-
router.Put("/repository/set", http.HandlerFunc(setAccess))
6867
router.Get("/repository/{name:[^/]*/?[^/]+}/archive", http.HandlerFunc(getArchive))
6968
router.Get("/repository/{name:[^/]*/?[^/]+}/contents", http.HandlerFunc(getFileContents))
7069
router.Get("/repository/{name:[^/]*/?[^/]+}/tree", http.HandlerFunc(getTree))
@@ -77,30 +76,12 @@ func SetupRouter() *pat.Router {
7776
router.Post("/repository", http.HandlerFunc(newRepository))
7877
router.Get("/repository/{name:[^/]*/?[^/]+}", http.HandlerFunc(getRepository))
7978
router.Delete("/repository/{name:[^/]*/?[^/]+}", http.HandlerFunc(removeRepository))
80-
router.Put("/repository/{name:[^/]*/?[^/]+}", http.HandlerFunc(renameRepository))
79+
router.Put("/repository/{name:[^/]*/?[^/]+}", http.HandlerFunc(updateRepository))
8180
router.Get("/healthcheck", http.HandlerFunc(healthCheck))
8281
router.Post("/hook/{name}", http.HandlerFunc(addHook))
8382
return router
8483
}
8584

86-
func setAccess(w http.ResponseWriter, r *http.Request) {
87-
repositories, users, err := accessParameters(r.Body)
88-
readOnly := r.URL.Query().Get("readonly") == "yes"
89-
if err != nil {
90-
http.Error(w, err.Error(), http.StatusBadRequest)
91-
return
92-
}
93-
if err := repository.SetAccess(repositories, users, readOnly); err != nil {
94-
http.Error(w, err.Error(), http.StatusNotFound)
95-
return
96-
}
97-
if readOnly {
98-
fmt.Fprintf(w, "Successfully set read-only access to users \"%s\" into repository \"%s\"", users, repositories)
99-
} else {
100-
fmt.Fprintf(w, "Successfully set full access to users \"%s\" into repository \"%s\"", users, repositories)
101-
}
102-
}
103-
10485
func grantAccess(w http.ResponseWriter, r *http.Request) {
10586
repositories, users, err := accessParameters(r.Body)
10687
readOnly := r.URL.Query().Get("readonly") == "yes"
@@ -253,15 +234,19 @@ func removeRepository(w http.ResponseWriter, r *http.Request) {
253234
fmt.Fprintf(w, "Repository \"%s\" successfully removed\n", name)
254235
}
255236

256-
func renameRepository(w http.ResponseWriter, r *http.Request) {
257-
var p struct{ Name string }
237+
func updateRepository(w http.ResponseWriter, r *http.Request) {
238+
name := r.URL.Query().Get(":name")
239+
repo, err := repository.Get(name)
240+
if err != nil {
241+
http.Error(w, err.Error(), http.StatusNotFound)
242+
return
243+
}
258244
defer r.Body.Close()
259-
err := parseBody(r.Body, &p)
245+
err = parseBody(r.Body, &repo)
260246
if err != nil {
261247
http.Error(w, err.Error(), http.StatusBadRequest)
262248
}
263-
name := r.URL.Query().Get(":name")
264-
err = repository.Rename(name, p.Name)
249+
err = repository.Update(name, repo)
265250
if err != nil && err.Error() == "not found" {
266251
http.Error(w, err.Error(), http.StatusNotFound)
267252
} else if err != nil {

api/handler_test.go

Lines changed: 113 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,37 @@ func (s *S) TestParseBodyShouldMapBodyJsonToGivenStruct(c *gocheck.C) {
309309
c.Assert(p.Name, gocheck.Equals, expected)
310310
}
311311

312+
func (s *S) TestParseBodyShouldMapBodyEmptyJsonToADict(c *gocheck.C) {
313+
dict := make(map[string]interface{})
314+
b := bufferCloser{bytes.NewBufferString(`{"name": "Test", "isPublic": false, "users": []}`)}
315+
err := parseBody(b, &dict)
316+
c.Assert(err, gocheck.IsNil)
317+
expected := map[string]interface{}{
318+
"name": "Test",
319+
"isPublic": false,
320+
"users": []interface{}{},
321+
}
322+
c.Assert(dict, gocheck.DeepEquals, expected)
323+
}
324+
325+
func (s *S) TestParseBodyShouldMapBodyJsonAndUpdateMap(c *gocheck.C) {
326+
dict := map[string]interface{}{
327+
"isPublic": false,
328+
"users": []string{"merry"},
329+
"readonlyusers": []string{"pippin"},
330+
}
331+
b := bufferCloser{bytes.NewBufferString(`{"name": "Test", "users": []}`)}
332+
err := parseBody(b, &dict)
333+
c.Assert(err, gocheck.IsNil)
334+
expected := map[string]interface{}{
335+
"name": "Test",
336+
"isPublic": false,
337+
"users": []interface{}{},
338+
"readonlyusers": []string{"pippin"},
339+
}
340+
c.Assert(dict, gocheck.DeepEquals, expected)
341+
}
342+
312343
func (s *S) TestParseBodyShouldReturnErrorWhenJsonIsInvalid(c *gocheck.C) {
313344
var p repository.Repository
314345
b := bufferCloser{bytes.NewBufferString("{]ja9aW}")}
@@ -342,67 +373,6 @@ func (s *S) TestNewRepositoryShouldReturnErrorWhenBodyIsEmpty(c *gocheck.C) {
342373
c.Assert(recorder.Code, gocheck.Equals, 400)
343374
}
344375

345-
func (s *S) TestSetAccessShouldReturnErrorWhenBodyIsEmpty(c *gocheck.C) {
346-
b := strings.NewReader("")
347-
recorder, request := put("/repository/set", b, c)
348-
s.router.ServeHTTP(recorder, request)
349-
c.Assert(recorder.Code, gocheck.Equals, 400)
350-
}
351-
352-
func (s *S) TestSetAccessUpdatesReposDocument(c *gocheck.C) {
353-
u, err := user.New("pippin", map[string]string{})
354-
conn, err := db.Conn()
355-
c.Assert(err, gocheck.IsNil)
356-
defer conn.Close()
357-
defer conn.User().Remove(bson.M{"_id": "pippin"})
358-
c.Assert(err, gocheck.IsNil)
359-
r := repository.Repository{Name: "onerepo", Users: []string{"oneuser"}}
360-
err = conn.Repository().Insert(&r)
361-
c.Assert(err, gocheck.IsNil)
362-
defer conn.Repository().Remove(bson.M{"_id": r.Name})
363-
r2 := repository.Repository{Name: "otherepo", Users: []string{"otheruser"}}
364-
err = conn.Repository().Insert(&r2)
365-
c.Assert(err, gocheck.IsNil)
366-
defer conn.Repository().Remove(bson.M{"_id": r2.Name})
367-
b := bytes.NewBufferString(fmt.Sprintf(`{"repositories": ["%s", "%s"], "users": ["%s"]}`, r.Name, r2.Name, u.Name))
368-
rec, req := put("/repository/set", b, c)
369-
s.router.ServeHTTP(rec, req)
370-
var repos []repository.Repository
371-
err = conn.Repository().Find(bson.M{"_id": bson.M{"$in": []string{r.Name, r2.Name}}}).All(&repos)
372-
c.Assert(err, gocheck.IsNil)
373-
c.Assert(rec.Code, gocheck.Equals, 200)
374-
for _, repo := range repos {
375-
c.Assert(repo.Users, gocheck.DeepEquals, []string{u.Name})
376-
}
377-
}
378-
379-
func (s *S) TestSetReadonlyAccessUpdatesReposDocument(c *gocheck.C) {
380-
u, err := user.New("pippin", map[string]string{})
381-
conn, err := db.Conn()
382-
c.Assert(err, gocheck.IsNil)
383-
defer conn.Close()
384-
defer conn.User().Remove(bson.M{"_id": "pippin"})
385-
c.Assert(err, gocheck.IsNil)
386-
r := repository.Repository{Name: "onerepo", ReadOnlyUsers: []string{"oneuser"}}
387-
err = conn.Repository().Insert(&r)
388-
c.Assert(err, gocheck.IsNil)
389-
defer conn.Repository().Remove(bson.M{"_id": r.Name})
390-
r2 := repository.Repository{Name: "otherepo", ReadOnlyUsers: []string{"otheruser"}}
391-
err = conn.Repository().Insert(&r2)
392-
c.Assert(err, gocheck.IsNil)
393-
defer conn.Repository().Remove(bson.M{"_id": r2.Name})
394-
b := bytes.NewBufferString(fmt.Sprintf(`{"repositories": ["%s", "%s"], "users": ["%s"]}`, r.Name, r2.Name, u.Name))
395-
rec, req := put("/repository/set?readonly=yes", b, c)
396-
s.router.ServeHTTP(rec, req)
397-
var repos []repository.Repository
398-
err = conn.Repository().Find(bson.M{"_id": bson.M{"$in": []string{r.Name, r2.Name}}}).All(&repos)
399-
c.Assert(err, gocheck.IsNil)
400-
c.Assert(rec.Code, gocheck.Equals, 200)
401-
for _, repo := range repos {
402-
c.Assert(repo.ReadOnlyUsers, gocheck.DeepEquals, []string{u.Name})
403-
}
404-
}
405-
406376
func (s *S) TestGrantAccessUpdatesReposDocument(c *gocheck.C) {
407377
u, err := user.New("pippin", map[string]string{})
408378
conn, err := db.Conn()
@@ -949,27 +919,96 @@ func (s *S) TestRemoveRepositoryShouldReturnErrorMsgWhenRepoDoesNotExist(c *goch
949919
c.Assert(string(b), gocheck.Equals, "Could not remove repository: not found\n")
950920
}
951921

952-
func (s *S) TestRenameRepository(c *gocheck.C) {
953-
r, err := repository.New("raising", []string{"[email protected]"}, []string{""}, true)
922+
func (s *S) TestUpdateRespositoryShouldReturnErrorWhenBodyIsEmpty(c *gocheck.C) {
923+
r, err := repository.New("something", []string{"[email protected]"}, []string{""}, true)
924+
c.Assert(err, gocheck.IsNil)
925+
conn, err := db.Conn()
954926
c.Assert(err, gocheck.IsNil)
927+
defer conn.Close()
928+
defer conn.Repository().RemoveId(r.Name)
929+
b := strings.NewReader("")
930+
recorder, request := put("/repository/something", b, c)
931+
s.router.ServeHTTP(recorder, request)
932+
c.Assert(recorder.Code, gocheck.Equals, 400)
933+
}
934+
935+
func (s *S) TestUpdateRepositoryData(c *gocheck.C) {
936+
r, err := repository.New("something", []string{"[email protected]"}, []string{""}, true)
937+
c.Assert(err, gocheck.IsNil)
938+
conn, err := db.Conn()
939+
c.Assert(err, gocheck.IsNil)
940+
defer conn.Close()
941+
defer conn.Repository().RemoveId(r.Name)
955942
url := fmt.Sprintf("/repository/%s", r.Name)
956-
body := strings.NewReader(`{"name":"freedom"}`)
943+
body := strings.NewReader(`{"users": ["b"], "readonlyusers": ["a"], "ispublic": false}`)
957944
request, err := http.NewRequest("PUT", url, body)
958945
c.Assert(err, gocheck.IsNil)
959946
recorder := httptest.NewRecorder()
960947
s.router.ServeHTTP(recorder, request)
961948
c.Assert(recorder.Code, gocheck.Equals, http.StatusOK)
962-
_, err = repository.Get("raising")
963-
c.Assert(err, gocheck.NotNil)
964-
r.Name = "freedom"
965-
repo, err := repository.Get("freedom")
949+
r.Users = []string{"b"}
950+
r.ReadOnlyUsers = []string{"a"}
951+
r.IsPublic = false
952+
repo, err := repository.Get("something")
966953
c.Assert(err, gocheck.IsNil)
967954
c.Assert(repo, gocheck.DeepEquals, *r)
968955
}
969956

957+
func (s *S) TestUpdateRepositoryDataPartial(c *gocheck.C) {
958+
r, err := repository.New("something", []string{"pippin"}, []string{"merry"}, true)
959+
c.Assert(err, gocheck.IsNil)
960+
conn, err := db.Conn()
961+
c.Assert(err, gocheck.IsNil)
962+
defer conn.Close()
963+
defer conn.Repository().RemoveId(r.Name)
964+
url := fmt.Sprintf("/repository/%s", r.Name)
965+
body := strings.NewReader(`{"readonlyusers": ["a", "b"]}`)
966+
request, err := http.NewRequest("PUT", url, body)
967+
c.Assert(err, gocheck.IsNil)
968+
recorder := httptest.NewRecorder()
969+
s.router.ServeHTTP(recorder, request)
970+
c.Assert(recorder.Code, gocheck.Equals, http.StatusOK)
971+
r.Users = []string{"pippin"}
972+
r.ReadOnlyUsers = []string{"a", "b"}
973+
r.IsPublic = true
974+
repo, err := repository.Get("something")
975+
c.Assert(err, gocheck.IsNil)
976+
c.Assert(repo, gocheck.DeepEquals, *r)
977+
}
978+
979+
func (s *S) TestUpdateRepositoryNotFound(c *gocheck.C) {
980+
url := "/repository/foo"
981+
body := strings.NewReader(`{"ispublic":true}`)
982+
request, err := http.NewRequest("PUT", url, body)
983+
c.Assert(err, gocheck.IsNil)
984+
recorder := httptest.NewRecorder()
985+
s.router.ServeHTTP(recorder, request)
986+
c.Assert(recorder.Code, gocheck.Equals, http.StatusNotFound)
987+
}
988+
989+
func (s *S) TestUpdateRepositoryInvalidJSON(c *gocheck.C) {
990+
r, err := repository.New("bar", []string{"[email protected]"}, []string{""}, true)
991+
c.Assert(err, gocheck.IsNil)
992+
conn, err := db.Conn()
993+
c.Assert(err, gocheck.IsNil)
994+
defer conn.Close()
995+
defer conn.Repository().RemoveId(r.Name)
996+
url := "/repository/bar"
997+
body := strings.NewReader(`{"name""`)
998+
request, err := http.NewRequest("PUT", url, body)
999+
c.Assert(err, gocheck.IsNil)
1000+
recorder := httptest.NewRecorder()
1001+
s.router.ServeHTTP(recorder, request)
1002+
c.Assert(recorder.Code, gocheck.Equals, http.StatusBadRequest)
1003+
}
1004+
9701005
func (s *S) TestRenameRepositoryWithNamespace(c *gocheck.C) {
9711006
r, err := repository.New("lift/raising", []string{"[email protected]"}, []string{}, true)
9721007
c.Assert(err, gocheck.IsNil)
1008+
conn, err := db.Conn()
1009+
c.Assert(err, gocheck.IsNil)
1010+
defer conn.Close()
1011+
defer conn.Repository().RemoveId(r.Name)
9731012
url := fmt.Sprintf("/repository/%s/", r.Name)
9741013
body := strings.NewReader(`{"name":"norestraint/freedom"}`)
9751014
request, err := http.NewRequest("PUT", url, body)
@@ -986,6 +1025,12 @@ func (s *S) TestRenameRepositoryWithNamespace(c *gocheck.C) {
9861025
}
9871026

9881027
func (s *S) TestRenameRepositoryInvalidJSON(c *gocheck.C) {
1028+
r, err := repository.New("foo", []string{"[email protected]"}, []string{}, true)
1029+
conn, err := db.Conn()
1030+
c.Assert(err, gocheck.IsNil)
1031+
defer conn.Close()
1032+
defer conn.Repository().RemoveId(r.Name)
1033+
c.Assert(err, gocheck.IsNil)
9891034
url := "/repository/foo"
9901035
body := strings.NewReader(`{"name""`)
9911036
request, err := http.NewRequest("PUT", url, body)

repository/repository.go

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -178,32 +178,45 @@ func Remove(name string) error {
178178
return nil
179179
}
180180

181-
// Rename renames a repository.
182-
func Rename(oldName, newName string) error {
183-
log.Debugf("Renaming repository %q to %q", oldName, newName)
184-
repo, err := Get(oldName)
181+
// Update update a repository data.
182+
func Update(name string, newData Repository) error {
183+
log.Debugf("Updating repository %q data", name)
184+
repo, err := Get(name)
185185
if err != nil {
186-
log.Errorf("repository.Rename: Repository %q not found: %s", oldName, err)
186+
log.Errorf("repository.Update: Repository %q not found: %s", name, err)
187187
return err
188188
}
189-
newRepo := repo
190-
newRepo.Name = newName
191189
conn, err := db.Conn()
192190
if err != nil {
193191
return err
194192
}
195193
defer conn.Close()
196-
err = conn.Repository().Insert(newRepo)
197-
if err != nil {
198-
log.Errorf("repository.Rename: Error adding new repository %q: %s", newName, err)
199-
return err
200-
}
201-
err = conn.Repository().RemoveId(oldName)
202-
if err != nil {
203-
log.Errorf("repository.Rename: Error removing old repository %q: %s", oldName, err)
204-
return err
194+
if len(newData.Name) > 0 && newData.Name != repo.Name {
195+
oldName := repo.Name
196+
log.Debugf("Renaming repository %q to %q", oldName, newData.Name)
197+
err = conn.Repository().Insert(newData)
198+
if err != nil {
199+
log.Errorf("repository.Rename: Error adding new repository %q: %s", newData.Name, err)
200+
return err
201+
}
202+
err = conn.Repository().RemoveId(oldName)
203+
if err != nil {
204+
log.Errorf("repository.Rename: Error removing old repository %q: %s", oldName, err)
205+
return err
206+
}
207+
err = fs.Filesystem().Rename(barePath(oldName), barePath(newData.Name))
208+
if err != nil {
209+
log.Errorf("repository.Rename: Error renaming old repository in filesystem %q: %s", oldName, err)
210+
return err
211+
}
212+
} else {
213+
err = conn.Repository().UpdateId(repo.Name, newData)
214+
if err != nil {
215+
log.Errorf("repository.Update: Error updating repository data %q: %s", repo.Name, err)
216+
return err
217+
}
205218
}
206-
return fs.Filesystem().Rename(barePath(oldName), barePath(newName))
219+
return nil
207220
}
208221

209222
// ReadWriteURL formats the git ssh url and return it. If no remote is configured in
@@ -285,22 +298,6 @@ func (r *Repository) isValid() (bool, error) {
285298
return true, nil
286299
}
287300

288-
// SetAccess gives full or read-only permission for users in all specified repositories.
289-
// It redefines all users permissions, replacing the respective user collection
290-
func SetAccess(rNames, uNames []string, readOnly bool) error {
291-
conn, err := db.Conn()
292-
if err != nil {
293-
return err
294-
}
295-
defer conn.Close()
296-
if readOnly {
297-
_, err = conn.Repository().UpdateAll(bson.M{"_id": bson.M{"$in": rNames}}, bson.M{"$set": bson.M{"readonlyusers": uNames}})
298-
} else {
299-
_, err = conn.Repository().UpdateAll(bson.M{"_id": bson.M{"$in": rNames}}, bson.M{"$set": bson.M{"users": uNames}})
300-
}
301-
return err
302-
}
303-
304301
// GrantAccess gives full or read-only permission for users in all specified repositories.
305302
// If any of the repositories/users does not exist, GrantAccess just skips it.
306303
func GrantAccess(rNames, uNames []string, readOnly bool) error {

0 commit comments

Comments
 (0)