Skip to content

Commit a25ef1c

Browse files
authored
Merge branch 'dev' into add-content-api-v2
2 parents 1b33414 + 1b315f9 commit a25ef1c

File tree

11 files changed

+274
-154
lines changed

11 files changed

+274
-154
lines changed

api/v1/handlers.go

+6-93
Original file line numberDiff line numberDiff line change
@@ -3399,7 +3399,7 @@ func (s *apiV1) handleCommitCollection(c echo.Context, u *util.User) error {
33993399
// @Description This endpoint is used to get contents in a collection. If no colpath query param is passed
34003400
// @Tags collections
34013401
// @Produce json
3402-
// @Success 200 {object} []collectionListResponse
3402+
// @Success 200 {object} []collections.CollectionListResponse
34033403
// @Failure 400 {object} util.HttpError
34043404
// @Failure 500 {object} util.HttpError
34053405
// @Param coluuid path string true "coluuid"
@@ -3442,97 +3442,12 @@ func (s *apiV1) handleGetCollectionContents(c echo.Context, u *util.User) error
34423442
// if queryDir is set, do the content listing
34433443
queryDir = filepath.Clean(queryDir)
34443444

3445-
dirs := make(map[string]bool)
3446-
var out []collectionListResponse
3447-
for _, r := range refs {
3448-
if r.Path == "" || r.Name == "" {
3449-
continue
3450-
}
3451-
3452-
relp, err := getRelativePath(r, queryDir)
3453-
if err != nil {
3454-
return c.JSON(http.StatusInternalServerError, fmt.Errorf("errored while calculating relative contentPath queryDir=%s, contentPath=%s", queryDir, r.Path))
3455-
}
3456-
3457-
// if the relative contentPath requires pathing up, its definitely not in this queryDir
3458-
if strings.HasPrefix(relp, "..") {
3459-
continue
3460-
}
3461-
3462-
if relp == "." { // Query directory is the complete path containing the content.
3463-
// trying to list a CID queryDir, not allowed
3464-
if r.Type == util.Directory {
3465-
return c.JSON(http.StatusBadRequest, fmt.Errorf("listing CID directories is not allowed"))
3466-
}
3467-
3468-
out = append(out, collectionListResponse{
3469-
Name: r.Name,
3470-
Size: r.Size,
3471-
ContID: r.ID,
3472-
Cid: &util.DbCID{CID: r.Cid.CID},
3473-
Dir: queryDir,
3474-
ColUuid: coluuid,
3475-
UpdatedAt: r.UpdatedAt,
3476-
})
3477-
} else { // Query directory has a subdirectory, which contains the actual content.
3478-
3479-
// if CID is a queryDir, set type as Dir and mark Dir as listed so we don't list it again
3480-
//if r.Type == util.Directory {
3481-
// if !dirs[relp] {
3482-
// dirs[relp] = true
3483-
// out = append(out, collectionListResponse{
3484-
// Name: relp,
3485-
// Type: Dir,
3486-
// Size: r.Size,
3487-
// ContID: r.ID,
3488-
// Cid: &r.Cid,
3489-
// Dir: queryDir,
3490-
// ColUuid: coluuid,
3491-
// })
3492-
// }
3493-
// continue
3494-
//}
3495-
3496-
// if relative contentPath has a /, the file is in a subdirectory
3497-
// print the directory the file is in if we haven't already
3498-
if strings.Contains(relp, "/") {
3499-
parts := strings.Split(relp, "/")
3500-
subDir := parts[0]
3501-
if !dirs[subDir] {
3502-
dirs[subDir] = true
3503-
out = append(out, collectionListResponse{
3504-
Name: subDir,
3505-
Type: Dir,
3506-
Dir: queryDir,
3507-
ColUuid: coluuid,
3508-
})
3509-
continue
3510-
}
3511-
}
3512-
}
3513-
3514-
//var contentType CidType
3515-
contentType := File
3516-
if r.Type == util.Directory {
3517-
contentType = Dir
3518-
}
3519-
out = append(out, collectionListResponse{
3520-
Name: r.Name,
3521-
Type: contentType,
3522-
Size: r.Size,
3523-
ContID: r.ID,
3524-
Cid: &util.DbCID{CID: r.Cid.CID},
3525-
Dir: queryDir,
3526-
ColUuid: coluuid,
3527-
})
3445+
out, err := collections.GetDirectoryContents(refs, queryDir, coluuid)
3446+
if err != nil {
3447+
return err
35283448
}
3529-
return c.JSON(http.StatusOK, out)
3530-
}
35313449

3532-
func getRelativePath(r util.ContentWithPath, queryDir string) (string, error) {
3533-
contentPath := r.Path
3534-
relp, err := filepath.Rel(queryDir, contentPath)
3535-
return relp, err
3450+
return c.JSON(http.StatusOK, out)
35363451
}
35373452

35383453
// handleDeleteCollection godoc
@@ -5116,9 +5031,7 @@ func (s *apiV1) handleShuttleRepinAll(c echo.Context) error {
51165031
type CidType string
51175032

51185033
const (
5119-
Dir CidType = "directory"
5120-
File CidType = "file"
5121-
ColDir string = "dir"
5034+
ColDir string = "dir"
51225035
)
51235036

51245037
type collectionListResponse struct {

cmd/estuary-shuttle/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,7 @@ func (d *Shuttle) doPinning(ctx context.Context, op *operation.PinningOperation,
16161616
ctx, span := d.Tracer.Start(ctx, "doPinning")
16171617
defer span.End()
16181618

1619-
prs, _ := operation.UnSerializePeers(op.Peers)
1619+
prs := operation.UnSerializePeers(op.Peers)
16201620
for _, pi := range prs {
16211621
if err := d.Node.Host.Connect(ctx, *pi); err != nil {
16221622
log.Warnf("failed to connect to origin node for pinning operation: %s", err)

collections/collections.go

+102
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package collections
33
import (
44
"fmt"
55
"net/http"
6+
"path/filepath"
67
"strings"
78
"time"
89

@@ -31,6 +32,24 @@ type CollectionRef struct {
3132
Path *string `gorm:"not null"`
3233
}
3334

35+
type CidType string
36+
37+
type CollectionListResponse struct {
38+
Name string `json:"name"`
39+
Type CidType `json:"type"`
40+
Size int64 `json:"size"`
41+
ContID uint `json:"contId"`
42+
Cid *util.DbCID `json:"cid,omitempty"`
43+
Dir string `json:"dir"`
44+
ColUuid string `json:"coluuid"`
45+
UpdatedAt time.Time `json:"updatedAt"`
46+
}
47+
48+
const (
49+
CidTypeDir CidType = "directory"
50+
CidTypeFile CidType = "file"
51+
)
52+
3453
func GetCollection(coluuid string, db *gorm.DB, u *util.User) (Collection, error) {
3554
var col Collection
3655
if err := db.First(&col, "uuid = ?", coluuid).Error; err != nil {
@@ -75,3 +94,86 @@ func GetContentsInPath(coluuid string, path string, db *gorm.DB, u *util.User) (
7594

7695
return selectedRefs, nil
7796
}
97+
98+
func GetDirectoryContents(refs []util.ContentWithPath, queryDir, coluuid string) ([]*CollectionListResponse, error) {
99+
dirs := make(map[string]bool)
100+
var result []*CollectionListResponse
101+
for _, r := range refs {
102+
directoryContent, err := getDirectoryContent(r, queryDir, coluuid)
103+
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
if directoryContent != nil { // if there was content
109+
if directoryContent.Type == CidTypeDir { // if the content was a directory
110+
subDir := directoryContent.Dir
111+
if dirs[subDir] { // if the directory had already been added to response, continue
112+
continue
113+
}
114+
dirs[subDir] = true
115+
}
116+
result = append(result, directoryContent)
117+
}
118+
}
119+
return result, nil
120+
}
121+
122+
func getDirectoryContent(r util.ContentWithPath, queryDir, coluuid string) (*CollectionListResponse, error) {
123+
if r.Path == "" || r.Name == "" {
124+
return nil, nil
125+
}
126+
127+
if !strings.HasPrefix(r.Path, queryDir) {
128+
return nil, nil
129+
}
130+
131+
relp, err := getRelativePath(r, queryDir)
132+
if err != nil {
133+
return nil, &util.HttpError{
134+
Code: http.StatusInternalServerError,
135+
Reason: util.ERR_INTERNAL_SERVER,
136+
Details: fmt.Sprintf("errored while calculating relative contentPath queryDir=%s, contentPath=%s", queryDir, r.Path),
137+
}
138+
}
139+
140+
// Query directory has a subdirectory, which contains the actual content.
141+
// if relative contentPath has a /, the file is in a subdirectory
142+
// print the directory the file is in if we haven't already
143+
if strings.Contains(relp, "/") {
144+
parts := strings.Split(relp, "/")
145+
subDir := parts[0]
146+
return &CollectionListResponse{
147+
Name: subDir,
148+
Type: CidTypeDir,
149+
Dir: queryDir,
150+
ColUuid: coluuid,
151+
UpdatedAt: r.UpdatedAt,
152+
}, nil
153+
}
154+
155+
// trying to list a CID queryDir, not allowed
156+
if r.Type == util.Directory {
157+
return nil, &util.HttpError{
158+
Code: http.StatusBadRequest,
159+
Reason: util.ERR_BAD_REQUEST,
160+
Details: fmt.Sprintf("listing CID directories is not allowed"),
161+
}
162+
}
163+
return &CollectionListResponse{
164+
Name: r.Name,
165+
Type: CidTypeFile,
166+
Size: r.Size,
167+
ContID: r.ID,
168+
Cid: &util.DbCID{CID: r.Cid.CID},
169+
Dir: queryDir,
170+
ColUuid: coluuid,
171+
UpdatedAt: r.UpdatedAt,
172+
}, nil
173+
}
174+
175+
func getRelativePath(r util.ContentWithPath, queryDir string) (string, error) {
176+
contentPath := r.Path
177+
relp, err := filepath.Rel(queryDir, contentPath)
178+
return relp, err
179+
}

collections/collections_test.go

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package collections
2+
3+
import (
4+
"github.com/application-research/estuary/util"
5+
"testing"
6+
)
7+
8+
const (
9+
name = "a"
10+
contentPath = "/dir1/dir2/dir3/a"
11+
contentId = uint(1)
12+
coluuid = "collection uuid"
13+
)
14+
15+
func setupRef() util.ContentWithPath {
16+
return util.ContentWithPath{
17+
Path: contentPath,
18+
Content: util.Content{
19+
ID: contentId,
20+
Name: name,
21+
},
22+
}
23+
}
24+
25+
func TestSubDirectory(t *testing.T) {
26+
ref := setupRef()
27+
queryDir := "/dir1"
28+
expectedResponse := CollectionListResponse{
29+
Name: "dir2",
30+
Type: CidTypeDir,
31+
Size: 0,
32+
ContID: 0,
33+
Dir: queryDir,
34+
ColUuid: coluuid,
35+
}
36+
runTest(t, ref, queryDir, coluuid, &expectedResponse)
37+
}
38+
39+
func TestSubDirectory2(t *testing.T) {
40+
ref := setupRef()
41+
queryDir := "/dir1/dir2"
42+
expectedResponse := CollectionListResponse{
43+
Name: "dir3",
44+
Type: CidTypeDir,
45+
Size: 0,
46+
ContID: 0,
47+
Dir: queryDir,
48+
ColUuid: coluuid,
49+
}
50+
runTest(t, ref, queryDir, coluuid, &expectedResponse)
51+
}
52+
53+
func TestSubDirectoryWithFileInIt(t *testing.T) {
54+
ref := setupRef()
55+
queryDir := "/dir1/dir2/dir3"
56+
expectedResponse := CollectionListResponse{
57+
Name: name,
58+
Type: CidTypeFile,
59+
Size: 0,
60+
ContID: contentId,
61+
Dir: queryDir,
62+
ColUuid: coluuid,
63+
}
64+
runTest(t, ref, queryDir, coluuid, &expectedResponse)
65+
}
66+
67+
func TestFullPath(t *testing.T) {
68+
ref := setupRef()
69+
queryDir := "/dir1/dir2/dir3/a"
70+
expectedResponse := CollectionListResponse{
71+
Name: name,
72+
Type: CidTypeFile,
73+
Size: 0,
74+
ContID: contentId,
75+
Dir: queryDir,
76+
ColUuid: coluuid,
77+
}
78+
runTest(t, ref, queryDir, coluuid, &expectedResponse)
79+
}
80+
81+
func TestInvalidDirectory(t *testing.T) {
82+
ref := setupRef()
83+
queryDir := "/dir0"
84+
response, _, err := getDirectoryContent(ref, queryDir, "collection uuid")
85+
86+
if err != nil {
87+
t.Fatalf("Error: %v\n", err)
88+
}
89+
90+
if response != nil {
91+
t.Fatalf("Expected nil response but got %v\n", response)
92+
}
93+
94+
}
95+
96+
func runTest(t *testing.T, ref util.ContentWithPath, queryDir, coluuid string, expectedResponse *CollectionListResponse) {
97+
response, _, err := getDirectoryContent(ref, queryDir, coluuid)
98+
99+
if err != nil {
100+
t.Fatalf("Error: %v\n", err)
101+
}
102+
103+
parsedResponse := CollectionListResponse{
104+
Name: response.Name,
105+
Type: response.Type,
106+
Size: response.Size,
107+
ContID: response.ContID,
108+
Dir: response.Dir,
109+
ColUuid: response.ColUuid,
110+
}
111+
112+
if parsedResponse != *expectedResponse {
113+
t.Fatalf("Expected %v, got %v\n", expectedResponse, response)
114+
}
115+
}

contentmgr/pinning.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (cm *ContentManager) PinDelegatesForContent(cont util.Content) []string {
7070
return out
7171

7272
} else {
73-
ai, err := cm.addrInfoForShuttle(cont.Location)
73+
ai, err := cm.addrInfoForContentLocation(cont.Location)
7474
if err != nil {
7575
cm.log.Errorf("failed to get address info for shuttle %q: %s", cont.Location, err)
7676
return nil
@@ -176,7 +176,7 @@ func (cm *ContentManager) GetPinOperation(cont util.Content, peers []*peer.AddrI
176176
Name: cont.Name,
177177
Peers: operation.SerializePeers(peers),
178178
Started: cont.CreatedAt,
179-
Status: types.PinningStatusQueued,
179+
Status: types.GetContentPinningStatus(cont),
180180
Replace: replaceID,
181181
Location: cont.Location,
182182
MakeDeal: makeDeal,
@@ -428,7 +428,7 @@ func (cm *ContentManager) DoPinning(ctx context.Context, op *operation.PinningOp
428428
}()
429429
}
430430

431-
prs, _ := operation.UnSerializePeers(op.Peers)
431+
prs := operation.UnSerializePeers(op.Peers)
432432
for _, pi := range prs {
433433
if err := cm.node.Host.Connect(ctx, *pi); err != nil {
434434
cm.log.Warnf("failed to connect to origin node for pinning operation: %s", err)

0 commit comments

Comments
 (0)