diff --git a/.gitignore b/.gitignore index 9fdd14b7..14907522 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ rice-box.go /frontend/package-lock.json /backend/vendor /backend/*.cov +/backend/test_config.yaml .DS_Store node_modules diff --git a/CHANGELOG.md b/CHANGELOG.md index 78966d50..b321a1ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version). +## v0.2.7 + + - **Change**: New sidebar style and behavior + - **Change**: make search view and button behavior more consistent. + - **Fix**: [upload file bug](https://github.com/gtsteffaniak/filebrowser/issues/153) + - **Fix**: user lock out bug introduced in 0.2.6 + - **Fix**: many minor state related issues. + ## v0.2.6 This change focuses on minimizing and simplifying build process. diff --git a/README.md b/README.md index 47836c91..5d411b3a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ License: Apache-2.0

- +

Filebrowser - A modern web-based file manager

@@ -10,10 +10,13 @@

> [!WARNING] -> Starting with v0.2.0, *ALL* configuration is done via `filebrowser.yaml` configuration file. -> Starting with v0.2.4 *ALL* share links need to be re-created (due to security fix). +> Starting with v0.2.0, *ALL* configuration is done via `filebrowser.yaml` +> configuration file. +> Starting with v0.2.4 *ALL* share links need to be re-created (due to +> security fix). -This fork makes the following significant changes to filebrowser for origin: +This fork makes the following significant changes to filebrowser for +origin: 1. [x] Better search - Lightning fast @@ -21,7 +24,8 @@ This fork makes the following significant changes to filebrowser for origin: - Works with more type filters - interactive results page. 2. [x] Revamped and simplified GUI navbar and sidebar menu. - - Additional compact view mode as well as refreshed view mode styles. + - Additional compact view mode as well as refreshed view mode + styles. 3. [x] Revamped configuration via `filebrowser.yml` config file. - More configurations possible at a per-user level - image @@ -34,12 +38,12 @@ It allows the creation of multiple users and each user can have its own directory. This repository is a fork, a collection of changes that make this program -work better in terms of asthetics and performance. Improved search, -simplified ui (without removing features) and more secure and up-to-date +work better in terms of asthetics and performance. Improved search, +simplified ui (without removing features) and more secure and up-to-date build are just a few examples. -This Implementation of filebrowser differs significantly to the original. -There are hundereds of thousands of lines changed and they are generally +This Implementation of filebrowser differs significantly to the original. +There are hundereds of thousands of lines changed and they are generally no longer compatible with eachother. This has been intentional -- the focus of this fork is on a few key principles: - Simplicity and improved user experience @@ -49,23 +53,24 @@ focus of this fork is on a few key principles: ## Look -One way you can observe the improved user experience is how I changed the UI. -The Navbar is simplified to a three component system : +One way you can observe the improved user experience is how I changed +the UI. The Navbar is simplified to a three component system : 1. (Left) The slide-out action panel button 2. (Middle) The powerful search bar. 3. (Right) The view change toggle. - -All other functions are moved either into the action menu or popup menus. -If the action is does not depend on context, it will exist in the slide-out action panel. -If the action is available based on context, it will showup as a popup menu. + +All other functions are moved either into the action menu or popup menus. +If the action is does not depend on context, it will exist in the slide-out +action panel. If the action is available based on context, it will showup as +a popup menu.

-image -image -image -image + image + image + image + image

## Install @@ -119,43 +124,67 @@ volumes: ``` -Not using docker (not recommended) (Must donwload asset with frontend directory next to filebrowser binary) +Not using docker (not recommended) + +Note: Must download asset with frontend directory next to filebrowser binary ``` -./filebrowser -f +./filebrowser -c ``` ## Configuration -All configuration is now done via a single configuration file: `filebrowser.yaml`, here is an example minimal [configuration file](./backend/filebrowser.yaml). +All configuration is now done via a single configuration file: +`filebrowser.yaml`, here is an example minimal [configuration +file](./backend/filebrowser.yaml). -View the [Configuration Help Page](./configuration.md) for available configuration options and other help. +View the [Configuration Help Page](./configuration.md) for available +configuration options and other help. ## Migration from filebrowser/filebrowser -If you are currently using filebrowser from the filebrowser/filebrowser repo, but want to try using this. I recommend you start fresh without reusing the database, but there are a few things you'll need to do if you must migrate: +If you are currently using filebrowser from the filebrowser/filebrowser +repo, but want to try using this. I recommend you start fresh without +reusing the database, but there are a few things you'll need to do if you +must migrate: 1. Create a configuration file as mentioned above. -2. Copy your database file from the original filebrowser to the path of the new one. -3. Update the configuration file to use the database (under server in filebrowser.yml) -4. If you are using docker, update the docker-compose file or docker run command to use the config file as described in the install section above. -5. If you are not using docker, just make sure you run filebrowser -f filebrowser.yml and have valid filebrowser config. +2. Copy your database file from the original filebrowser to the path of + the new one. +3. Update the configuration file to use the database (under server in + filebrowser.yml) +4. If you are using docker, update the docker-compose file or docker run + command to use the config file as described in the install section + above. +5. If you are not using docker, just make sure you run filebrowser -c + filebrowser.yml and have valid filebrowser config. -The filebrowser application should run with the same user and rules that you have from the original. But keep in mind the differences that are mentioned at the top of this readme. +The filebrowser application should run with the same user and rules that +you have from the original. But keep in mind the differences that are +mentioned at the top of this readme. ### background & help -The original project filebrowser/filebrowser used multiple different ways to configure the server. -This was confusing and difficult to work with from a user and from a developer's perspective. -So I completely redesigned the program to use one single human-readable config file. +The original project filebrowser/filebrowser used multiple different ways +to configure the server. This was confusing and difficult to work with +from a user and from a developer's perspective. So I completely redesigned +the program to use one single human-readable config file. -I understand many coming from the original fork may notice differences which make using this improved version more difficult. If you notice issues that you believe should be fixed, please open an issue here and it will very likely be addressed with a PR within a few weeks. +I understand many coming from the original fork may notice differences +which make using this improved version more difficult. If you notice +issues that you believe should be fixed, please open an issue here and it +will very likely be addressed with a PR within a few weeks. -This version of filebrowser is going through a configuration overhaul as mentioned above. Certain features related to rules and commands may not work as they do on the original filebrowser. The purpose of this is to create a more consistent experience where configuration is done via files rather than running commands, so that it's very clear what the current state of the configuration is. When running commands its not clear what the configuration is. +This version of filebrowser is going through a configuration overhaul as +mentioned above. Certain features related to rules and commands may not +work as they do on the original filebrowser. The purpose of this is to +create a more consistent experience where configuration is done via files +rather than running commands, so that it's very clear what the current +state of the configuration is. When running commands its not clear what +the configuration is. ## Roadmap see [Roadmap Page](./roadmap.md) - diff --git a/backend/http/public.go b/backend/http/public.go index 9d204d2a..1eac9291 100644 --- a/backend/http/public.go +++ b/backend/http/public.go @@ -46,7 +46,7 @@ var withHashFile = func(fn handleFunc) handleFunc { Fs: fsPath, Path: lastComponent, Modify: d.user.Perm.Modify, - Expand: false, + Expand: true, ReadHeader: d.server.TypeDetectionByHeader, Checker: d, Token: link.Token, diff --git a/backend/http/users.go b/backend/http/users.go index 603ce0d2..893d2b19 100644 --- a/backend/http/users.go +++ b/backend/http/users.go @@ -4,6 +4,7 @@ import ( "encoding/json" "log" "net/http" + "reflect" "sort" "strconv" @@ -155,30 +156,24 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request return http.StatusBadRequest, nil } - if len(req.Which) == 0 || (len(req.Which) == 1 && req.Which[0] == "all") { - if !d.user.Perm.Admin { - return http.StatusForbidden, nil - } - - if req.Data.Password != "" { - req.Data.Password, err = users.HashPwd(req.Data.Password) - } else { - var suser *users.User - suser, err = d.store.Users.Get(d.server.Root, d.raw.(uint)) - req.Data.Password = suser.Password - } - - if err != nil { - return http.StatusInternalServerError, err - } - + if len(req.Which) == 0 || req.Which[0] == "all" { req.Which = []string{} + v := reflect.ValueOf(req.Data) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + t := v.Type() + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + if field.Name != "Password" && field.Name != "Fs" { + req.Which = append(req.Which, field.Name) + } + } } for k, v := range req.Which { v = cases.Title(language.English, cases.NoLower).String(v) req.Which[k] = v - if v == "Password" { if !d.user.Perm.Admin && d.user.LockPassword { return http.StatusForbidden, nil @@ -195,7 +190,6 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request } } } - err = d.store.Users.Update(req.Data, req.Which...) if err != nil { return http.StatusInternalServerError, err diff --git a/backend/settings/config.go b/backend/settings/config.go index 023ca631..7c856b76 100644 --- a/backend/settings/config.go +++ b/backend/settings/config.go @@ -71,6 +71,7 @@ func setDefaults() Settings { }, }, UserDefaults: UserDefaults{ + StickySidebar: true, Scope: ".", LockPassword: false, HideDotfiles: true, @@ -92,6 +93,7 @@ func setDefaults() Settings { // Apply applies the default options to a user. func (d *UserDefaults) Apply(u *users.User) { + u.StickySidebar = d.StickySidebar u.DisableSettings = d.DisableSettings u.DarkMode = d.DarkMode u.Scope = d.Scope diff --git a/backend/settings/structs.go b/backend/settings/structs.go index c6b54266..7d9e7914 100644 --- a/backend/settings/structs.go +++ b/backend/settings/structs.go @@ -68,6 +68,7 @@ type Frontend struct { // UserDefaults is a type that holds the default values // for some fields on User. type UserDefaults struct { + StickySidebar bool `json:"stickySidebar"` DarkMode bool `json:"darkMode"` LockPassword bool `json:"lockPassword"` DisableSettings bool `json:"disableSettings,omitempty"` diff --git a/backend/storage/bolt/users.go b/backend/storage/bolt/users.go index a6485ecf..64e9490d 100644 --- a/backend/storage/bolt/users.go +++ b/backend/storage/bolt/users.go @@ -55,7 +55,6 @@ func (st usersBackend) Update(user *users.User, fields ...string) error { if len(fields) == 0 { return st.Save(user) } - for _, field := range fields { userField := reflect.ValueOf(user).Elem().FieldByName(field) if !userField.IsValid() { @@ -63,10 +62,9 @@ func (st usersBackend) Update(user *users.User, fields ...string) error { } val := userField.Interface() if err := st.db.UpdateField(user, field, val); err != nil { - return err + return fmt.Errorf("Error updating user field: %s, error: %v", field, err.Error()) } } - return nil } diff --git a/backend/users/users.go b/backend/users/users.go index e08692a3..50a94a74 100644 --- a/backend/users/users.go +++ b/backend/users/users.go @@ -28,6 +28,7 @@ type Sorting struct { // User describes a user. type User struct { + StickySidebar bool `json:"stickySidebar"` DarkMode bool `json:"darkMode"` DisableSettings bool `json:"disableSettings"` ID uint `storm:"id,increment" json:"id"` diff --git a/frontend/src/api/users.js b/frontend/src/api/users.js index 34a4bb12..6a827713 100644 --- a/frontend/src/api/users.js +++ b/frontend/src/api/users.js @@ -24,6 +24,10 @@ export async function create(user) { } export async function update(user, which = ["all"]) { + if (which[0] != "password") { + user.password = ""; + } + console.log("updating user",user,which) await fetchURL(`/api/users/${user.id}`, { method: "PUT", body: JSON.stringify({ diff --git a/frontend/src/components/ButtonGroup.vue b/frontend/src/components/ButtonGroup.vue index ffc92848..78e4d6bf 100644 --- a/frontend/src/components/ButtonGroup.vue +++ b/frontend/src/components/ButtonGroup.vue @@ -1,14 +1,18 @@ @@ -103,6 +107,10 @@ button:hover { background: #e0e0e0; } +button:disabled { + cursor: not-allowed !important; +} + button.active { background-color: var(--blue) !important; color: #ffffff; diff --git a/frontend/src/components/FileSelection.vue b/frontend/src/components/FileSelection.vue new file mode 100644 index 00000000..e13db4f5 --- /dev/null +++ b/frontend/src/components/FileSelection.vue @@ -0,0 +1,168 @@ + + + + diff --git a/frontend/src/components/Search.vue b/frontend/src/components/Search.vue index 2985f88a..14233098 100644 --- a/frontend/src/components/Search.vue +++ b/frontend/src/components/Search.vue @@ -101,39 +101,6 @@
Search Context: {{ getContext }}
- -

- autorenew -

- -
-

{{ noneMessage }}

-
Help
-
- -
-

- Search occurs on each character you type (3 character minimum for search - terms). -

-

- The index: Search utilizes the index which automatically gets updated - on the configured interval (default: 5 minutes). Searching when the program - has just started may result in incomplete results. -

-

- Filter by type: You can have multiple type filters by adding - type:condition followed by search terms. -

-

- Multiple Search terms: Additional terms separated by |, - for example "test|not" searches for both terms independently. -

-

- File size: Searching files by size may have significantly longer - search times. -

-
-
+

Smaller Than:

+ +

+ autorenew +

+ +
+

{{ noneMessage }}

+
Help
+
+ +
+

+ Search occurs on each character you type (3 character minimum for search + terms). +

+

+ The index: Search utilizes the index which automatically gets updated + on the configured interval (default: 5 minutes). Searching when the program + has just started may result in incomplete results. +

+

+ Filter by type: You can have multiple type filters by adding + type:condition followed by search terms. +

+

+ Multiple Search terms: Additional terms separated by |, + for example "test|not" searches for both terms independently. +

+

+ File size: Searching files by size may have significantly longer search + times. +

+
  • * { border-bottom-left-radius: 0; } +input.sizeInput:disabled { + cursor: not-allowed; +} + /* Search Input Placeholder */ #search::-webkit-input-placeholder { color: rgba(255, 255, 255, 0.5); diff --git a/frontend/src/components/Sidebar.vue b/frontend/src/components/Sidebar.vue index be8b388f..d2c80d68 100644 --- a/frontend/src/components/Sidebar.vue +++ b/frontend/src/components/Sidebar.vue @@ -1,18 +1,48 @@ diff --git a/frontend/src/components/prompts/UploadFiles.vue b/frontend/src/components/prompts/UploadFiles.vue deleted file mode 100644 index 8a7a9823..00000000 --- a/frontend/src/components/prompts/UploadFiles.vue +++ /dev/null @@ -1,65 +0,0 @@ - - diff --git a/frontend/src/components/settings/Languages.vue b/frontend/src/components/settings/Languages.vue index 6e2f7903..7591adb6 100644 --- a/frontend/src/components/settings/Languages.vue +++ b/frontend/src/components/settings/Languages.vue @@ -1,12 +1,12 @@ - + + \ No newline at end of file diff --git a/frontend/src/views/files/Preview.vue b/frontend/src/views/files/Preview.vue index fa500533..3e5a5b1a 100644 --- a/frontend/src/views/files/Preview.vue +++ b/frontend/src/views/files/Preview.vue @@ -155,6 +155,9 @@ export default { }, watch: { $route() { + if (!getters.isLoggedIn()) { + return; + } this.updatePreview(); this.toggleNavigation(); }, diff --git a/frontend/src/views/settings/Profile.vue b/frontend/src/views/settings/Profile.vue index 1baf5e2d..63307e0e 100644 --- a/frontend/src/views/settings/Profile.vue +++ b/frontend/src/views/settings/Profile.vue @@ -85,7 +85,7 @@