Skip to content

Commit 7e4e966

Browse files
authored
Auto update notifications (#773)
1 parent f867716 commit 7e4e966

File tree

18 files changed

+259
-59
lines changed

18 files changed

+259
-59
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. For commit
44

55
## v0.7.9-beta
66

7+
**New Features**:
8+
- Admin users will get a small notification banner for available update in sidebar with link to new release.
9+
710
**Notes**:
811
- docker now defaults to ./data/databse.db as the database path allowing a simplified initial docker-compose.yaml. Existing configurations do not need updating.
912
- oidc groups header updates admin permission of existing user (either add/remove if role exists)'

README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@
1818
> [!WARNING]
1919
> There is no stable version -- planned for 2025. ([Read more](https://github.com/gtsteffaniak/filebrowser/discussions/628))
2020
21+
## About
22+
23+
FileBrowser Quantum provide a simple and easy way to access and manage your files from a web-based app. It allows you to create secure shared links, users with their own specific permissions and settings, and a great viewing experience for many file types.
24+
25+
This version is called "Quantum" because it packs tons of advanced features into a tiny easy to run file. Unlike the majority of alternative options, FileBrowser Quantum is simple to install and easy to configure.
26+
27+
The goal for this repo is to become the best open-source self-hosted file browsing application that exists -- **all for free**. This repo will always be free and open-source.
28+
29+
For more, see the [Q&A Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Q&A)
30+
31+
## How its different
32+
2133
FileBrowser Quantum is a massive fork of the file browser open-source project with the following changes:
2234

2335
1. ✅ Multiple sources support
@@ -43,18 +55,11 @@ Notable features that this fork *does not* have (removed):
4355
- ❌ rules are not supported yet (planned).
4456
- ❌ shell commands are completely removed and will not be returned.
4557

46-
## About
58+
> [!WARNING]
59+
> Every file and directory in the source gets indexed (by default). This enables powerful features such as instant search, but large source filesystems can increase your system requirements. [See indexing wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Indexing) for more info.
4760
4861
FileBrowser Quantum differs significantly from the original version. Many of these changes required a significant overhaul. Creating a fork was a necessary process to make the program better. There have been many growing pains, but a stable release is planned and coming soon.
4962

50-
This version is called "Quantum" because it packs tons of advanced features in a tiny executable file. Unlike the majority of alternative options, FileBrowser Quantum is simple to install and easy to configure.
51-
52-
The goal for this repo is to become the best open-source self-hosted file browsing application that exists -- **all for free**.
53-
54-
This repo will always be free and open-source.
55-
56-
For more, see the [Q&A Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Q&A)
57-
5863
## The UI
5964

6065
The UI has a simple three-component navigation system:

backend/cmd/root.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/gtsteffaniak/filebrowser/backend/adapters/fs/fileutils"
1313
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
14+
"github.com/gtsteffaniak/filebrowser/backend/common/utils"
1415
"github.com/gtsteffaniak/filebrowser/backend/common/version"
1516
"github.com/gtsteffaniak/filebrowser/backend/database/storage"
1617
fbhttp "github.com/gtsteffaniak/filebrowser/backend/http"
@@ -52,6 +53,15 @@ func StartFilebrowser() {
5253
if !keepGoing {
5354
return
5455
}
56+
info, err := utils.CheckForUpdates()
57+
if err != nil {
58+
logger.Errorf("Error checking for updates: %v", err)
59+
} else if info.LatestVersion != "" {
60+
logger.Infof("A new version is available: %s (current: %s)", info.LatestVersion, info.CurrentVersion)
61+
logger.Infof("Release notes: %s", info.ReleaseNotes)
62+
}
63+
go utils.StartCheckForUpdates()
64+
5565
// Create context and channels for graceful shutdown
5666
ctx, cancel := context.WithCancel(context.Background())
5767
defer cancel()

backend/common/settings/structs.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,23 @@ type ExternalLink struct {
113113
// UserDefaults is a type that holds the default values
114114
// for some fields on User.
115115
type UserDefaults struct {
116-
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
117-
DarkMode bool `json:"darkMode"` // should dark mode be enabled
118-
Locale string `json:"locale"` // language to use: eg. de, en, or fr
119-
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
120-
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
121-
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
122-
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
123-
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
124-
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
125-
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
126-
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
127-
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
128-
LockPassword bool `json:"lockPassword"` // disable the user from changing their password
129-
DisableSettings bool `json:"disableSettings,omitempty"` // disable the user from viewing the settings page
130-
Preview users.Preview `json:"preview"`
131-
DefaultScopes []users.SourceScope `json:"-"`
132-
Permissions users.Permissions `json:"permissions"`
133-
LoginMethod string `json:"loginMethod,omitempty"` // login method to use: eg. password, proxy, oidc
116+
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
117+
DarkMode bool `json:"darkMode"` // should dark mode be enabled
118+
Locale string `json:"locale"` // language to use: eg. de, en, or fr
119+
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
120+
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
121+
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
122+
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
123+
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
124+
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
125+
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
126+
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
127+
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
128+
LockPassword bool `json:"lockPassword"` // disable the user from changing their password
129+
DisableSettings bool `json:"disableSettings,omitempty"` // disable the user from viewing the settings page
130+
Preview users.Preview `json:"preview"`
131+
DefaultScopes []users.SourceScope `json:"-"`
132+
Permissions users.Permissions `json:"permissions"`
133+
LoginMethod string `json:"loginMethod,omitempty"` // login method to use: eg. password, proxy, oidc
134+
DisableUpdateNotifications bool `json:"disableUpdateNotifications"` // disable update notifications banner for admin users
134135
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package utils
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"strings"
8+
"time"
9+
10+
"github.com/gtsteffaniak/filebrowser/backend/common/version"
11+
"github.com/gtsteffaniak/go-logger/logger"
12+
"golang.org/x/mod/semver"
13+
)
14+
15+
var updateAvailableUrl = ""
16+
17+
type Tag struct {
18+
Name string `json:"name"`
19+
}
20+
21+
type updateInfo struct {
22+
LatestVersion string
23+
CurrentVersion string
24+
ReleaseNotes string
25+
ReleaseUrl string
26+
}
27+
28+
func CheckForUpdates() (updateInfo, error) {
29+
// --- Configuration ---
30+
repoOwner := "gtsteffaniak"
31+
repoName := "filebrowser"
32+
currentVersion := version.Version
33+
splitVersion := strings.Split(currentVersion, "-")
34+
versionCategory := "stable"
35+
if len(splitVersion) > 1 {
36+
versionCategory = splitVersion[1]
37+
}
38+
githubApiUrl := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", repoOwner, repoName)
39+
// Make the GET request
40+
resp, err := http.Get(githubApiUrl)
41+
if err != nil {
42+
return updateInfo{}, err
43+
}
44+
defer resp.Body.Close()
45+
46+
if resp.StatusCode != http.StatusOK {
47+
return updateInfo{}, fmt.Errorf("failed to fetch tags from GitHub API")
48+
}
49+
// Decode the JSON response
50+
var tags []Tag
51+
if err := json.NewDecoder(resp.Body).Decode(&tags); err != nil {
52+
return updateInfo{}, err
53+
}
54+
// Find the latest beta version greater than the current one
55+
var NewVersion string
56+
for _, tag := range tags {
57+
// Check if the version is valid, is a pre-release, and contains "beta"
58+
if semver.IsValid(tag.Name) && strings.Contains(semver.Prerelease(tag.Name), versionCategory) {
59+
// Check if this tag is greater than the current version
60+
// and also greater than any other beta version we've found so far
61+
if semver.Compare(tag.Name, currentVersion) > 0 {
62+
if NewVersion == "" || semver.Compare(tag.Name, NewVersion) > 0 {
63+
NewVersion = tag.Name
64+
}
65+
}
66+
}
67+
}
68+
if NewVersion == "" {
69+
// No newer version found, return empty updateInfo
70+
return updateInfo{}, fmt.Errorf("no newer version found for %s", currentVersion)
71+
}
72+
73+
updateAvailableUrl = fmt.Sprintf("https://github.com/%s/%s/releases/tag/%s", repoOwner, repoName, NewVersion)
74+
return updateInfo{
75+
LatestVersion: NewVersion,
76+
CurrentVersion: currentVersion,
77+
ReleaseNotes: updateAvailableUrl,
78+
ReleaseUrl: updateAvailableUrl,
79+
}, nil
80+
}
81+
82+
func GetUpdateAvailableUrl() string {
83+
return updateAvailableUrl
84+
}
85+
86+
// starts a background process to check for updates periodically.
87+
func StartCheckForUpdates() {
88+
// Create a ticker that fires every 24 hours.
89+
ticker := time.NewTicker(24 * time.Hour)
90+
defer ticker.Stop()
91+
// Start a loop that waits for the ticker to fire.
92+
for range ticker.C {
93+
_, err := CheckForUpdates()
94+
if err != nil {
95+
// In a real application, you might want more sophisticated logging.
96+
logger.Debug("update check failed:", err)
97+
continue // Don't stop the loop, just wait for the next tick.
98+
}
99+
// Update the global variable with the result of the check.
100+
// This will be an empty string if no newer version was found.
101+
}
102+
}

backend/database/users/users.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,22 @@ type SourceScope struct {
7575

7676
// json tags must match variable name with smaller case first letter
7777
type NonAdminEditable struct {
78-
Preview Preview `json:"preview"`
79-
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
80-
DarkMode bool `json:"darkMode"` // should dark mode be enabled
81-
Password string `json:"password,omitempty"`
82-
Locale string `json:"locale"` // language to use: eg. de, en, or fr
83-
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
84-
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
85-
Sorting Sorting `json:"sorting"`
86-
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
87-
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
88-
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
89-
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
90-
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
91-
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
92-
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
78+
Preview Preview `json:"preview"`
79+
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
80+
DarkMode bool `json:"darkMode"` // should dark mode be enabled
81+
Password string `json:"password,omitempty"`
82+
Locale string `json:"locale"` // language to use: eg. de, en, or fr
83+
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
84+
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
85+
Sorting Sorting `json:"sorting"`
86+
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
87+
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
88+
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
89+
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
90+
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
91+
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
92+
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
93+
DisableUpdateNotifications bool `json:"disableUpdateNotifications"` // disable update notifications
9394
}
9495

9596
var PublicUser = User{

backend/go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUP
327327
github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s=
328328
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE=
329329
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY=
330+
github.com/golangci/golangci-lint v1.64.8 h1:y5TdeVidMtBGG32zgSC7ZXTFNHrsJkDnpO4ItB3Am+I=
330331
github.com/golangci/golangci-lint/v2 v2.1.6 h1:LXqShFfAGM5BDzEOWD2SL1IzJAgUOqES/HRBsfKjI+w=
331332
github.com/golangci/golangci-lint/v2 v2.1.6/go.mod h1:EPj+fgv4TeeBq3TcqaKZb3vkiV5dP4hHHKhXhEhzci8=
332333
github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 h1:AkK+w9FZBXlU/xUmBtSJN1+tAI4FIvy5WtnUnY8e4p8=

backend/http/static.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"text/template"
1010

1111
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
12+
"github.com/gtsteffaniak/filebrowser/backend/common/utils"
1213
"github.com/gtsteffaniak/filebrowser/backend/common/version"
1314
)
1415

@@ -59,6 +60,7 @@ func handleWithStaticData(w http.ResponseWriter, r *http.Request, file, contentT
5960
"PasswordAvailable": config.Auth.Methods.PasswordAuth.Enabled,
6061
"MediaAvailable": config.Integrations.Media.FfmpegPath != "",
6162
"MuPdfAvailable": config.Server.MuPdfAvailable,
63+
"UpdateAvailable": utils.GetUpdateAvailableUrl(),
6264
}
6365

6466
b, err := json.Marshal(data)

backend/swagger/docs/docs.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2242,6 +2242,10 @@ const docTemplate = `{
22422242
"description": "disable the user from viewing the settings page",
22432243
"type": "boolean"
22442244
},
2245+
"disableUpdateNotifications": {
2246+
"description": "disable update notifications banner for admin users",
2247+
"type": "boolean"
2248+
},
22452249
"gallerySize": {
22462250
"description": "0-9 - the size of the gallery thumbnails",
22472251
"type": "integer"
@@ -2466,6 +2470,10 @@ const docTemplate = `{
24662470
"disableSettings": {
24672471
"type": "boolean"
24682472
},
2473+
"disableUpdateNotifications": {
2474+
"description": "disable update notifications",
2475+
"type": "boolean"
2476+
},
24692477
"gallerySize": {
24702478
"description": "0-9 - the size of the gallery thumbnails",
24712479
"type": "integer"

backend/swagger/docs/swagger.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,6 +2231,10 @@
22312231
"description": "disable the user from viewing the settings page",
22322232
"type": "boolean"
22332233
},
2234+
"disableUpdateNotifications": {
2235+
"description": "disable update notifications banner for admin users",
2236+
"type": "boolean"
2237+
},
22342238
"gallerySize": {
22352239
"description": "0-9 - the size of the gallery thumbnails",
22362240
"type": "integer"
@@ -2455,6 +2459,10 @@
24552459
"disableSettings": {
24562460
"type": "boolean"
24572461
},
2462+
"disableUpdateNotifications": {
2463+
"description": "disable update notifications",
2464+
"type": "boolean"
2465+
},
24582466
"gallerySize": {
24592467
"description": "0-9 - the size of the gallery thumbnails",
24602468
"type": "integer"

0 commit comments

Comments
 (0)