V0.2.1 - search scope bugfix (#56)

Co-authored-by: Graham Steffaniak <graham.steffaniak@autodesk.com>
This commit is contained in:
Graham Steffaniak 2023-10-18 10:32:22 -05:00 committed by GitHub
parent 4bab354c99
commit 47e1975c12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 123 additions and 80 deletions

View File

@ -5,33 +5,45 @@
? github.com/gtsteffaniak/filebrowser/auth [no test files] ? github.com/gtsteffaniak/filebrowser/auth [no test files]
? github.com/gtsteffaniak/filebrowser/cmd [no test files] ? github.com/gtsteffaniak/filebrowser/cmd [no test files]
PASS PASS
ok github.com/gtsteffaniak/filebrowser/diskcache 0.003s ok github.com/gtsteffaniak/filebrowser/diskcache 0.004s
? github.com/gtsteffaniak/filebrowser/errors [no test files] ? github.com/gtsteffaniak/filebrowser/errors [no test files]
? github.com/gtsteffaniak/filebrowser/files [no test files] ? github.com/gtsteffaniak/filebrowser/files [no test files]
PASS PASS
ok github.com/gtsteffaniak/filebrowser/fileutils 0.003s ok github.com/gtsteffaniak/filebrowser/fileutils 0.003s
2023/09/24 12:52:05 h: 401 <nil> 2023/10/18 10:19:52 Saving new user: username
2023/09/24 12:52:05 h: 401 <nil> 2023/10/18 10:19:52 Saving new user: username
2023/09/24 12:52:05 h: 401 <nil> 2023/10/18 10:19:52 Saving new user: username
2023/09/24 12:52:05 h: 401 <nil> 2023/10/18 10:19:52 Saving new user: username
2023/09/24 12:52:05 h: 401 <nil> 2023/10/18 10:19:52 Saving new user: username
2023/09/24 12:52:05 h: 401 <nil> 2023/10/18 10:19:52 Saving new user: username
2023/10/18 10:19:52 Saving new user: username
2023/10/18 10:19:52 Saving new user: username
2023/10/18 10:19:52 h: 401 <nil>
2023/10/18 10:19:52 h: 401 <nil>
2023/10/18 10:19:52 h: 401 <nil>
2023/10/18 10:19:52 h: 401 <nil>
2023/10/18 10:19:52 Saving new user: username
2023/10/18 10:19:52 Saving new user: username
2023/10/18 10:19:52 Saving new user: username
2023/10/18 10:19:52 Saving new user: username
2023/10/18 10:19:53 h: 401 <nil>
2023/10/18 10:19:53 h: 401 <nil>
PASS PASS
ok github.com/gtsteffaniak/filebrowser/http 0.094s ok github.com/gtsteffaniak/filebrowser/http 0.208s
PASS PASS
ok github.com/gtsteffaniak/filebrowser/img 0.144s ok github.com/gtsteffaniak/filebrowser/img 0.124s
goos: linux
goarch: amd64
pkg: github.com/gtsteffaniak/filebrowser/index
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
BenchmarkFillIndex-8 10 3239196 ns/op 11289 B/op 448 allocs/op
BenchmarkSearchAllIndexes-8 10 6645964 ns/op 3176834 B/op 59104 allocs/op
PASS
ok github.com/gtsteffaniak/filebrowser/index 0.126s
PASS PASS
ok github.com/gtsteffaniak/filebrowser/rules 0.002s ok github.com/gtsteffaniak/filebrowser/rules 0.002s
PASS PASS
ok github.com/gtsteffaniak/filebrowser/runner 0.003s ok github.com/gtsteffaniak/filebrowser/runner 0.003s
goos: linux
goarch: amd64
pkg: github.com/gtsteffaniak/filebrowser/search
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
BenchmarkSearchAllIndexes-8 10 5912685 ns/op 3003976 B/op 46139 allocs/op
BenchmarkFillIndex-8 10 3157995 ns/op 18370 B/op 449 allocs/op
PASS
ok github.com/gtsteffaniak/filebrowser/search 0.116s
PASS PASS
ok github.com/gtsteffaniak/filebrowser/settings 0.005s ok github.com/gtsteffaniak/filebrowser/settings 0.005s
? github.com/gtsteffaniak/filebrowser/share [no test files] ? github.com/gtsteffaniak/filebrowser/share [no test files]

View File

@ -2,6 +2,7 @@ package http
import ( import (
"net/http" "net/http"
"strings"
"github.com/gtsteffaniak/filebrowser/index" "github.com/gtsteffaniak/filebrowser/index"
) )
@ -11,8 +12,11 @@ var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *dat
query := r.URL.Query().Get("query") query := r.URL.Query().Get("query")
// Retrieve the User-Agent and X-Auth headers from the request // Retrieve the User-Agent and X-Auth headers from the request
sessionId := r.Header.Get("SessionId") sessionId := r.Header.Get("SessionId")
userScope := r.Header.Get("UserScope")
index := *index.GetIndex() index := *index.GetIndex()
results, fileTypes := index.Search(query, r.URL.Path, sessionId) combinedScope := strings.TrimPrefix(userScope+r.URL.Path, ".")
combinedScope = strings.TrimPrefix(combinedScope, "/")
results, fileTypes := index.Search(query, combinedScope, sessionId)
for _, path := range results { for _, path := range results {
responseObj := map[string]interface{}{ responseObj := map[string]interface{}{
"path": path, "path": path,

View File

@ -8,7 +8,14 @@ import (
) )
var typeRegexp = regexp.MustCompile(`type:(\S+)`) var typeRegexp = regexp.MustCompile(`type:(\S+)`)
var AllFiletypeOptions = []string{
"image",
"audio",
"archive",
"video",
"doc",
"dir",
}
var documentTypes = []string{ var documentTypes = []string{
".word", ".word",
".pdf", ".pdf",

View File

@ -18,13 +18,18 @@ var (
) )
func (si *Index) Search(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) { func (si *Index) Search(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
if scope == "" {
scope = "/"
}
fileTypes := map[string]bool{}
runningHash := generateRandomHash(4) runningHash := generateRandomHash(4)
sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
searchOptions := ParseSearch(search) searchOptions := ParseSearch(search)
mutex.RLock() mutex.RLock()
defer mutex.RUnlock() defer mutex.RUnlock()
fileListTypes := make(map[string]map[string]bool) fileListTypes := make(map[string]map[string]bool)
var matching []string matching := []string{}
for _, searchTerm := range searchOptions.Terms { for _, searchTerm := range searchOptions.Terms {
if searchTerm == "" { if searchTerm == "" {
continue continue
@ -42,7 +47,6 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
case "Files": case "Files":
paths = si.Files paths = si.Files
} }
for _, path := range paths { for _, path := range paths {
value, found := sessionInProgress.Load(sourceSession) value, found := sessionInProgress.Load(sourceSession)
if !found || value != runningHash { if !found || value != runningHash {
@ -55,7 +59,8 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
if pathName == "" { if pathName == "" {
continue continue
} }
matches, fileType := containsSearchTerm(path, searchTerm, *searchOptions, isDir)
matches, fileType := containsSearchTerm(path, searchTerm, *searchOptions, isDir, fileTypes)
if !matches { if !matches {
continue continue
} }
@ -80,24 +85,16 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
func scopedPathNameFilter(pathName string, scope string) string { func scopedPathNameFilter(pathName string, scope string) string {
scope = strings.TrimPrefix(scope, "/") scope = strings.TrimPrefix(scope, "/")
pathName = strings.TrimPrefix(pathName, "/")
if strings.HasPrefix(pathName, scope) { if strings.HasPrefix(pathName, scope) {
pathName = strings.TrimPrefix(pathName, scope) pathName = "/" + strings.TrimPrefix(pathName, scope)
} else { } else {
pathName = "" pathName = ""
} }
return pathName return pathName
} }
var fileTypes = map[string]bool{ func containsSearchTerm(pathName string, searchTerm string, options SearchOptions, isDir bool, fileTypes map[string]bool) (bool, map[string]bool) {
"audio": false,
"image": false,
"video": false,
"doc": false,
"archive": false,
"dir": false,
}
func containsSearchTerm(pathName string, searchTerm string, options SearchOptions, isDir bool) (bool, map[string]bool) {
conditions := options.Conditions conditions := options.Conditions
path := getLastPathComponent(pathName) path := getLastPathComponent(pathName)
// Convert to lowercase once // Convert to lowercase once
@ -110,11 +107,12 @@ func containsSearchTerm(pathName string, searchTerm string, options SearchOption
var fileSize int64 var fileSize int64
matchesAllConditions := true matchesAllConditions := true
extension := filepath.Ext(path) extension := filepath.Ext(path)
for k := range fileTypes { for _, k := range AllFiletypeOptions {
fileTypes[k] = IsMatchingType(extension, k) if IsMatchingType(extension, k) {
fileTypes[k] = true
}
} }
fileTypes["dir"] = isDir fileTypes["dir"] = isDir
for t, v := range conditions { for t, v := range conditions {
if t == "exact" { if t == "exact" {
continue continue

View File

@ -3,6 +3,8 @@ package index
import ( import (
"reflect" "reflect"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func BenchmarkSearchAllIndexes(b *testing.B) { func BenchmarkSearchAllIndexes(b *testing.B) {
@ -75,27 +77,74 @@ func TestParseSearch(t *testing.T) {
} }
func TestSearchIndexes(t *testing.T) { func TestSearchIndexes(t *testing.T) {
type args struct { indexes = Index{
search string Dirs: []string{
scope string "/test",
sourceSession string "/test/path",
"/new/test/path",
},
Files: []string{
"/test/path/file.txt",
"/test/audio1.wav",
"/new/test/audio.wav",
"/new/test/video.mp4",
"/new/test/video.MP4",
"/new/test/path/archive.zip",
},
} }
tests := []struct { tests := []struct {
name string search string
args args scope string
want []string expectedResult []string
want1 map[string]map[string]bool expectedTypes map[string]map[string]bool
}{ }{
// TODO: Add test cases. {
search: "audio",
scope: "/new/",
expectedResult: []string{"/test/audio.wav"},
expectedTypes: map[string]map[string]bool{
"/test/audio.wav": map[string]bool{"audio": true, "dir": false},
},
},
{
search: "test",
scope: "/",
expectedResult: []string{"/test"},
expectedTypes: map[string]map[string]bool{
"/test/": map[string]bool{"dir": true},
},
},
{
search: "archive",
scope: "/",
expectedResult: []string{"/new/test/path/archive.zip"},
expectedTypes: map[string]map[string]bool{
"/new/test/path/archive.zip": map[string]bool{"archive": true, "dir": false},
},
},
{
search: "video",
scope: "/",
expectedResult: []string{
"/new/test/video.mp4",
"/new/test/video.MP4",
},
expectedTypes: map[string]map[string]bool{
"/new/test/video.MP4": map[string]bool{"video": true, "dir": false},
"/new/test/video.mp4": map[string]bool{"video": true, "dir": false},
},
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.search, func(t *testing.T) {
got, got1 := indexes.Search(tt.args.search, tt.args.scope, tt.args.sourceSession) actualResult, actualTypes := indexes.Search(tt.search, tt.scope, "")
if !reflect.DeepEqual(got, tt.want) { assert.Equal(t, tt.expectedResult, actualResult)
t.Errorf("SearchAllIndexes() got = %v, want %v", got, tt.want) if len(tt.expectedTypes) > 0 {
for key, value := range tt.expectedTypes {
actualValue, exists := actualTypes[key]
assert.True(t, exists, "Expected type key '%s' not found in actual types", key)
assert.Equal(t, value, actualValue, "Type value mismatch for key '%s'", key)
} }
if !reflect.DeepEqual(got1, tt.want1) {
t.Errorf("SearchAllIndexes() got1 = %v, want %v", got1, tt.want1)
} }
}) })
} }
@ -122,34 +171,6 @@ func Test_scopedPathNameFilter(t *testing.T) {
} }
} }
func Test_containsSearchTerm(t *testing.T) {
type args struct {
pathName string
searchTerm string
options SearchOptions
isDir bool
}
tests := []struct {
name string
args args
want bool
want1 map[string]bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := containsSearchTerm(tt.args.pathName, tt.args.searchTerm, tt.args.options, tt.args.isDir)
if got != tt.want {
t.Errorf("containsSearchTerm() got = %v, want %v", got, tt.want)
}
if !reflect.DeepEqual(got1, tt.want1) {
t.Errorf("containsSearchTerm() got1 = %v, want %v", got1, tt.want1)
}
})
}
}
func Test_isDoc(t *testing.T) { func Test_isDoc(t *testing.T) {
type args struct { type args struct {
extension string extension string

View File

@ -15,6 +15,7 @@ export async function fetchURL(url, opts, auth = true) {
headers: { headers: {
"X-Auth": store.state.jwt, "X-Auth": store.state.jwt,
"sessionId": store.state.sessionId, "sessionId": store.state.sessionId,
"userScope": store.state.user.scope,
...headers, ...headers,
}, },
...rest, ...rest,