Merge lp:~mattyw/sharinfoo/list-all into lp:sharinfoo

Proposed by Matthew Williams
Status: Merged
Merged at revision: 15
Proposed branch: lp:~mattyw/sharinfoo/list-all
Merge into: lp:sharinfoo
Diff against target: 375 lines (+168/-38)
7 files modified
client/client.go (+30/-0)
client/client_test.go (+44/-18)
cmd/shfoo/main.go (+8/-0)
server.go (+43/-18)
simplestore.go (+32/-2)
store.go (+1/-0)
tests/client_test.py (+10/-0)
To merge this branch: bzr merge lp:~mattyw/sharinfoo/list-all
Reviewer Review Type Date Requested Status
Casey Marshall Approve
Review via email: mp+201794@code.launchpad.net

Commit message

Add support for admins to do a shfoo -list command to get a list of all files in the server.

Returned as a json list of path names

Description of the change

Add support for admins to do a shfoo -list command to get a list of all files in the server.

Returned as a json list of path names

To post a comment you must log in.
Revision history for this message
Casey Marshall (cmars) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'client/client.go'
2--- client/client.go 2014-01-13 14:34:27 +0000
3+++ client/client.go 2014-01-15 15:03:39 +0000
4@@ -228,3 +228,33 @@
5 sha := resp.Header.Get("Content-sha256")
6 return sha, nil
7 }
8+
9+func List(addr string) ([]byte, error) {
10+ authString, err := loadAuth()
11+ if err != nil {
12+ return nil, err
13+ }
14+
15+ query := url.Values{}
16+ query.Add("listall", "1")
17+
18+ u := url.URL{
19+ Scheme: "http",
20+ Host: addr,
21+ Path: "/",
22+ RawQuery: query.Encode(),
23+ }
24+ req, err := http.NewRequest("GET", u.String(), nil)
25+ if err != nil {
26+ return nil, err
27+ }
28+ req.Header.Add("Authorization", authString)
29+ resp, err := http.DefaultClient.Do(req)
30+ if err != nil {
31+ return nil, err
32+ }
33+ if resp.StatusCode != 200 {
34+ return nil, fmt.Errorf(resp.Status)
35+ }
36+ return ioutil.ReadAll(resp.Body)
37+}
38
39=== modified file 'client/client_test.go'
40--- client/client_test.go 2014-01-13 11:00:26 +0000
41+++ client/client_test.go 2014-01-15 15:03:39 +0000
42@@ -4,11 +4,11 @@
43 "crypto/sha256"
44 "encoding/base64"
45 "encoding/json"
46- . "launchpad.net/gocheck"
47+ gc "launchpad.net/gocheck"
48 "testing"
49 )
50
51-func Test(t *testing.T) { TestingT(t) }
52+func Test(t *testing.T) { gc.TestingT(t) }
53
54 var (
55 addr = "localhost:8080"
56@@ -17,47 +17,73 @@
57
58 type ClientSuite struct{}
59
60-var _ = Suite(&ClientSuite{})
61+var _ = gc.Suite(&ClientSuite{})
62
63-func (s *ClientSuite) TestPutGet(c *C) {
64+func (s *ClientSuite) TestPutGet(c *gc.C) {
65 data := []byte("hello there")
66 path := "/test-data"
67 err := Put(addr, path, data)
68- c.Assert(err, IsNil)
69+ c.Assert(err, gc.IsNil)
70 result, err := Get(addr, path)
71- c.Assert(err, IsNil)
72- c.Assert(result, DeepEquals, data)
73+ c.Assert(err, gc.IsNil)
74+ c.Assert(result, gc.DeepEquals, data)
75 err = Delete(addr, path)
76- c.Assert(err, IsNil)
77+ c.Assert(err, gc.IsNil)
78 }
79
80-func (s *ClientSuite) TestShareAndAccess(c *C) {
81+func (s *ClientSuite) TestShareAndAccess(c *gc.C) {
82 output := []map[string]bool{}
83 shareWith := "foo@foobar.com"
84 data := []byte("hello there")
85 path := "/test-share"
86 err := Put(addr, path, data)
87- c.Assert(err, IsNil)
88+ c.Assert(err, gc.IsNil)
89 err = Share(addr, path, shareWith)
90- c.Assert(err, IsNil)
91+ c.Assert(err, gc.IsNil)
92 owners, err := Access(addr, path)
93 err = json.Unmarshal(owners, &output)
94- c.Assert(err, IsNil)
95- c.Assert(output[1], DeepEquals, map[string]bool{shareWith: true})
96+ c.Assert(err, gc.IsNil)
97+ c.Assert(output[1], gc.DeepEquals, map[string]bool{shareWith: true})
98
99 err = Delete(addr, path)
100- c.Assert(err, IsNil)
101+ c.Assert(err, gc.IsNil)
102 }
103
104-func (s *ClientSuite) TestHead(c *C) {
105+func (s *ClientSuite) TestHead(c *gc.C) {
106 data := []byte("hello there")
107 path := "/test-data"
108 err := Put(addr, path, data)
109- c.Assert(err, IsNil)
110+ c.Assert(err, gc.IsNil)
111 hasher.Write(data)
112 expected := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
113
114 sha, err := Sha(addr, path)
115- c.Assert(err, IsNil)
116- c.Assert(sha, Equals, expected)
117+ c.Assert(err, gc.IsNil)
118+ c.Assert(sha, gc.Equals, expected)
119+}
120+
121+func (s *ClientSuite) putFile(data []byte, path string, c *gc.C) {
122+ err := Put(addr, path, data)
123+ c.Assert(err, gc.IsNil)
124+}
125+
126+func (s *ClientSuite) deleteFile(path string, c *gc.C) {
127+ err := Delete(addr, path)
128+ c.Assert(err, gc.IsNil)
129+}
130+
131+func (s *ClientSuite) TestListAll(c *gc.C) {
132+ s.putFile([]byte("hello there"), "/test-data", c)
133+ s.putFile([]byte("hello again"), "/test-data-2", c)
134+
135+ expected := []string{"/test-data-2", "/test-data"}
136+ result := []string{}
137+
138+ list, err := List(addr)
139+ c.Assert(err, gc.IsNil)
140+ s.deleteFile("/test-data", c)
141+ s.deleteFile("/test-data-2", c)
142+ err = json.Unmarshal(list, &result)
143+ c.Assert(err, gc.IsNil)
144+ c.Assert(result, gc.DeepEquals, expected)
145 }
146
147=== modified file 'cmd/shfoo/main.go'
148--- cmd/shfoo/main.go 2014-01-13 14:34:27 +0000
149+++ cmd/shfoo/main.go 2014-01-15 15:03:39 +0000
150@@ -35,6 +35,7 @@
151 var addr *string = flag.String("http", "localhost:8080", "Remote sharinfoo address")
152 var access *string = flag.String("access", "", "Get list of users with access to this path")
153 var sha *string = flag.String("sha", "", "Get the sha256 of the file")
154+var list *bool = flag.Bool("list", false, "List all files")
155
156 func die(err error) {
157 log.Println(err)
158@@ -75,6 +76,13 @@
159 die(err)
160 }
161 fmt.Println(output)
162+ case *list:
163+ output, err := client.List(*addr)
164+ if err != nil {
165+ die(err)
166+ }
167+ os.Stdout.Write(output)
168+ fmt.Println("")
169 default:
170 err = fmt.Errorf("No action specified")
171 }
172
173=== modified file 'server.go'
174--- server.go 2014-01-13 14:34:27 +0000
175+++ server.go 2014-01-15 15:03:39 +0000
176@@ -60,11 +60,12 @@
177 respError(w, err)
178 return
179 }
180+ _, meta := query["meta"]
181 req.ParseForm()
182- if req.Form.Get("meta") == "1" || len(query) == 1 && query["meta"][0] == "1" {
183+ if req.Form.Get("meta") == "1" || meta {
184 fs.handleMetadata(w, req)
185 } else {
186- fs.handleContent(w, req)
187+ fs.handleContent(w, req, query)
188 }
189 }
190
191@@ -81,7 +82,38 @@
192 return true
193 }
194
195-func (fs *FileServer) handleContent(w http.ResponseWriter, req *http.Request) {
196+func (fs *FileServer) getFile(w http.ResponseWriter, userId, path string) {
197+ access, err := fs.store.Access(userId, path)
198+ if err != nil {
199+ respError(w, err)
200+ return
201+ }
202+ if !access.CanRead() {
203+ respForbidden(w)
204+ return
205+ }
206+ content, err := fs.store.Get(path)
207+ if err != nil {
208+ respError(w, err)
209+ return
210+ }
211+ _, err = io.Copy(w, content)
212+ if err != nil {
213+ log.Println(err)
214+ }
215+}
216+
217+func (fs *FileServer) getListAll(w http.ResponseWriter) {
218+ list, err := fs.store.List()
219+ if err != nil {
220+ respError(w, err)
221+ return
222+ }
223+ w.WriteHeader(http.StatusOK)
224+ w.Write(list)
225+}
226+
227+func (fs *FileServer) handleContent(w http.ResponseWriter, req *http.Request, query url.Values) {
228 userId, err := ValidateAuthorization(req)
229 if err != nil {
230 respError(w, err)
231@@ -98,24 +130,17 @@
232
233 switch req.Method {
234 case "GET":
235- access, err := fs.store.Access(userId, path)
236- if err != nil {
237- respError(w, err)
238- return
239- }
240- if !access.CanRead() {
241+ _, listall := query["listall"]
242+ if listall {
243+ if fs.AllowAdmin(userId) {
244+ fs.getListAll(w)
245+ return
246+ }
247 respForbidden(w)
248 return
249 }
250- content, err := fs.store.Get(path)
251- if err != nil {
252- respError(w, err)
253- return
254- }
255- _, err = io.Copy(w, content)
256- if err != nil {
257- log.Println(err)
258- }
259+ fs.getFile(w, userId, path)
260+ return
261 case "HEAD":
262 hasher := sha256.New()
263 access, err := fs.store.Access(userId, path)
264
265=== modified file 'simplestore.go'
266--- simplestore.go 2014-01-07 21:43:46 +0000
267+++ simplestore.go 2014-01-15 15:03:39 +0000
268@@ -26,19 +26,24 @@
269 "os"
270 "path"
271 "path/filepath"
272+ "regexp"
273 )
274
275+var metaRegex = regexp.MustCompile(".meta$")
276+
277 type SimpleStore struct {
278 Path string
279 }
280
281 type SimpleMetadata struct {
282+ Path string
283 Owners map[string]bool
284 Readers map[string]bool
285 }
286
287-func NewSimpleMetadata() *SimpleMetadata {
288+func NewSimpleMetadata(path string) *SimpleMetadata {
289 return &SimpleMetadata{
290+ Path: path,
291 Owners: make(map[string]bool),
292 Readers: make(map[string]bool),
293 }
294@@ -93,7 +98,7 @@
295 meta, err := ss.metadata(p)
296 if err != nil {
297 if os.IsNotExist(err) {
298- meta = NewSimpleMetadata()
299+ meta = NewSimpleMetadata(p)
300 } else {
301 return err
302 }
303@@ -131,6 +136,10 @@
304 if err != nil {
305 return nil, err
306 }
307+ return ss.openMetaData(mdPath)
308+}
309+
310+func (ss *SimpleStore) openMetaData(mdPath string) (*SimpleMetadata, error) {
311 f, err := os.Open(mdPath)
312 if err != nil {
313 return nil, err
314@@ -166,3 +175,24 @@
315 _, err = f.Write(buf)
316 return err
317 }
318+
319+func (ss *SimpleStore) List() ([]byte, error) {
320+ pathList := []string{}
321+ walkerF := func(path string, info os.FileInfo, err error) error {
322+ if metaRegex.Match([]byte(info.Name())) {
323+ md, err := ss.openMetaData(path)
324+ if err != nil {
325+ return err
326+ }
327+ if md.Path != "" { //For now, if the path is empty - ignore it
328+ pathList = append(pathList, md.Path)
329+ }
330+ }
331+ return nil
332+ }
333+ err := filepath.Walk(ss.Path, walkerF)
334+ if err != nil {
335+ return nil, err
336+ }
337+ return json.Marshal(pathList)
338+}
339
340=== modified file 'store.go'
341--- store.go 2014-01-07 21:43:46 +0000
342+++ store.go 2014-01-15 15:03:39 +0000
343@@ -53,4 +53,5 @@
344 Get(path string) (io.ReadCloser, error)
345 Put(path, owner string, content io.ReadCloser) error
346 Delete(path string) error
347+ List() (string, error)
348 }
349
350=== modified file 'tests/client_test.py'
351--- tests/client_test.py 2014-01-13 14:34:27 +0000
352+++ tests/client_test.py 2014-01-15 15:03:39 +0000
353@@ -26,6 +26,11 @@
354 f.write(line)
355
356
357+def list_command():
358+ out = subprocess.Popen(["shfoo", "-list"], stdout=subprocess.PIPE)
359+ return out.stdout.read().strip()
360+
361+
362 def share_command(path, share):
363 subprocess.check_call(["shfoo", "-share", "/%s" % path, "-with", share])
364
365@@ -81,5 +86,10 @@
366 out = sha_command(test_data)
367 self.assertEquals(out, expected)
368
369+ def test_list(self):
370+ ls = list_command()
371+ expected = '["/%s"]' % test_data
372+ self.assertEquals(ls, expected)
373+
374 if __name__ == '__main__':
375 unittest.main()

Subscribers

People subscribed via source and target branches