mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-22 04:20:37 -06:00
@@ -165,15 +165,16 @@ func (i *Index) Purge(id *sprovider.ResourceId) error {
|
||||
}
|
||||
|
||||
// Move update the path of an entry and all its children
|
||||
func (i *Index) Move(ri *sprovider.ResourceInfo, fullPath string) error {
|
||||
doc, err := i.getEntity(idToBleveId(ri.Id))
|
||||
func (i *Index) Move(id *sprovider.ResourceId, fullPath string) error {
|
||||
bleveId := idToBleveId(id)
|
||||
doc, err := i.getEntity(bleveId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldName := doc.Path
|
||||
newName := utils.MakeRelativePath(fullPath)
|
||||
|
||||
doc, err = i.updateEntity(idToBleveId(ri.Id), func(doc *indexDocument) {
|
||||
doc, err = i.updateEntity(bleveId, func(doc *indexDocument) {
|
||||
doc.Path = newName
|
||||
doc.Name = path.Base(newName)
|
||||
})
|
||||
@@ -211,7 +212,7 @@ func (i *Index) Search(ctx context.Context, req *searchsvc.SearchIndexRequest) (
|
||||
deletedQuery := bleve.NewBoolFieldQuery(false)
|
||||
deletedQuery.SetField("Deleted")
|
||||
query := bleve.NewConjunctionQuery(
|
||||
bleve.NewQueryStringQuery("Name:"+strings.ToLower(req.Query)),
|
||||
bleve.NewQueryStringQuery(req.Query),
|
||||
deletedQuery, // Skip documents that have been marked as deleted
|
||||
bleve.NewQueryStringQuery("RootID:"+req.Ref.ResourceId.StorageId+"!"+req.Ref.ResourceId.OpaqueId), // Limit search to the space
|
||||
bleve.NewQueryStringQuery("Path:"+utils.MakeRelativePath(path.Join(req.Ref.Path, "/"))+"*"), // Limit search to this directory in the space
|
||||
|
||||
@@ -24,25 +24,9 @@ var _ = Describe("Index", func() {
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "rootopaqueid",
|
||||
}
|
||||
ref = &sprovider.Reference{
|
||||
ResourceId: rootId,
|
||||
Path: "./foo.pdf",
|
||||
}
|
||||
ri = &sprovider.ResourceInfo{
|
||||
Id: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "opaqueid",
|
||||
},
|
||||
ParentId: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "someopaqueid",
|
||||
},
|
||||
Path: "Foo.pdf",
|
||||
Size: 12345,
|
||||
Type: sprovider.ResourceType_RESOURCE_TYPE_FILE,
|
||||
MimeType: "application/pdf",
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 4000},
|
||||
}
|
||||
filename string
|
||||
ref *sprovider.Reference
|
||||
ri *sprovider.ResourceInfo
|
||||
parentRef = &sprovider.Reference{
|
||||
ResourceId: rootId,
|
||||
Path: "./my/sudbir",
|
||||
@@ -76,7 +60,7 @@ var _ = Describe("Index", func() {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 4000},
|
||||
}
|
||||
|
||||
assertDocCount = func(rootId *sprovider.ResourceId, query string, expectedCount int) {
|
||||
assertDocCount = func(rootId *sprovider.ResourceId, query string, expectedCount int) []*searchmsg.Match {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Query: query,
|
||||
Ref: &searchmsg.Reference{
|
||||
@@ -87,11 +71,14 @@ var _ = Describe("Index", func() {
|
||||
},
|
||||
})
|
||||
ExpectWithOffset(1, err).ToNot(HaveOccurred())
|
||||
ExpectWithOffset(1, len(res.Matches)).To(Equal(expectedCount))
|
||||
ExpectWithOffset(1, len(res.Matches)).To(Equal(expectedCount), "query returned unexpected number of results: "+query)
|
||||
return res.Matches
|
||||
}
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
filename = "Foo.pdf"
|
||||
|
||||
mapping, err := index.BuildMapping()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
@@ -102,6 +89,28 @@ var _ = Describe("Index", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
ref = &sprovider.Reference{
|
||||
ResourceId: rootId,
|
||||
Path: "./" + filename,
|
||||
}
|
||||
ri = &sprovider.ResourceInfo{
|
||||
Id: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "opaqueid",
|
||||
},
|
||||
ParentId: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "someopaqueid",
|
||||
},
|
||||
Path: filename,
|
||||
Size: 12345,
|
||||
Type: sprovider.ResourceType_RESOURCE_TYPE_FILE,
|
||||
MimeType: "application/pdf",
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 4000},
|
||||
}
|
||||
})
|
||||
|
||||
Describe("New", func() {
|
||||
It("returns a new index instance", func() {
|
||||
i, err := index.New(bleveIndex)
|
||||
@@ -119,163 +128,139 @@ var _ = Describe("Index", func() {
|
||||
})
|
||||
|
||||
Describe("Search", func() {
|
||||
Context("with a file in the root of the space", func() {
|
||||
BeforeEach(func() {
|
||||
Context("by other fields than filename", func() {
|
||||
JustBeforeEach(func() {
|
||||
err := i.Add(ref, ri)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("scopes the search to the specified space", func() {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: "differentstorageid",
|
||||
OpaqueId: "differentopaqueid",
|
||||
},
|
||||
},
|
||||
Query: "foo.pdf",
|
||||
})
|
||||
It("finds files by size", func() {
|
||||
assertDocCount(ref.ResourceId, `Size:12345`, 1)
|
||||
assertDocCount(ref.ResourceId, `Size:>1000`, 1)
|
||||
assertDocCount(ref.ResourceId, `Size:<100000`, 1)
|
||||
|
||||
assertDocCount(ref.ResourceId, `Size:12344`, 0)
|
||||
assertDocCount(ref.ResourceId, `Size:<1000`, 0)
|
||||
assertDocCount(ref.ResourceId, `Size:>100000`, 0)
|
||||
})
|
||||
})
|
||||
|
||||
Context("by filename", func() {
|
||||
It("finds files with spaces in the filename", func() {
|
||||
ri.Path = "Foo oo.pdf"
|
||||
ref.Path = "./" + ri.Path
|
||||
err := i.Add(ref, ri)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
Expect(len(res.Matches)).To(Equal(0))
|
||||
|
||||
assertDocCount(ref.ResourceId, `Name:foo\ o*`, 1)
|
||||
})
|
||||
|
||||
It("limits the search to the relevant fields", func() {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: ref.ResourceId.StorageId,
|
||||
OpaqueId: ref.ResourceId.OpaqueId,
|
||||
},
|
||||
},
|
||||
Query: "*" + ref.ResourceId.OpaqueId + "*",
|
||||
})
|
||||
It("finds files by digits in the filename", func() {
|
||||
ri.Path = "12345.pdf"
|
||||
ref.Path = "./" + ri.Path
|
||||
err := i.Add(ref, ri)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
Expect(len(res.Matches)).To(Equal(0))
|
||||
|
||||
assertDocCount(ref.ResourceId, `Name:1234*`, 1)
|
||||
})
|
||||
|
||||
It("returns all desired fields", func() {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: ref.ResourceId.StorageId,
|
||||
OpaqueId: ref.ResourceId.OpaqueId,
|
||||
},
|
||||
},
|
||||
Query: "foo.pdf",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
Expect(len(res.Matches)).To(Equal(1))
|
||||
match := res.Matches[0]
|
||||
Expect(match.Entity.Ref.ResourceId.OpaqueId).To(Equal(ref.ResourceId.OpaqueId))
|
||||
Expect(match.Entity.Ref.Path).To(Equal(ref.Path))
|
||||
Expect(match.Entity.Id.OpaqueId).To(Equal(ri.Id.OpaqueId))
|
||||
Expect(match.Entity.Name).To(Equal(ri.Path))
|
||||
Expect(match.Entity.Size).To(Equal(ri.Size))
|
||||
Expect(match.Entity.Type).To(Equal(uint64(ri.Type)))
|
||||
Expect(match.Entity.MimeType).To(Equal(ri.MimeType))
|
||||
Expect(match.Entity.Deleted).To(BeFalse())
|
||||
Expect(uint64(match.Entity.LastModifiedTime.AsTime().Unix())).To(Equal(ri.Mtime.Seconds))
|
||||
})
|
||||
|
||||
It("finds files by name, prefix or substring match", func() {
|
||||
queries := []string{"foo.pdf", "foo*", "*oo.p*"}
|
||||
for _, query := range queries {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: ref.ResourceId.StorageId,
|
||||
OpaqueId: ref.ResourceId.OpaqueId,
|
||||
},
|
||||
},
|
||||
Query: query,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
Expect(len(res.Matches)).To(Equal(1), "query returned no result: "+query)
|
||||
Expect(res.Matches[0].Entity.Ref.ResourceId.OpaqueId).To(Equal(ref.ResourceId.OpaqueId))
|
||||
Expect(res.Matches[0].Entity.Ref.Path).To(Equal(ref.Path))
|
||||
Expect(res.Matches[0].Entity.Id.OpaqueId).To(Equal(ri.Id.OpaqueId))
|
||||
Expect(res.Matches[0].Entity.Name).To(Equal(ri.Path))
|
||||
Expect(res.Matches[0].Entity.Size).To(Equal(ri.Size))
|
||||
}
|
||||
})
|
||||
|
||||
It("is case-insensitive", func() {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: ref.ResourceId.StorageId,
|
||||
OpaqueId: ref.ResourceId.OpaqueId,
|
||||
},
|
||||
},
|
||||
Query: "Foo*",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
Expect(len(res.Matches)).To(Equal(1))
|
||||
})
|
||||
|
||||
Context("and an additional file in a subdirectory", func() {
|
||||
var (
|
||||
nestedRef *sprovider.Reference
|
||||
nestedRI *sprovider.ResourceInfo
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
nestedRef = &sprovider.Reference{
|
||||
ResourceId: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "rootopaqueid",
|
||||
},
|
||||
Path: "./nested/nestedpdf.pdf",
|
||||
}
|
||||
nestedRI = &sprovider.ResourceInfo{
|
||||
Id: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "nestedopaqueid",
|
||||
},
|
||||
Path: "nestedpdf.pdf",
|
||||
Size: 12345,
|
||||
}
|
||||
err := i.Add(nestedRef, nestedRI)
|
||||
Context("with a file in the root of the space", func() {
|
||||
JustBeforeEach(func() {
|
||||
err := i.Add(ref, ri)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("finds files living deeper in the tree by filename, prefix or substring match", func() {
|
||||
queries := []string{"nestedpdf.pdf", "nested*", "*tedpdf.*"}
|
||||
It("scopes the search to the specified space", func() {
|
||||
resourceId := &sprovider.ResourceId{
|
||||
StorageId: "differentstorageid",
|
||||
OpaqueId: "differentopaqueid",
|
||||
}
|
||||
assertDocCount(resourceId, `Name:foo.pdf`, 0)
|
||||
})
|
||||
|
||||
It("limits the search to the specified fields", func() {
|
||||
assertDocCount(ref.ResourceId, "Name:*"+ref.ResourceId.OpaqueId+"*", 0)
|
||||
})
|
||||
|
||||
It("returns all desired fields", func() {
|
||||
matches := assertDocCount(ref.ResourceId, "Name:foo.pdf", 1)
|
||||
match := matches[0]
|
||||
Expect(match.Entity.Ref.ResourceId.OpaqueId).To(Equal(ref.ResourceId.OpaqueId))
|
||||
Expect(match.Entity.Ref.Path).To(Equal(ref.Path))
|
||||
Expect(match.Entity.Id.OpaqueId).To(Equal(ri.Id.OpaqueId))
|
||||
Expect(match.Entity.Name).To(Equal(ri.Path))
|
||||
Expect(match.Entity.Size).To(Equal(ri.Size))
|
||||
Expect(match.Entity.Type).To(Equal(uint64(ri.Type)))
|
||||
Expect(match.Entity.MimeType).To(Equal(ri.MimeType))
|
||||
Expect(match.Entity.Deleted).To(BeFalse())
|
||||
Expect(uint64(match.Entity.LastModifiedTime.AsTime().Unix())).To(Equal(ri.Mtime.Seconds))
|
||||
})
|
||||
|
||||
It("finds files by name, prefix or substring match", func() {
|
||||
queries := []string{"foo.pdf", "foo*", "*oo.p*"}
|
||||
for _, query := range queries {
|
||||
matches := assertDocCount(ref.ResourceId, query, 1)
|
||||
Expect(matches[0].Entity.Ref.ResourceId.OpaqueId).To(Equal(ref.ResourceId.OpaqueId))
|
||||
Expect(matches[0].Entity.Ref.Path).To(Equal(ref.Path))
|
||||
Expect(matches[0].Entity.Id.OpaqueId).To(Equal(ri.Id.OpaqueId))
|
||||
Expect(matches[0].Entity.Name).To(Equal(ri.Path))
|
||||
Expect(matches[0].Entity.Size).To(Equal(ri.Size))
|
||||
}
|
||||
})
|
||||
|
||||
It("uses a lower-case index", func() {
|
||||
assertDocCount(ref.ResourceId, "Name:foo*", 1)
|
||||
assertDocCount(ref.ResourceId, "Name:Foo*", 0)
|
||||
})
|
||||
|
||||
Context("and an additional file in a subdirectory", func() {
|
||||
var (
|
||||
nestedRef *sprovider.Reference
|
||||
nestedRI *sprovider.ResourceInfo
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
nestedRef = &sprovider.Reference{
|
||||
ResourceId: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "rootopaqueid",
|
||||
},
|
||||
Path: "./nested/nestedpdf.pdf",
|
||||
}
|
||||
nestedRI = &sprovider.ResourceInfo{
|
||||
Id: &sprovider.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "nestedopaqueid",
|
||||
},
|
||||
Path: "nestedpdf.pdf",
|
||||
Size: 12345,
|
||||
}
|
||||
err := i.Add(nestedRef, nestedRI)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("finds files living deeper in the tree by filename, prefix or substring match", func() {
|
||||
queries := []string{"nestedpdf.pdf", "nested*", "*tedpdf.*"}
|
||||
for _, query := range queries {
|
||||
assertDocCount(ref.ResourceId, query, 1)
|
||||
}
|
||||
})
|
||||
|
||||
It("does not find the higher levels when limiting the searched directory", func() {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: ref.ResourceId.StorageId,
|
||||
OpaqueId: ref.ResourceId.OpaqueId,
|
||||
},
|
||||
Path: "./nested/",
|
||||
},
|
||||
Query: query,
|
||||
Query: "Name:foo.pdf",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
Expect(len(res.Matches)).To(Equal(1), "query returned no result: "+query)
|
||||
}
|
||||
})
|
||||
|
||||
It("does not find the higher levels when limiting the searched directory", func() {
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: ref.ResourceId.StorageId,
|
||||
OpaqueId: ref.ResourceId.OpaqueId,
|
||||
},
|
||||
Path: "./nested/",
|
||||
},
|
||||
Query: "foo.pdf",
|
||||
Expect(len(res.Matches)).To(Equal(0))
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
Expect(len(res.Matches)).To(Equal(0))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -366,23 +351,13 @@ var _ = Describe("Index", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
parentRi.Path = "newname"
|
||||
err = i.Move(parentRi, "./somewhere/else/newname")
|
||||
err = i.Move(parentRi.Id, "./somewhere/else/newname")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
assertDocCount(rootId, "subdir", 0)
|
||||
|
||||
res, err := i.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Query: "child.pdf",
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: rootId.StorageId,
|
||||
OpaqueId: rootId.OpaqueId,
|
||||
},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(res.Matches)).To(Equal(1))
|
||||
Expect(res.Matches[0].Entity.Ref.Path).To(Equal("./somewhere/else/newname/child.pdf"))
|
||||
matches := assertDocCount(rootId, "Name:child.pdf", 1)
|
||||
Expect(matches[0].Entity.Ref.Path).To(Equal("./somewhere/else/newname/child.pdf"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,13 +30,13 @@ func (_m *IndexClient) Add(ref *providerv1beta1.Reference, ri *providerv1beta1.R
|
||||
return r0
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ri
|
||||
func (_m *IndexClient) Delete(ri *providerv1beta1.ResourceId) error {
|
||||
ret := _m.Called(ri)
|
||||
// Delete provides a mock function with given fields: id
|
||||
func (_m *IndexClient) Delete(id *providerv1beta1.ResourceId) error {
|
||||
ret := _m.Called(id)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId) error); ok {
|
||||
r0 = rf(ri)
|
||||
r0 = rf(id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -65,13 +65,13 @@ func (_m *IndexClient) DocCount() (uint64, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Move provides a mock function with given fields: ri, path
|
||||
func (_m *IndexClient) Move(ri *providerv1beta1.ResourceInfo, path string) error {
|
||||
ret := _m.Called(ri, path)
|
||||
// Move provides a mock function with given fields: id, fullPath
|
||||
func (_m *IndexClient) Move(id *providerv1beta1.ResourceId, fullPath string) error {
|
||||
ret := _m.Called(id, fullPath)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceInfo, string) error); ok {
|
||||
r0 = rf(ri, path)
|
||||
if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId, string) error); ok {
|
||||
r0 = rf(id, fullPath)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -79,13 +79,13 @@ func (_m *IndexClient) Move(ri *providerv1beta1.ResourceInfo, path string) error
|
||||
return r0
|
||||
}
|
||||
|
||||
// Purge provides a mock function with given fields: ri
|
||||
func (_m *IndexClient) Purge(ri *providerv1beta1.ResourceId) error {
|
||||
ret := _m.Called(ri)
|
||||
// Purge provides a mock function with given fields: id
|
||||
func (_m *IndexClient) Purge(id *providerv1beta1.ResourceId) error {
|
||||
ret := _m.Called(id)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId) error); ok {
|
||||
r0 = rf(ri)
|
||||
r0 = rf(id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -93,13 +93,13 @@ func (_m *IndexClient) Purge(ri *providerv1beta1.ResourceId) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// Restore provides a mock function with given fields: ri
|
||||
func (_m *IndexClient) Restore(ri *providerv1beta1.ResourceId) error {
|
||||
ret := _m.Called(ri)
|
||||
// Restore provides a mock function with given fields: id
|
||||
func (_m *IndexClient) Restore(id *providerv1beta1.ResourceId) error {
|
||||
ret := _m.Called(id)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId) error); ok {
|
||||
r0 = rf(ri)
|
||||
r0 = rf(id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -58,11 +58,11 @@ func (p *Provider) handleEvent(ev interface{}) {
|
||||
|
||||
statRes, err := p.statResource(ref, owner)
|
||||
if err != nil {
|
||||
p.logger.Error().Err(err).Msg("failed to stat the changed resource")
|
||||
p.logger.Error().Err(err).Msg("failed to stat the moved resource")
|
||||
return
|
||||
}
|
||||
if statRes.Status.Code != rpc.Code_CODE_OK {
|
||||
p.logger.Error().Interface("statRes", statRes).Msg("failed to stat the changed resource")
|
||||
p.logger.Error().Interface("statRes", statRes).Msg("failed to stat the moved resource")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -76,9 +76,9 @@ func (p *Provider) handleEvent(ev interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
err = p.indexClient.Move(statRes.Info, gpRes.Path)
|
||||
err = p.indexClient.Move(statRes.Info.Id, gpRes.Path)
|
||||
if err != nil {
|
||||
p.logger.Error().Err(err).Msg("failed to restore the changed resource in the index")
|
||||
p.logger.Error().Err(err).Msg("failed to move the changed resource in the index")
|
||||
}
|
||||
return
|
||||
case events.ContainerCreated:
|
||||
@@ -126,7 +126,6 @@ func (p *Provider) statResource(ref *provider.Reference, owner *user.User) (*pro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Stat changed resource resource
|
||||
return p.gwClient.Stat(ownerCtx, &provider.StatRequest{Ref: ref})
|
||||
}
|
||||
|
||||
@@ -136,7 +135,6 @@ func (p *Provider) getPath(id *provider.ResourceId, owner *user.User) (*provider
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Stat changed resource resource
|
||||
return p.gwClient.GetPath(ownerCtx, &provider.GetPathRequest{ResourceId: id})
|
||||
}
|
||||
|
||||
|
||||
@@ -156,8 +156,8 @@ var _ = Describe("Searchprovider", func() {
|
||||
Status: status.NewOK(ctx),
|
||||
Path: "./new/path.pdf",
|
||||
}, nil)
|
||||
indexClient.On("Move", mock.MatchedBy(func(riToIndex *sprovider.ResourceInfo) bool {
|
||||
return riToIndex.Id.OpaqueId == ri.Id.OpaqueId
|
||||
indexClient.On("Move", mock.MatchedBy(func(id *sprovider.ResourceId) bool {
|
||||
return id.OpaqueId == ri.Id.OpaqueId
|
||||
}), "./new/path.pdf").Return(nil).Run(func(args mock.Arguments) {
|
||||
called = true
|
||||
})
|
||||
|
||||
@@ -125,7 +125,7 @@ func (p *Provider) Search(ctx context.Context, req *searchsvc.SearchRequest) (*s
|
||||
|
||||
_, rootStorageID := storagespace.SplitStorageID(space.Root.StorageId)
|
||||
res, err := p.indexClient.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
Query: req.Query,
|
||||
Query: formatQuery(req.Query),
|
||||
Ref: &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: space.Root.StorageId,
|
||||
@@ -217,3 +217,18 @@ func (p *Provider) logDocCount() {
|
||||
}
|
||||
p.logger.Debug().Interface("count", c).Msg("new document count")
|
||||
}
|
||||
|
||||
func formatQuery(q string) string {
|
||||
query := q
|
||||
fields := []string{"RootID", "Path", "ID", "Name", "Size", "Mtime", "MimeType", "Type"}
|
||||
for _, field := range fields {
|
||||
query = strings.ReplaceAll(query, strings.ToLower(field)+":", field+":")
|
||||
}
|
||||
|
||||
if strings.Contains(query, ":") {
|
||||
return query // Sophisticated field based search
|
||||
}
|
||||
|
||||
// this is a basic filename search
|
||||
return "Name:*" + strings.ReplaceAll(strings.ToLower(query), " ", `\ `) + "*"
|
||||
}
|
||||
|
||||
@@ -146,6 +146,50 @@ var _ = Describe("Searchprovider", func() {
|
||||
}, nil)
|
||||
})
|
||||
|
||||
It("lowercases the filename", func() {
|
||||
p.Search(ctx, &searchsvc.SearchRequest{
|
||||
Query: "Foo.pdf",
|
||||
})
|
||||
indexClient.AssertCalled(GinkgoT(), "Search", mock.Anything, mock.MatchedBy(func(req *searchsvc.SearchIndexRequest) bool {
|
||||
return req.Query == "Name:*foo.pdf*"
|
||||
}))
|
||||
})
|
||||
|
||||
It("does not mess with field-based searches", func() {
|
||||
p.Search(ctx, &searchsvc.SearchRequest{
|
||||
Query: "Size:<10",
|
||||
})
|
||||
indexClient.AssertCalled(GinkgoT(), "Search", mock.Anything, mock.MatchedBy(func(req *searchsvc.SearchIndexRequest) bool {
|
||||
return req.Query == "Size:<10"
|
||||
}))
|
||||
})
|
||||
|
||||
It("uppercases field names", func() {
|
||||
tests := []struct {
|
||||
Original string
|
||||
Expected string
|
||||
}{
|
||||
{Original: "size:<100", Expected: "Size:<100"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
p.Search(ctx, &searchsvc.SearchRequest{
|
||||
Query: test.Original,
|
||||
})
|
||||
indexClient.AssertCalled(GinkgoT(), "Search", mock.Anything, mock.MatchedBy(func(req *searchsvc.SearchIndexRequest) bool {
|
||||
return req.Query == test.Expected
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
It("escapes special characters", func() {
|
||||
p.Search(ctx, &searchsvc.SearchRequest{
|
||||
Query: "Foo oo.pdf",
|
||||
})
|
||||
indexClient.AssertCalled(GinkgoT(), "Search", mock.Anything, mock.MatchedBy(func(req *searchsvc.SearchIndexRequest) bool {
|
||||
return req.Query == `Name:*foo\ oo.pdf*`
|
||||
}))
|
||||
})
|
||||
|
||||
It("searches the personal user space", func() {
|
||||
res, err := p.Search(ctx, &searchsvc.SearchRequest{
|
||||
Query: "foo",
|
||||
@@ -160,7 +204,7 @@ var _ = Describe("Searchprovider", func() {
|
||||
Expect(match.Entity.Ref.Path).To(Equal("./path/to/Foo.pdf"))
|
||||
|
||||
indexClient.AssertCalled(GinkgoT(), "Search", mock.Anything, mock.MatchedBy(func(req *searchsvc.SearchIndexRequest) bool {
|
||||
return req.Query == "foo" && req.Ref.ResourceId.OpaqueId == personalSpace.Root.OpaqueId && req.Ref.Path == ""
|
||||
return req.Query == "Name:*foo*" && req.Ref.ResourceId.OpaqueId == personalSpace.Root.OpaqueId && req.Ref.Path == ""
|
||||
}))
|
||||
})
|
||||
})
|
||||
@@ -225,7 +269,7 @@ var _ = Describe("Searchprovider", func() {
|
||||
}, nil)
|
||||
|
||||
res, err := p.Search(ctx, &searchsvc.SearchRequest{
|
||||
Query: "foo",
|
||||
Query: "Foo",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).ToNot(BeNil())
|
||||
@@ -237,7 +281,7 @@ var _ = Describe("Searchprovider", func() {
|
||||
Expect(match.Entity.Ref.Path).To(Equal("./to/Shared.pdf"))
|
||||
|
||||
indexClient.AssertCalled(GinkgoT(), "Search", mock.Anything, mock.MatchedBy(func(req *searchsvc.SearchIndexRequest) bool {
|
||||
return req.Query == "foo" && req.Ref.ResourceId.StorageId == grantSpace.Root.StorageId && req.Ref.Path == "./grant/path"
|
||||
return req.Query == "Name:*foo*" && req.Ref.ResourceId.StorageId == grantSpace.Root.StorageId && req.Ref.Path == "./grant/path"
|
||||
}))
|
||||
})
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ type ProviderClient interface {
|
||||
type IndexClient interface {
|
||||
Search(ctx context.Context, req *searchsvc.SearchIndexRequest) (*searchsvc.SearchIndexResponse, error)
|
||||
Add(ref *providerv1beta1.Reference, ri *providerv1beta1.ResourceInfo) error
|
||||
Move(ri *providerv1beta1.ResourceInfo, path string) error
|
||||
Delete(ri *providerv1beta1.ResourceId) error
|
||||
Restore(ri *providerv1beta1.ResourceId) error
|
||||
Purge(ri *providerv1beta1.ResourceId) error
|
||||
Move(id *providerv1beta1.ResourceId, fullPath string) error
|
||||
Delete(id *providerv1beta1.ResourceId) error
|
||||
Restore(id *providerv1beta1.ResourceId) error
|
||||
Purge(id *providerv1beta1.ResourceId) error
|
||||
DocCount() (uint64, error)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
revactx "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/owncloud/ocis/v2/extensions/webdav/pkg/net"
|
||||
"github.com/owncloud/ocis/v2/extensions/webdav/pkg/prop"
|
||||
@@ -43,7 +44,7 @@ func (g Webdav) Search(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := revactx.ContextSetToken(r.Context(), t)
|
||||
ctx = metadata.Set(ctx, revactx.TokenHeader, t)
|
||||
rsp, err := g.searchClient.Search(ctx, &searchsvc.SearchRequest{
|
||||
Query: "*" + rep.SearchFiles.Search.Pattern + "*",
|
||||
Query: rep.SearchFiles.Search.Pattern,
|
||||
})
|
||||
if err != nil {
|
||||
e := merrors.Parse(err.Error())
|
||||
@@ -128,9 +129,15 @@ func matchToPropResponse(ctx context.Context, match *searchmsg.Match) (*propfind
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getcontenttype", match.Entity.MimeType))
|
||||
|
||||
size := strconv.FormatUint(match.Entity.Size, 10)
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:size", size))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getcontentlength", size))
|
||||
|
||||
if match.Entity.Type == uint64(provider.ResourceType_RESOURCE_TYPE_CONTAINER) {
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Raw("d:resourcetype", "<d:collection/>"))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:size", size))
|
||||
} else {
|
||||
propstatOK.Prop = append(propstatOK.Prop,
|
||||
prop.Escaped("d:resourcetype", ""),
|
||||
prop.Escaped("d:getcontentlength", size),
|
||||
)
|
||||
}
|
||||
// TODO find name for score property
|
||||
score := strconv.FormatFloat(float64(match.Score), 'f', -1, 64)
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:score", score))
|
||||
|
||||
Reference in New Issue
Block a user