improve search #88
Former-commit-id: 8cd36c3ce8d79bf256587107fbe31e9ae88c85b6 [formerly f685d2088f8c28b03a816a71851e321e371cf821] [formerly 13b9d953907545737051178a0ee26e60fe29d305 [formerly 1ff0c6cb68]]
Former-commit-id: 81cd9b61592d8367b340ce52ade8ee0707f28ba9 [formerly d6d2074f965ff37d3342fce90c626b934c1f65c2]
Former-commit-id: 064840128e5a8788998905e6012bd7e29f553228
			
			
				pull/726/head
			
			
		
							parent
							
								
									4cb3ff6ff2
								
							
						
					
					
						commit
						eb86ce27f6
					
				
							
								
								
									
										22
									
								
								README.md
								
								
								
								
							
							
						
						
									
										22
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -141,6 +141,28 @@ filemanager /admin {
 | 
			
		|||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## About Search
 | 
			
		||||
 | 
			
		||||
FileManager allows you to search through your files and it has some options. By default, your search will be something like this:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
this are keywords
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If you search for that it will look at every file that contains "this", "are" and "keywords" on their name. If you want to search for an exact term, you should surround your search by double quotes:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
"this is the name"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
That will search for any file that contains "this is the name" on its name. It won't search for each separated term this time.
 | 
			
		||||
 | 
			
		||||
By default, every search will be case sensitive. Although, you can make a case insensitive search by adding `case:insensitive` to the search terms, like this:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
this are keywords case:insensitive
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Developers
 | 
			
		||||
 | 
			
		||||
If you want to build Caddy from source with this plugin, you should take the following steps:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,39 @@ import (
 | 
			
		|||
	"github.com/hacdias/caddy-filemanager/config"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type searchOptions struct {
 | 
			
		||||
	CaseInsensitive bool
 | 
			
		||||
	Terms           []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseSearch(value string) *searchOptions {
 | 
			
		||||
	opts := &searchOptions{
 | 
			
		||||
		CaseInsensitive: strings.Contains(value, "case:insensitive"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// removes the options from the value
 | 
			
		||||
	value = strings.Replace(value, "case:insensitive", "", -1)
 | 
			
		||||
	value = strings.Replace(value, "case:sensitive", "", -1)
 | 
			
		||||
	value = strings.TrimSpace(value)
 | 
			
		||||
 | 
			
		||||
	if opts.CaseInsensitive {
 | 
			
		||||
		value = strings.ToLower(value)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if the value starts with " and finishes what that character, we will
 | 
			
		||||
	// only search for that term
 | 
			
		||||
	if value[0] == '"' && value[len(value)-1] == '"' {
 | 
			
		||||
		unique := strings.TrimPrefix(value, "\"")
 | 
			
		||||
		unique = strings.TrimSuffix(unique, "\"")
 | 
			
		||||
 | 
			
		||||
		opts.Terms = []string{unique}
 | 
			
		||||
		return opts
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opts.Terms = strings.Split(value, " ")
 | 
			
		||||
	return opts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Search ...
 | 
			
		||||
func Search(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) {
 | 
			
		||||
	// Upgrades the connection to a websocket and checks for errors.
 | 
			
		||||
| 
						 | 
				
			
			@ -20,12 +53,11 @@ func Search(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.
 | 
			
		|||
	defer conn.Close()
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		search  string
 | 
			
		||||
		value   string
 | 
			
		||||
		search  *searchOptions
 | 
			
		||||
		message []byte
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	caseInsensitive := (r.URL.Query().Get("insensitive") == "true")
 | 
			
		||||
 | 
			
		||||
	// Starts an infinite loop until a valid command is captured.
 | 
			
		||||
	for {
 | 
			
		||||
		_, message, err = conn.ReadMessage()
 | 
			
		||||
| 
						 | 
				
			
			@ -34,15 +66,12 @@ func Search(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if len(message) != 0 {
 | 
			
		||||
			search = string(message)
 | 
			
		||||
			value = string(message)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if caseInsensitive {
 | 
			
		||||
		search = strings.ToLower(search)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	search = parseSearch(value)
 | 
			
		||||
	scope := strings.Replace(r.URL.Path, c.BaseURL, "", 1)
 | 
			
		||||
	scope = strings.TrimPrefix(scope, "/")
 | 
			
		||||
	scope = "/" + scope
 | 
			
		||||
| 
						 | 
				
			
			@ -51,22 +80,25 @@ func Search(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.
 | 
			
		|||
	scope = filepath.Clean(scope)
 | 
			
		||||
 | 
			
		||||
	err = filepath.Walk(scope, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if caseInsensitive {
 | 
			
		||||
		if search.CaseInsensitive {
 | 
			
		||||
			path = strings.ToLower(path)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if strings.Contains(path, search) {
 | 
			
		||||
			if !u.Allowed(path) {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		path = strings.Replace(path, "\\", "/", -1)
 | 
			
		||||
 | 
			
		||||
			path = strings.TrimPrefix(path, scope)
 | 
			
		||||
			path = strings.Replace(path, "\\", "/", -1)
 | 
			
		||||
			path = strings.TrimPrefix(path, "/")
 | 
			
		||||
		for _, term := range search.Terms {
 | 
			
		||||
			if strings.Contains(path, term) {
 | 
			
		||||
				if !u.Allowed(path) {
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			err = conn.WriteMessage(websocket.TextMessage, []byte(path))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
				path = strings.TrimPrefix(path, scope)
 | 
			
		||||
				path = strings.TrimPrefix(path, "/")
 | 
			
		||||
 | 
			
		||||
				err = conn.WriteMessage(websocket.TextMessage, []byte(path))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue