From c4ccfd48f510f4bc33b649ee10fb98eb978e5475 Mon Sep 17 00:00:00 2001 From: Graham Steffaniak <42989099+gtsteffaniak@users.noreply.github.com> Date: Sun, 16 Feb 2025 09:07:38 -0500 Subject: [PATCH] Beta/v0.5.3 (#374) --- .github/workflows/regular-tests.yaml | 2 +- .github/workflows/release_beta.yaml | 2 +- .github/workflows/release_stable.yaml | 2 +- CHANGELOG.md | 21 + README.md | 3 + _docker/Dockerfile | 2 +- backend/files/file.go | 73 +-- backend/files/indexingFiles.go | 6 +- backend/files/indexingSchedule.go | 12 +- backend/files/mime.go | 612 ++++++++++++++++++ backend/fileutils/file.go | 7 - backend/go.mod | 6 +- backend/go.sum | 16 +- backend/http/auth.go | 2 +- backend/http/middleware.go | 2 +- backend/http/middleware_test.go | 4 +- backend/http/onlyOffice.go | 4 +- backend/http/preview.go | 2 +- backend/http/raw.go | 3 +- backend/img/service.go | 2 +- backend/runner/commands.go | 2 +- backend/runner/runner.go | 4 +- backend/settings/config.go | 21 +- backend/settings/settings_test.go | 2 +- backend/settings/structs.go | 15 +- backend/storage/bolt/auth.go | 2 +- backend/storage/bolt/bolt.go | 2 +- backend/storage/bolt/config.go | 2 +- backend/storage/bolt/share.go | 2 +- backend/storage/bolt/users.go | 2 +- backend/storage/bolt/utils.go | 2 +- backend/storage/storage.go | 2 +- backend/swagger/docs/docs.go | 6 + backend/swagger/docs/swagger.json | 6 + backend/swagger/docs/swagger.yaml | 4 + backend/users/users.go | 47 +- frontend/package.json | 2 + frontend/src/api/files.js | 305 ++++----- frontend/src/api/utils.js | 7 +- frontend/src/api/utils.test.js | 14 +- frontend/src/components/ContextMenu.vue | 57 +- frontend/src/components/Search.vue | 2 +- frontend/src/components/prompts/Copy.vue | 4 +- frontend/src/components/prompts/Delete.vue | 17 +- .../src/components/prompts/DeleteUser.vue | 2 +- frontend/src/components/prompts/FileList.vue | 2 +- frontend/src/components/prompts/Info.vue | 4 +- frontend/src/components/prompts/Move.vue | 4 +- frontend/src/components/prompts/Rename.vue | 4 +- frontend/src/components/prompts/Share.vue | 2 +- frontend/src/components/settings/Rules.vue | 63 -- frontend/src/components/sidebar/General.vue | 2 + frontend/src/components/sidebar/Sidebar.vue | 6 +- frontend/src/css/base.css | 4 +- frontend/src/css/header.css | 11 +- frontend/src/notify/loadingSpinner.js | 5 +- frontend/src/store/getters.js | 18 +- frontend/src/store/state.js | 1 + frontend/src/utils/files.js | 7 + frontend/src/utils/subtitles.js | 190 ++++++ frontend/src/utils/upload.js | 23 +- frontend/src/utils/url.js | 9 +- frontend/src/views/Files.vue | 12 +- frontend/src/views/bars/EditorBar.vue | 2 +- frontend/src/views/files/Editor.vue | 2 +- frontend/src/views/files/ListingView.vue | 45 +- frontend/src/views/files/MarkdownViewer.vue | 4 +- frontend/src/views/files/Preview.vue | 135 ++-- frontend/src/views/settings/Profile.vue | 40 ++ frontend/tests/file-actions.spec.ts | 47 +- frontend/tests/navigation.spec.ts | 14 + frontend/tests/playwright-files/deleteme.txt | 0 .../playwright-files/folder#hash/file#.sh | 0 73 files changed, 1461 insertions(+), 509 deletions(-) create mode 100644 backend/files/mime.go delete mode 100644 frontend/src/components/settings/Rules.vue create mode 100644 frontend/src/utils/files.js create mode 100644 frontend/src/utils/subtitles.js create mode 100644 frontend/tests/navigation.spec.ts create mode 100644 frontend/tests/playwright-files/deleteme.txt create mode 100644 frontend/tests/playwright-files/folder#hash/file#.sh diff --git a/.github/workflows/regular-tests.yaml b/.github/workflows/regular-tests.yaml index b591e903..b9fb45cc 100644 --- a/.github/workflows/regular-tests.yaml +++ b/.github/workflows/regular-tests.yaml @@ -24,7 +24,7 @@ jobs: go-version: 'stable' - uses: golangci/golangci-lint-action@v5 with: - version: v1.60 + version: 'v1.64' working-directory: backend format-backend: runs-on: ubuntu-latest diff --git a/.github/workflows/release_beta.yaml b/.github/workflows/release_beta.yaml index daf5f6ba..ebd3fe4f 100644 --- a/.github/workflows/release_beta.yaml +++ b/.github/workflows/release_beta.yaml @@ -56,7 +56,7 @@ jobs: - name: Create Release uses: softprops/action-gh-release@v2 with: - target_commitish: ${{ steps.extract_branch.outputs.branch_name }} + target_commitish: ${{ github.sha }} token: ${{ secrets.PAT }} tag_name: ${{ steps.extract_branch.outputs.tag_name }} prerelease: false # change this to false when stable gets released diff --git a/.github/workflows/release_stable.yaml b/.github/workflows/release_stable.yaml index 2792c396..423d1c66 100644 --- a/.github/workflows/release_stable.yaml +++ b/.github/workflows/release_stable.yaml @@ -56,7 +56,7 @@ jobs: - name: Create Release uses: softprops/action-gh-release@v2 with: - target_commitish: ${{ steps.extract_branch.outputs.branch_name }} + target_commitish: ${{ github.sha }} token: ${{ secrets.PAT }} tag_name: ${{ steps.extract_branch.outputs.tag_name }} prerelease: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ad3c575..f73244a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ 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.5.3-beta + + **New Features** + - onlyoffice disable filetypes for user specified file types. https://github.com/gtsteffaniak/filebrowser/issues/346 + + **Notes**: + - navbar/sidebar lightmode style tweaks. + - any item that has utf formatted text will get editor. + - tweaks to create options on context menu. + - removed small delay on preview before detecting the file. + + **BugFixes**: + - fix `/files/` prefix loading issue https://github.com/gtsteffaniak/filebrowser/issues/362 + - fix special characters in filename issue https://github.com/gtsteffaniak/filebrowser/issues/357 + - fix drag and drop issue https://github.com/gtsteffaniak/filebrowser/issues/361 + - fix conflict issue with creating same file after deletion. + - fix mimetype detection https://github.com/gtsteffaniak/filebrowser/issues/327 + - subtitles for videos https://github.com/gtsteffaniak/filebrowser/issues/358 + - supports caption sidecar files : ".vtt", ".srt", ".lrc", ".sbv", ".ass", ".ssa", ".sub", ".smi" + - embedded subtitles not yet supported. + ## v0.5.2-beta **New Features**: diff --git a/README.md b/README.md index 9f08095c..db7f0113 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,9 @@ [![DockerHub Pulls](https://img.shields.io/docker/pulls/gtstef/filebrowser?label=latest%20Docker%20pulls)](https://hub.docker.com/r/gtstef/filebrowser) [![Apache-2.0 License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) + [![Poll](https://img.shields.io/badge/poll-vote_most_important_features-purple)](https://github.com/gtsteffaniak/filebrowser/discussions/368) + [![Donate with PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/donate/?business=W5XKNXHJM2WPE&no_recurring=0¤cy_code=USD) +

FileBrowser Quantum

A modern web-based file manager diff --git a/_docker/Dockerfile b/_docker/Dockerfile index 65b446dd..7afa75e4 100644 --- a/_docker/Dockerfile +++ b/_docker/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23-alpine AS base +FROM golang:1.24-alpine AS base ARG VERSION ARG REVISION WORKDIR /app diff --git a/backend/files/file.go b/backend/files/file.go index 65ff96a2..793b9ee9 100644 --- a/backend/files/file.go +++ b/backend/files/file.go @@ -24,6 +24,7 @@ import ( "github.com/gtsteffaniak/filebrowser/backend/cache" "github.com/gtsteffaniak/filebrowser/backend/errors" "github.com/gtsteffaniak/filebrowser/backend/fileutils" + "github.com/gtsteffaniak/filebrowser/backend/logger" "github.com/gtsteffaniak/filebrowser/backend/settings" "github.com/gtsteffaniak/filebrowser/backend/users" "github.com/gtsteffaniak/filebrowser/backend/utils" @@ -54,7 +55,7 @@ type FileInfo struct { // for efficiency, a response will be a pointer to the data // extra calculated fields can be added here type ExtendedFileInfo struct { - *FileInfo + FileInfo Content string `json:"content,omitempty"` // text content of a file, if requested Subtitles []string `json:"subtitles,omitempty"` // subtitles for video files Checksums map[string]string `json:"checksums,omitempty"` // checksums for the file @@ -129,7 +130,7 @@ func FileInfoFaster(opts FileOptions) (ExtendedFileInfo, error) { } info, exists := index.GetReducedMetadata(opts.Path, opts.IsDir) if !exists { - return response, err + return response, fmt.Errorf("could not get metadata for path: %v", opts.Path) } if opts.Content { content, err := getContent("default", opts.Path) @@ -138,11 +139,15 @@ func FileInfoFaster(opts FileOptions) (ExtendedFileInfo, error) { } response.Content = content } - response.FileInfo = info + response.FileInfo = *info response.RealPath = realPath + response.Source = opts.Source if settings.Config.Integrations.OnlyOffice.Secret != "" && info.Type != "directory" && isOnlyOffice(info.Name) { response.OnlyOfficeId = generateOfficeId(realPath) } + if strings.HasPrefix(info.Type, "video") { + response.detectSubtitles(realPath) + } return response, nil } @@ -365,42 +370,32 @@ func (i *ItemInfo) DetectType(realPath string, saveContent bool) { // TODO add subtitles back // detectSubtitles detects subtitles for video files. -//func (i *FileInfo) detectSubtitles(path string) { -// if i.Type != "video" { -// return -// } -// parentDir := filepath.Dir(path) -// fileName := filepath.Base(path) -// i.Subtitles = []string{} -// ext := filepath.Ext(fileName) -// dir, err := os.Open(parentDir) -// if err != nil { -// // Directory must have been deleted, remove it from the index -// return -// } -// defer dir.Close() // Ensure directory handle is closed -// -// files, err := dir.Readdir(-1) -// if err != nil { -// return -// } -// -// base := strings.TrimSuffix(fileName, ext) -// subtitleExts := []string{".vtt", ".txt", ".srt", ".lrc"} -// -// for _, f := range files { -// if f.IsDir() || !strings.HasPrefix(f.Name(), base) { -// continue -// } -// -// for _, subtitleExt := range subtitleExts { -// if strings.HasSuffix(f.Name(), subtitleExt) { -// i.Subtitles = append(i.Subtitles, filepath.Join(parentDir, f.Name())) -// break -// } -// } -// } -//} +func (i *ExtendedFileInfo) detectSubtitles(path string) { + if !strings.HasPrefix(i.Type, "video") { + logger.Debug("subtitles are not supported for this file : " + path) + return + } + + idx := GetIndex(i.Source) + parentInfo, exists := idx.GetReducedMetadata(filepath.Dir(i.Path), true) + if !exists { + return + } + base := strings.Split(i.Name, ".")[0] + for _, f := range parentInfo.Files { + baseName := strings.Split(f.Name, ".")[0] + if baseName != base { + continue + } + + for _, subtitleExt := range []string{".vtt", ".srt", ".lrc", ".sbv", ".ass", ".ssa", ".sub", ".smi"} { + if strings.HasSuffix(f.Name, subtitleExt) { + fullPathBase := strings.Split(i.Path, ".")[0] + i.Subtitles = append(i.Subtitles, fullPathBase+subtitleExt) + } + } + } +} func IsNamedPipe(mode os.FileMode) bool { return mode&os.ModeNamedPipe != 0 diff --git a/backend/files/indexingFiles.go b/backend/files/indexingFiles.go index fb005d2a..6f6d28c4 100644 --- a/backend/files/indexingFiles.go +++ b/backend/files/indexingFiles.go @@ -54,11 +54,11 @@ func Initialize(source settings.Source) { if !newIndex.Source.Config.Disabled { time.Sleep(time.Second) - logger.Info("Initializing index and assessing file system complexity") + logger.Info(fmt.Sprintf("initializing index: [%v]", newIndex.Source.Name)) newIndex.RunIndexing("/", false) go newIndex.setupIndexingScanners() } else { - logger.Debug("Indexing disabled for source: " + newIndex.Source.Name) + logger.Debug("indexing disabled for source: " + newIndex.Source.Name) } } @@ -122,7 +122,7 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err // Process each file and directory in the current directory for _, file := range files { - isHidden := isHidden(file, idx.Path+combinedPath) + isHidden := isHidden(file, idx.Source.Path+combinedPath) isDir := file.IsDir() fullCombined := combinedPath + file.Name() if idx.shouldSkip(isDir, isHidden, fullCombined) { diff --git a/backend/files/indexingSchedule.go b/backend/files/indexingSchedule.go index 16a6aceb..25a4f5ca 100644 --- a/backend/files/indexingSchedule.go +++ b/backend/files/indexingSchedule.go @@ -76,9 +76,9 @@ func (idx *Index) RunIndexing(origin string, quick bool) { prevNumDirs := idx.NumDirs prevNumFiles := idx.NumFiles if quick { - logger.Debug("Starting quick scan") + logger.Debug(fmt.Sprintf("Starting quick scan for [%v]", idx.Source.Name)) } else { - logger.Debug("Starting full scan") + logger.Debug(fmt.Sprintf("Starting full scan for [%v]", idx.Source.Name)) idx.NumDirs = 0 idx.NumFiles = 0 } @@ -106,18 +106,18 @@ func (idx *Index) RunIndexing(origin string, quick bool) { idx.assessment = "normal" } if firstRun { - logger.Info(fmt.Sprintf("Index assessment : complexity=%v directories=%v files=%v", idx.assessment, idx.NumDirs, idx.NumFiles)) + logger.Info(fmt.Sprintf("Index assessment : index=%v complexity=%v directories=%v files=%v", idx.Source.Name, idx.assessment, idx.NumDirs, idx.NumFiles)) } else { - logger.Debug(fmt.Sprintf("Index assessment : complexity=%v directories=%v files=%v", idx.assessment, idx.NumDirs, idx.NumFiles)) + logger.Debug(fmt.Sprintf("Index assessment : iindex=%v complexity=%v directories=%v files=%v", idx.Source.Name, idx.assessment, idx.NumDirs, idx.NumFiles)) } if idx.NumDirs != prevNumDirs || idx.NumFiles != prevNumFiles { idx.FilesChangedDuringIndexing = true } } if firstRun { - logger.Info(fmt.Sprintf("Time spent indexing : %v seconds", idx.indexingTime)) + logger.Info(fmt.Sprintf("Time spent indexing [%v]: %v seconds", idx.Source.Name, idx.indexingTime)) } else { - logger.Debug(fmt.Sprintf("Time spent indexing : %v seconds", idx.indexingTime)) + logger.Debug(fmt.Sprintf("Time spent indexing [%v]: %v seconds", idx.Source.Name, idx.indexingTime)) } } diff --git a/backend/files/mime.go b/backend/files/mime.go new file mode 100644 index 00000000..1782fb72 --- /dev/null +++ b/backend/files/mime.go @@ -0,0 +1,612 @@ +package files + +// This file contains code primarily sourced from:: +// github.com/kataras/iris + +import ( + "mime" +) + +const ( + // ContentBinaryHeaderValue header value for binary data. + ContentBinaryHeaderValue = "application/octet-stream" + // ContentWebassemblyHeaderValue header value for web assembly files. + ContentWebassemblyHeaderValue = "application/wasm" + // ContentHTMLHeaderValue is the string of text/html response header's content type value. + ContentHTMLHeaderValue = "text/html" + // ContentJSONHeaderValue header value for JSON data. + ContentJSONHeaderValue = "application/json" + // ContentJSONProblemHeaderValue header value for JSON API problem error. + // Read more at: https://tools.ietf.org/html/rfc7807 + ContentJSONProblemHeaderValue = "application/problem+json" + // ContentXMLProblemHeaderValue header value for XML API problem error. + // Read more at: https://tools.ietf.org/html/rfc7807 + ContentXMLProblemHeaderValue = "application/problem+xml" + // ContentJavascriptHeaderValue header value for JSONP & Javascript data. + ContentJavascriptHeaderValue = "text/javascript" + // ContentTextHeaderValue header value for Text data. + ContentTextHeaderValue = "text/plain" + // ContentXMLHeaderValue header value for XML data. + ContentXMLHeaderValue = "text/xml" + // ContentXMLUnreadableHeaderValue obsolete header value for XML. + ContentXMLUnreadableHeaderValue = "application/xml" + // ContentMarkdownHeaderValue custom key/content type, the real is the text/html. + ContentMarkdownHeaderValue = "text/markdown" + // ContentYAMLHeaderValue header value for YAML data. + ContentYAMLHeaderValue = "application/x-yaml" + // ContentYAMLTextHeaderValue header value for YAML plain text. + ContentYAMLTextHeaderValue = "text/yaml" + // ContentProtobufHeaderValue header value for Protobuf messages data. + ContentProtobufHeaderValue = "application/x-protobuf" + // ContentMsgPackHeaderValue header value for MsgPack data. + ContentMsgPackHeaderValue = "application/msgpack" + // ContentMsgPack2HeaderValue alternative header value for MsgPack data. + ContentMsgPack2HeaderValue = "application/x-msgpack" + // ContentFormHeaderValue header value for post form data. + ContentFormHeaderValue = "application/x-www-form-urlencoded" + // ContentFormMultipartHeaderValue header value for post multipart form data. + ContentFormMultipartHeaderValue = "multipart/form-data" + // ContentMultipartRelatedHeaderValue header value for multipart related data. + ContentMultipartRelatedHeaderValue = "multipart/related" + // ContentGRPCHeaderValue Content-Type header value for gRPC. + ContentGRPCHeaderValue = "application/grpc" +) + +var types = map[string]string{ + ".3dm": "x-world/x-3dmf", + ".3dmf": "x-world/x-3dmf", + ".7z": "application/x-7z-compressed", + ".a": "application/octet-stream", + ".aab": "application/x-authorware-bin", + ".aam": "application/x-authorware-map", + ".aas": "application/x-authorware-seg", + ".abc": "text/vndabc", + ".ace": "application/x-ace-compressed", + ".acgi": "text/html", + ".afl": "video/animaflex", + ".ai": "application/postscript", + ".aif": "audio/aiff", + ".aifc": "audio/aiff", + ".aiff": "audio/aiff", + ".aim": "application/x-aim", + ".aip": "text/x-audiosoft-intra", + ".alz": "application/x-alz-compressed", + ".ani": "application/x-navi-animation", + ".aos": "application/x-nokia-9000-communicator-add-on-software", + ".aps": "application/mime", + ".apk": "application/vnd.android.package-archive", + ".arc": "application/x-arc-compressed", + ".arj": "application/arj", + ".art": "image/x-jg", + ".asf": "video/x-ms-asf", + ".asm": "text/x-asm", + ".asp": "text/asp", + ".asx": "application/x-mplayer2", + ".au": "audio/basic", + ".avi": "video/x-msvideo", + ".avs": "video/avs-video", + ".bcpio": "application/x-bcpio", + ".bin": "application/mac-binary", + ".bmp": "image/bmp", + ".boo": "application/book", + ".book": "application/book", + ".boz": "application/x-bzip2", + ".bsh": "application/x-bsh", + ".bz2": "application/x-bzip2", + ".bz": "application/x-bzip", + ".c++": ContentTextHeaderValue, + ".c": "text/x-c", + ".cab": "application/vnd.ms-cab-compressed", + ".cat": "application/vndms-pkiseccat", + ".cc": "text/x-c", + ".ccad": "application/clariscad", + ".cco": "application/x-cocoa", + ".cdf": "application/cdf", + ".cer": "application/pkix-cert", + ".cha": "application/x-chat", + ".chat": "application/x-chat", + ".chrt": "application/vnd.kde.kchart", + ".class": "application/java", + ".com": ContentTextHeaderValue, + ".conf": ContentTextHeaderValue, + ".cpio": "application/x-cpio", + ".cpp": "text/x-c", + ".cpt": "application/mac-compactpro", + ".crl": "application/pkcs-crl", + ".crt": "application/pkix-cert", + ".crx": "application/x-chrome-extension", + ".csh": "text/x-scriptcsh", + ".css": "text/css", + ".csv": "text/csv", + ".cxx": ContentTextHeaderValue, + ".dar": "application/x-dar", + ".dcr": "application/x-director", + ".deb": "application/x-debian-package", + ".deepv": "application/x-deepv", + ".def": ContentTextHeaderValue, + ".der": "application/x-x509-ca-cert", + ".dif": "video/x-dv", + ".dir": "application/x-director", + ".divx": "video/divx", + ".dl": "video/dl", + ".dmg": "application/x-apple-diskimage", + ".doc": "application/msword", + ".dot": "application/msword", + ".dp": "application/commonground", + ".drw": "application/drafting", + ".dump": "application/octet-stream", + ".dv": "video/x-dv", + ".dvi": "application/x-dvi", + ".dwf": "drawing/x-dwf=(old)", + ".dwg": "application/acad", + ".dxf": "application/dxf", + ".dxr": "application/x-director", + ".el": "text/x-scriptelisp", + ".elc": "application/x-bytecodeelisp=(compiled=elisp)", + ".eml": "message/rfc822", + ".env": "application/x-envoy", + ".eps": "application/postscript", + ".es": "application/x-esrehber", + ".etx": "text/x-setext", + ".evy": "application/envoy", + ".exe": "application/octet-stream", + ".f77": "text/x-fortran", + ".f90": "text/x-fortran", + ".f": "text/x-fortran", + ".fdf": "application/vndfdf", + ".fif": "application/fractals", + ".fli": "video/fli", + ".flo": "image/florian", + ".flv": "video/x-flv", + ".flx": "text/vndfmiflexstor", + ".fmf": "video/x-atomic3d-feature", + ".for": "text/x-fortran", + ".fpx": "image/vndfpx", + ".frl": "application/freeloader", + ".funk": "audio/make", + ".g3": "image/g3fax", + ".g": ContentTextHeaderValue, + ".gif": "image/gif", + ".gl": "video/gl", + ".gsd": "audio/x-gsm", + ".gsm": "audio/x-gsm", + ".gsp": "application/x-gsp", + ".gss": "application/x-gss", + ".gtar": "application/x-gtar", + ".gz": "application/x-compressed", + ".gzip": "application/x-gzip", + ".h": "text/x-h", + ".hdf": "application/x-hdf", + ".help": "application/x-helpfile", + ".hgl": "application/vndhp-hpgl", + ".hh": "text/x-h", + ".hlb": "text/x-script", + ".hlp": "application/hlp", + ".hpg": "application/vndhp-hpgl", + ".hpgl": "application/vndhp-hpgl", + ".hqx": "application/binhex", + ".hta": "application/hta", + ".htc": "text/x-component", + ".htm": "text/html", + ".html": "text/html", + ".htmls": "text/html", + ".htt": "text/webviewhtml", + ".htx": "text/html", + ".ice": "x-conference/x-cooltalk", + ".ico": "image/x-icon", + ".ics": "text/calendar", + ".icz": "text/calendar", + ".idc": ContentTextHeaderValue, + ".ief": "image/ief", + ".iefs": "image/ief", + ".iges": "application/iges", + ".igs": "application/iges", + ".ima": "application/x-ima", + ".imap": "application/x-httpd-imap", + ".inf": "application/inf", + ".ins": "application/x-internett-signup", + ".ip": "application/x-ip2", + ".isu": "video/x-isvideo", + ".it": "audio/it", + ".iv": "application/x-inventor", + ".ivr": "i-world/i-vrml", + ".ivy": "application/x-livescreen", + ".jam": "audio/x-jam", + ".jav": "text/x-java-source", + ".java": "text/x-java-source", + ".jcm": "application/x-java-commerce", + ".jfif-tbnl": "image/jpeg", + ".jfif": "image/jpeg", + ".jnlp": "application/x-java-jnlp-file", + ".jpe": "image/jpeg", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".jps": "image/x-jps", + ".js": ContentJavascriptHeaderValue, + ".mjs": ContentJavascriptHeaderValue, + ".json": ContentJSONHeaderValue, + ".vue": ContentJavascriptHeaderValue, + ".jut": "image/jutvision", + ".kar": "audio/midi", + ".karbon": "application/vnd.kde.karbon", + ".kfo": "application/vnd.kde.kformula", + ".flw": "application/vnd.kde.kivio", + ".kml": "application/vnd.google-earth.kml+xml", + ".kmz": "application/vnd.google-earth.kmz", + ".kon": "application/vnd.kde.kontour", + ".kpr": "application/vnd.kde.kpresenter", + ".kpt": "application/vnd.kde.kpresenter", + ".ksp": "application/vnd.kde.kspread", + ".kwd": "application/vnd.kde.kword", + ".kwt": "application/vnd.kde.kword", + ".ksh": "text/x-scriptksh", + ".la": "audio/nspaudio", + ".lam": "audio/x-liveaudio", + ".latex": "application/x-latex", + ".lha": "application/lha", + ".lhx": "application/octet-stream", + ".list": ContentTextHeaderValue, + ".lma": "audio/nspaudio", + ".log": ContentTextHeaderValue, + ".lsp": "text/x-scriptlisp", + ".lst": ContentTextHeaderValue, + ".lsx": "text/x-la-asf", + ".ltx": "application/x-latex", + ".lzh": "application/octet-stream", + ".lzx": "application/lzx", + ".m1v": "video/mpeg", + ".m2a": "audio/mpeg", + ".m2v": "video/mpeg", + ".m3u": "audio/x-mpegurl", + ".m": "text/x-m", + ".man": "application/x-troff-man", + ".manifest": "text/cache-manifest", + ".map": "application/x-navimap", + ".mar": ContentTextHeaderValue, + ".mbd": "application/mbedlet", + ".mc$": "application/x-magic-cap-package-10", + ".mcd": "application/mcad", + ".mcf": "text/mcf", + ".mcp": "application/netmc", + ".me": "application/x-troff-me", + ".mht": "message/rfc822", + ".mhtml": "message/rfc822", + ".mid": "application/x-midi", + ".midi": "application/x-midi", + ".mif": "application/x-frame", + ".mime": "message/rfc822", + ".mjf": "audio/x-vndaudioexplosionmjuicemediafile", + ".mjpg": "video/x-motion-jpeg", + ".mm": "application/base64", + ".mme": "application/base64", + ".mod": "audio/mod", + ".moov": "video/quicktime", + ".mov": "video/quicktime", + ".movie": "video/x-sgi-movie", + ".mp2": "audio/mpeg", + ".mp3": "audio/mpeg", + ".mp4": "video/mp4", + ".mpa": "audio/mpeg", + ".mpc": "application/x-project", + ".mpe": "video/mpeg", + ".mpeg": "video/mpeg", + ".mpg": "video/mpeg", + ".mpga": "audio/mpeg", + ".mpp": "application/vndms-project", + ".mpt": "application/x-project", + ".mpv": "application/x-project", + ".mpx": "application/x-project", + ".mrc": "application/marc", + ".ms": "application/x-troff-ms", + ".mv": "video/x-sgi-movie", + ".my": "audio/make", + ".mzz": "application/x-vndaudioexplosionmzz", + ".nap": "image/naplps", + ".naplps": "image/naplps", + ".nc": "application/x-netcdf", + ".ncm": "application/vndnokiaconfiguration-message", + ".nif": "image/x-niff", + ".niff": "image/x-niff", + ".nix": "application/x-mix-transfer", + ".nsc": "application/x-conference", + ".nvd": "application/x-navidoc", + ".o": "application/octet-stream", + ".oda": "application/oda", + ".odb": "application/vnd.oasis.opendocument.database", + ".odc": "application/vnd.oasis.opendocument.chart", + ".odf": "application/vnd.oasis.opendocument.formula", + ".odg": "application/vnd.oasis.opendocument.graphics", + ".odi": "application/vnd.oasis.opendocument.image", + ".odm": "application/vnd.oasis.opendocument.text-master", + ".odp": "application/vnd.oasis.opendocument.presentation", + ".ods": "application/vnd.oasis.opendocument.spreadsheet", + ".odt": "application/vnd.oasis.opendocument.text", + ".oga": "audio/ogg", + ".ogg": "audio/ogg", + ".ogv": "video/ogg", + ".omc": "application/x-omc", + ".omcd": "application/x-omcdatamaker", + ".omcr": "application/x-omcregerator", + ".otc": "application/vnd.oasis.opendocument.chart-template", + ".otf": "application/vnd.oasis.opendocument.formula-template", + ".otg": "application/vnd.oasis.opendocument.graphics-template", + ".oth": "application/vnd.oasis.opendocument.text-web", + ".oti": "application/vnd.oasis.opendocument.image-template", + ".otm": "application/vnd.oasis.opendocument.text-master", + ".otp": "application/vnd.oasis.opendocument.presentation-template", + ".ots": "application/vnd.oasis.opendocument.spreadsheet-template", + ".ott": "application/vnd.oasis.opendocument.text-template", + ".p10": "application/pkcs10", + ".p12": "application/pkcs-12", + ".p7a": "application/x-pkcs7-signature", + ".p7c": "application/pkcs7-mime", + ".p7m": "application/pkcs7-mime", + ".p7r": "application/x-pkcs7-certreqresp", + ".p7s": "application/pkcs7-signature", + ".p": "text/x-pascal", + ".part": "application/pro_eng", + ".pas": "text/pascal", + ".pbm": "image/x-portable-bitmap", + ".pcl": "application/vndhp-pcl", + ".pct": "image/x-pict", + ".pcx": "image/x-pcx", + ".pdb": "chemical/x-pdb", + ".pdf": "application/pdf", + ".pfunk": "audio/make", + ".pgm": "image/x-portable-graymap", + ".pic": "image/pict", + ".pict": "image/pict", + ".pkg": "application/x-newton-compatible-pkg", + ".pko": "application/vndms-pkipko", + ".pl": "text/x-scriptperl", + ".plx": "application/x-pixclscript", + ".pm4": "application/x-pagemaker", + ".pm5": "application/x-pagemaker", + ".pm": "text/x-scriptperl-module", + ".png": "image/png", + ".pnm": "application/x-portable-anymap", + ".pot": "application/mspowerpoint", + ".pov": "model/x-pov", + ".ppa": "application/vndms-powerpoint", + ".ppm": "image/x-portable-pixmap", + ".pps": "application/mspowerpoint", + ".ppt": "application/mspowerpoint", + ".ppz": "application/mspowerpoint", + ".pre": "application/x-freelance", + ".prt": "application/pro_eng", + ".ps": "application/postscript", + ".psd": "application/octet-stream", + ".pvu": "paleovu/x-pv", + ".pwz": "application/vndms-powerpoint", + ".py": "text/x-scriptphyton", + ".pyc": "application/x-bytecodepython", + ".qcp": "audio/vndqcelp", + ".qd3": "x-world/x-3dmf", + ".qd3d": "x-world/x-3dmf", + ".qif": "image/x-quicktime", + ".qt": "video/quicktime", + ".qtc": "video/x-qtc", + ".qti": "image/x-quicktime", + ".qtif": "image/x-quicktime", + ".ra": "audio/x-pn-realaudio", + ".ram": "audio/x-pn-realaudio", + ".rar": "application/x-rar-compressed", + ".ras": "application/x-cmu-raster", + ".rast": "image/cmu-raster", + ".rexx": "text/x-scriptrexx", + ".rf": "image/vndrn-realflash", + ".rgb": "image/x-rgb", + ".rm": "application/vndrn-realmedia", + ".rmi": "audio/mid", + ".rmm": "audio/x-pn-realaudio", + ".rmp": "audio/x-pn-realaudio", + ".rng": "application/ringing-tones", + ".rnx": "application/vndrn-realplayer", + ".roff": "application/x-troff", + ".rp": "image/vndrn-realpix", + ".rpm": "audio/x-pn-realaudio-plugin", + ".rt": "text/vndrn-realtext", + ".rtf": "text/richtext", + ".rtx": "text/richtext", + ".rv": "video/vndrn-realvideo", + ".s": "text/x-asm", + ".s3m": "audio/s3m", + ".s7z": "application/x-7z-compressed", + ".saveme": "application/octet-stream", + ".sbk": "application/x-tbook", + ".scm": "text/x-scriptscheme", + ".sdml": ContentTextHeaderValue, + ".sdp": "application/sdp", + ".sdr": "application/sounder", + ".sea": "application/sea", + ".set": "application/set", + ".sgm": "text/x-sgml", + ".sgml": "text/x-sgml", + ".sh": "text/x-scriptsh", + ".shar": "application/x-bsh", + ".shtml": "text/x-server-parsed-html", + ".sid": "audio/x-psid", + ".skd": "application/x-koan", + ".skm": "application/x-koan", + ".skp": "application/x-koan", + ".skt": "application/x-koan", + ".sit": "application/x-stuffit", + ".sitx": "application/x-stuffitx", + ".sl": "application/x-seelogo", + ".smi": "application/smil", + ".smil": "application/smil", + ".snd": "audio/basic", + ".sol": "application/solids", + ".spc": "text/x-speech", + ".spl": "application/futuresplash", + ".spr": "application/x-sprite", + ".sprite": "application/x-sprite", + ".spx": "audio/ogg", + ".src": "application/x-wais-source", + ".srt": "text/plain", + ".sbv": "text/plain", + ".ssa": "text/plain", + ".ssi": "text/x-server-parsed-html", + ".ssm": "application/streamingmedia", + ".sst": "application/vndms-pkicertstore", + ".step": "application/step", + ".stl": "application/sla", + ".stp": "application/step", + ".sv4cpio": "application/x-sv4cpio", + ".sv4crc": "application/x-sv4crc", + ".svf": "image/vnddwg", + ".svg": "image/svg+xml", + ".svr": "application/x-world", + ".swf": "application/x-shockwave-flash", + ".t": "application/x-troff", + ".talk": "text/x-speech", + ".tar": "application/x-tar", + ".tbk": "application/toolbook", + ".tcl": "text/x-scripttcl", + ".tcsh": "text/x-scripttcsh", + ".tex": "application/x-tex", + ".texi": "application/x-texinfo", + ".texinfo": "application/x-texinfo", + ".text": ContentTextHeaderValue, + ".tgz": "application/gnutar", + ".tif": "image/tiff", + ".tiff": "image/tiff", + ".tr": "application/x-troff", + ".tsi": "audio/tsp-audio", + ".tsp": "application/dsptype", + ".tsv": "text/tab-separated-values", + ".turbot": "image/florian", + ".txt": ContentTextHeaderValue, + ".uil": "text/x-uil", + ".uni": "text/uri-list", + ".unis": "text/uri-list", + ".unv": "application/i-deas", + ".uri": "text/uri-list", + ".uris": "text/uri-list", + ".ustar": "application/x-ustar", + ".uu": "text/x-uuencode", + ".uue": "text/x-uuencode", + ".vcd": "application/x-cdlink", + ".vcf": "text/x-vcard", + ".vcard": "text/x-vcard", + ".vcs": "text/x-vcalendar", + ".vda": "application/vda", + ".vdo": "video/vdo", + ".vew": "application/groupwise", + ".viv": "video/vivo", + ".vivo": "video/vivo", + ".vmd": "application/vocaltec-media-desc", + ".vmf": "application/vocaltec-media-file", + ".voc": "audio/voc", + ".vos": "video/vosaic", + ".vox": "audio/voxware", + ".vqe": "audio/x-twinvq-plugin", + ".vqf": "audio/x-twinvq", + ".vql": "audio/x-twinvq-plugin", + ".vrml": "application/x-vrml", + ".vrt": "x-world/x-vrt", + ".vsd": "application/x-visio", + ".vst": "application/x-visio", + ".vsw": "application/x-visio", + ".w60": "application/wordperfect60", + ".w61": "application/wordperfect61", + ".w6w": "application/msword", + ".wav": "audio/wav", + ".wb1": "application/x-qpro", + ".wbmp": "image/vnd.wap.wbmp", + ".web": "application/vndxara", + ".wiz": "application/msword", + ".wk1": "application/x-123", + ".wmf": "windows/metafile", + ".wml": "text/vnd.wap.wml", + ".wmlc": "application/vnd.wap.wmlc", + ".wmls": "text/vnd.wap.wmlscript", + ".wmlsc": "application/vnd.wap.wmlscriptc", + ".word": "application/msword", + ".wp5": "application/wordperfect", + ".wp6": "application/wordperfect", + ".wp": "application/wordperfect", + ".wpd": "application/wordperfect", + ".wq1": "application/x-lotus", + ".wri": "application/mswrite", + ".wrl": "application/x-world", + ".wrz": "model/vrml", + ".wsc": "text/scriplet", + ".wsrc": "application/x-wais-source", + ".wtk": "application/x-wintalk", + ".x-png": "image/png", + ".xbm": "image/x-xbitmap", + ".xdr": "video/x-amt-demorun", + ".xgz": "xgl/drawing", + ".xif": "image/vndxiff", + ".xl": "application/excel", + ".xla": "application/excel", + ".xlb": "application/excel", + ".xlc": "application/excel", + ".xld": "application/excel", + ".xlk": "application/excel", + ".xll": "application/excel", + ".xlm": "application/excel", + ".xls": "application/excel", + ".xlt": "application/excel", + ".xlv": "application/excel", + ".xlw": "application/excel", + ".xm": "audio/xm", + ".xml": ContentXMLHeaderValue, + ".xmz": "xgl/movie", + ".xpix": "application/x-vndls-xpix", + ".xpm": "image/x-xpixmap", + ".xsr": "video/x-amt-showrun", + ".xwd": "image/x-xwd", + ".xyz": "chemical/x-pdb", + ".z": "application/x-compress", + ".zip": "application/zip", + ".zoo": "application/octet-stream", + ".zsh": "text/x-scriptzsh", + ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".docm": "application/vnd.ms-word.document.macroEnabled.12", + ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + ".dotm": "application/vnd.ms-word.template.macroEnabled.12", + ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12", + ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + ".xltm": "application/vnd.ms-excel.template.macroEnabled.12", + ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12", + ".xlam": "application/vnd.ms-excel.addin.macroEnabled.12", + ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12", + ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", + ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template", + ".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12", + ".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12", + ".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", + ".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12", + ".thmx": "application/vnd.ms-officetheme", + ".onetoc": "application/onenote", + ".onetoc2": "application/onenote", + ".onetmp": "application/onenote", + ".onepkg": "application/onenote", + ".xpi": "application/x-xpinstall", + ".wasm": "application/wasm", + ".m4a": "audio/mp4", + ".flac": "audio/x-flac", + ".amr": "audio/amr", + ".aac": "audio/aac", + ".opus": "video/ogg", + ".m4v": "video/mp4", + ".mkv": "video/x-matroska", + ".caf": "audio/x-caf", + ".m3u8": "application/x-mpegURL", + ".mpd": "application/dash+xml", + ".webp": "image/webp", + ".epub": "application/epub+zip", +} + +//nolint:gochecknoinits +func init() { + for ext, typ := range types { + // skip errors + _ = mime.AddExtensionType(ext, typ) + } +} diff --git a/backend/fileutils/file.go b/backend/fileutils/file.go index bd89a644..e077093b 100644 --- a/backend/fileutils/file.go +++ b/backend/fileutils/file.go @@ -1,7 +1,6 @@ package fileutils import ( - "fmt" "io" "os" "path" @@ -12,21 +11,15 @@ import ( // By default, the rename system call is used. If src and dst point to different volumes, // the file copy is used as a fallback. func MoveFile(src, dst string) error { - fmt.Println("moving", src, dst) if os.Rename(src, dst) == nil { return nil } - fmt.Println("copyfile instead", src, dst) - // fallback err := CopyFile(src, dst) if err != nil { - fmt.Println("ok it errored too", err) - _ = os.Remove(dst) return err } - fmt.Println("removing", src) if err := os.Remove(src); err != nil { return err } diff --git a/backend/go.mod b/backend/go.mod index 3d1f3006..03b253b8 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -9,7 +9,7 @@ require ( github.com/disintegration/imaging v1.6.2 github.com/dsoprea/go-exif/v3 v3.0.1 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 - github.com/goccy/go-yaml v1.15.17 + github.com/goccy/go-yaml v1.15.23 github.com/golang-jwt/jwt/v4 v4.5.1 github.com/google/go-cmp v0.6.0 github.com/shirou/gopsutil/v3 v3.24.5 @@ -43,8 +43,8 @@ require ( github.com/swaggo/files v1.0.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/bbolt v1.4.0 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/tools v0.29.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/tools v0.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index e5d9a634..7312e1f9 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -46,8 +46,8 @@ github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9Z github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/goccy/go-yaml v1.15.17 h1:dK4FbbTTEOZTLH/NW3/xBqg0JdC14YKVmYwS9GT3H60= -github.com/goccy/go-yaml v1.15.17/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo= +github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= @@ -112,8 +112,8 @@ golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+o golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -125,8 +125,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= @@ -160,8 +160,8 @@ golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= diff --git a/backend/http/auth.go b/backend/http/auth.go index d9ce2608..d0ab137e 100644 --- a/backend/http/auth.go +++ b/backend/http/auth.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4/request" "golang.org/x/crypto/bcrypt" diff --git a/backend/http/middleware.go b/backend/http/middleware.go index 135aa2ff..0291ec95 100644 --- a/backend/http/middleware.go +++ b/backend/http/middleware.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v4" "github.com/gtsteffaniak/filebrowser/backend/files" "github.com/gtsteffaniak/filebrowser/backend/logger" "github.com/gtsteffaniak/filebrowser/backend/runner" diff --git a/backend/http/middleware_test.go b/backend/http/middleware_test.go index 5c135b75..bb309fa8 100644 --- a/backend/http/middleware_test.go +++ b/backend/http/middleware_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/gtsteffaniak/filebrowser/backend/diskcache" "github.com/gtsteffaniak/filebrowser/backend/files" "github.com/gtsteffaniak/filebrowser/backend/img" @@ -50,7 +50,7 @@ func mockFileInfoFaster(t *testing.T) { // Mock the function to skip execution FileInfoFasterFunc = func(opts files.FileOptions) (files.ExtendedFileInfo, error) { return files.ExtendedFileInfo{ - FileInfo: &files.FileInfo{ + FileInfo: files.FileInfo{ Path: opts.Path, ItemInfo: files.ItemInfo{ Name: "mocked_file", diff --git a/backend/http/onlyOffice.go b/backend/http/onlyOffice.go index f103fb7c..cf596926 100644 --- a/backend/http/onlyOffice.go +++ b/backend/http/onlyOffice.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" - "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v4" "github.com/gtsteffaniak/filebrowser/backend/cache" "github.com/gtsteffaniak/filebrowser/backend/files" "github.com/gtsteffaniak/filebrowser/backend/settings" @@ -56,7 +56,7 @@ func onlyofficeClientConfigGetHandler(w http.ResponseWriter, r *http.Request, d path := pathParts[len(pathParts)-1] urlFirst := pathParts[0] if settings.Config.Server.InternalUrl != "" { - urlFirst = settings.Config.Server.InternalUrl + urlFirst = strings.TrimSuffix(settings.Config.Server.InternalUrl, "/") replacement := strings.Split(url, "/api/raw")[0] url = strings.Replace(url, replacement, settings.Config.Server.InternalUrl, 1) } diff --git a/backend/http/preview.go b/backend/http/preview.go index cdaee33c..5105a497 100644 --- a/backend/http/preview.go +++ b/backend/http/preview.go @@ -153,7 +153,7 @@ func previewCacheKey(realPath, previewSize string, modTime time.Time) string { return fmt.Sprintf("%x%x%x", realPath, modTime.Unix(), previewSize) } -func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo) (int, error) { +func rawFileHandler(w http.ResponseWriter, r *http.Request, file files.FileInfo) (int, error) { idx := files.GetIndex("default") realPath, _, _ := idx.GetRealPath(file.Path) fd, err := os.Open(realPath) diff --git a/backend/http/raw.go b/backend/http/raw.go index f911174a..b46c61f2 100644 --- a/backend/http/raw.go +++ b/backend/http/raw.go @@ -57,7 +57,7 @@ func rawHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (int, if err != nil { return http.StatusBadRequest, fmt.Errorf("invalid path encoding: %v", err) } - fileList := strings.Split(files, ",") + fileList := strings.Split(files, ",|") for i, f := range fileList { fileList[i] = filepath.Join(filePrefix, f) } @@ -196,6 +196,7 @@ func rawFilesHandler(w http.ResponseWriter, r *http.Request, d *requestContext, // Set headers and serve the file setContentDisposition(w, r, fileName) w.Header().Set("Cache-Control", "private") + w.Header().Set("X-Content-Type-Options", "nosniff") // Serve the content http.ServeContent(w, r, fileName, fileInfo.ModTime(), fd) diff --git a/backend/img/service.go b/backend/img/service.go index f699c0a6..d84932a7 100644 --- a/backend/img/service.go +++ b/backend/img/service.go @@ -10,7 +10,7 @@ import ( "io" "github.com/disintegration/imaging" - "github.com/dsoprea/go-exif/v3" + exif "github.com/dsoprea/go-exif/v3" exifcommon "github.com/dsoprea/go-exif/v3/common" ) diff --git a/backend/runner/commands.go b/backend/runner/commands.go index 186e2654..4d598a28 100644 --- a/backend/runner/commands.go +++ b/backend/runner/commands.go @@ -19,7 +19,7 @@ import ( "runtime" "unicode" - "github.com/flynn/go-shlex" + shlex "github.com/flynn/go-shlex" ) const ( diff --git a/backend/runner/runner.go b/backend/runner/runner.go index 24149043..90c98097 100644 --- a/backend/runner/runner.go +++ b/backend/runner/runner.go @@ -25,7 +25,7 @@ func (r *Runner) RunHook(fn func() error, evt, path, dst string, user *users.Use dst, _, _ = idx.GetRealPath(user.Scope, dst) if r.Enabled { - if val, ok := r.Commands["before_"+evt]; ok { + if val, ok := r.Settings.Commands["before_"+evt]; ok { for _, command := range val { err := r.exec(command, "before_"+evt, path, dst, user) if err != nil { @@ -41,7 +41,7 @@ func (r *Runner) RunHook(fn func() error, evt, path, dst string, user *users.Use } if r.Enabled { - if val, ok := r.Commands["after_"+evt]; ok { + if val, ok := r.Settings.Commands["after_"+evt]; ok { for _, command := range val { err := r.exec(command, "after_"+evt, path, dst, user) if err != nil { diff --git a/backend/settings/config.go b/backend/settings/config.go index c9426559..d65f6bbc 100644 --- a/backend/settings/config.go +++ b/backend/settings/config.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "github.com/goccy/go-yaml" + yaml "github.com/goccy/go-yaml" "github.com/gtsteffaniak/filebrowser/backend/logger" "github.com/gtsteffaniak/filebrowser/backend/users" "github.com/gtsteffaniak/filebrowser/backend/version" @@ -155,15 +155,16 @@ func setDefaults() Settings { Name: "FileBrowser Quantum", }, UserDefaults: UserDefaults{ - StickySidebar: true, - Scope: ".", - LockPassword: false, - ShowHidden: false, - DarkMode: true, - DisableSettings: false, - ViewMode: "normal", - Locale: "en", - GallerySize: 3, + DisableOnlyOfficeExt: ".txt .csv .html", + StickySidebar: true, + Scope: ".", + LockPassword: false, + ShowHidden: false, + DarkMode: true, + DisableSettings: false, + ViewMode: "normal", + Locale: "en", + GallerySize: 3, Permissions: users.Permissions{ Create: false, Rename: false, diff --git a/backend/settings/settings_test.go b/backend/settings/settings_test.go index 54d62c29..c259b565 100644 --- a/backend/settings/settings_test.go +++ b/backend/settings/settings_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/goccy/go-yaml" + yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/gtsteffaniak/filebrowser/backend/logger" ) diff --git a/backend/settings/structs.go b/backend/settings/structs.go index 88b14739..70238b87 100644 --- a/backend/settings/structs.go +++ b/backend/settings/structs.go @@ -156,11 +156,12 @@ type UserDefaults struct { By string `json:"by"` Asc bool `json:"asc"` } `json:"sorting"` - Perm users.Permissions `json:"perm"` - Permissions users.Permissions `json:"permissions"` - Commands []string `json:"commands,omitempty"` - ShowHidden bool `json:"showHidden"` - DateFormat bool `json:"dateFormat"` - ThemeColor string `json:"themeColor"` - QuickDownload bool `json:"quickDownload"` + Perm users.Permissions `json:"perm"` + Permissions users.Permissions `json:"permissions"` + Commands []string `json:"commands,omitempty"` + ShowHidden bool `json:"showHidden"` + DateFormat bool `json:"dateFormat"` + ThemeColor string `json:"themeColor"` + QuickDownload bool `json:"quickDownload"` + DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` } diff --git a/backend/storage/bolt/auth.go b/backend/storage/bolt/auth.go index 5ddd5fcb..a6111851 100644 --- a/backend/storage/bolt/auth.go +++ b/backend/storage/bolt/auth.go @@ -1,7 +1,7 @@ package bolt import ( - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/gtsteffaniak/filebrowser/backend/auth" "github.com/gtsteffaniak/filebrowser/backend/errors" ) diff --git a/backend/storage/bolt/bolt.go b/backend/storage/bolt/bolt.go index 7d8fecdc..41f761c2 100644 --- a/backend/storage/bolt/bolt.go +++ b/backend/storage/bolt/bolt.go @@ -1,7 +1,7 @@ package bolt import ( - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/gtsteffaniak/filebrowser/backend/auth" "github.com/gtsteffaniak/filebrowser/backend/settings" diff --git a/backend/storage/bolt/config.go b/backend/storage/bolt/config.go index d41cdb65..16337978 100644 --- a/backend/storage/bolt/config.go +++ b/backend/storage/bolt/config.go @@ -1,7 +1,7 @@ package bolt import ( - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/gtsteffaniak/filebrowser/backend/settings" ) diff --git a/backend/storage/bolt/share.go b/backend/storage/bolt/share.go index 2c868418..d9fa636d 100644 --- a/backend/storage/bolt/share.go +++ b/backend/storage/bolt/share.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/asdine/storm/v3/q" "github.com/gtsteffaniak/filebrowser/backend/errors" diff --git a/backend/storage/bolt/users.go b/backend/storage/bolt/users.go index 3b628479..433238da 100644 --- a/backend/storage/bolt/users.go +++ b/backend/storage/bolt/users.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/gtsteffaniak/filebrowser/backend/errors" "github.com/gtsteffaniak/filebrowser/backend/settings" diff --git a/backend/storage/bolt/utils.go b/backend/storage/bolt/utils.go index 66c61031..26f5861a 100644 --- a/backend/storage/bolt/utils.go +++ b/backend/storage/bolt/utils.go @@ -1,7 +1,7 @@ package bolt import ( - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/gtsteffaniak/filebrowser/backend/errors" ) diff --git a/backend/storage/storage.go b/backend/storage/storage.go index 5c4833cd..5e0ce736 100644 --- a/backend/storage/storage.go +++ b/backend/storage/storage.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" - "github.com/asdine/storm/v3" + storm "github.com/asdine/storm/v3" "github.com/gtsteffaniak/filebrowser/backend/auth" "github.com/gtsteffaniak/filebrowser/backend/errors" "github.com/gtsteffaniak/filebrowser/backend/files" diff --git a/backend/swagger/docs/docs.go b/backend/swagger/docs/docs.go index 04da8065..24c8cb47 100644 --- a/backend/swagger/docs/docs.go +++ b/backend/swagger/docs/docs.go @@ -1364,6 +1364,9 @@ const docTemplate = `{ "dateFormat": { "type": "boolean" }, + "disableOnlyOfficeExt": { + "type": "string" + }, "disableSettings": { "type": "boolean" }, @@ -1575,6 +1578,9 @@ const docTemplate = `{ "dateFormat": { "type": "boolean" }, + "disableOnlyOfficeExt": { + "type": "string" + }, "disableSettings": { "type": "boolean" }, diff --git a/backend/swagger/docs/swagger.json b/backend/swagger/docs/swagger.json index 9ded0650..a4df6a86 100644 --- a/backend/swagger/docs/swagger.json +++ b/backend/swagger/docs/swagger.json @@ -1353,6 +1353,9 @@ "dateFormat": { "type": "boolean" }, + "disableOnlyOfficeExt": { + "type": "string" + }, "disableSettings": { "type": "boolean" }, @@ -1564,6 +1567,9 @@ "dateFormat": { "type": "boolean" }, + "disableOnlyOfficeExt": { + "type": "string" + }, "disableSettings": { "type": "boolean" }, diff --git a/backend/swagger/docs/swagger.yaml b/backend/swagger/docs/swagger.yaml index 1810a63f..74d46fb4 100644 --- a/backend/swagger/docs/swagger.yaml +++ b/backend/swagger/docs/swagger.yaml @@ -132,6 +132,8 @@ definitions: type: boolean dateFormat: type: boolean + disableOnlyOfficeExt: + type: string disableSettings: type: boolean gallerySize: @@ -273,6 +275,8 @@ definitions: type: boolean dateFormat: type: boolean + disableOnlyOfficeExt: + type: string disableSettings: type: boolean gallerySize: diff --git a/backend/users/users.go b/backend/users/users.go index 7f259296..30d19fe3 100644 --- a/backend/users/users.go +++ b/backend/users/users.go @@ -3,7 +3,7 @@ package users import ( "regexp" - "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v4" ) type AuthToken struct { @@ -36,33 +36,34 @@ 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"` - Username string `storm:"unique" json:"username"` - Password string `json:"password,omitempty"` - Scope string `json:"scope"` - Locale string `json:"locale"` - LockPassword bool `json:"lockPassword"` - ViewMode string `json:"viewMode"` - SingleClick bool `json:"singleClick"` - Sorting Sorting `json:"sorting"` - Perm Permissions `json:"perm"` - Commands []string `json:"commands"` - Rules []Rule `json:"rules"` - ApiKeys map[string]AuthToken `json:"apiKeys,omitempty"` - ShowHidden bool `json:"showHidden"` - DateFormat bool `json:"dateFormat"` - GallerySize int `json:"gallerySize"` - ThemeColor string `json:"themeColor"` - QuickDownload bool `json:"quickDownload"` + StickySidebar bool `json:"stickySidebar"` + DarkMode bool `json:"darkMode"` + DisableSettings bool `json:"disableSettings"` + ID uint `storm:"id,increment" json:"id"` + Username string `storm:"unique" json:"username"` + Password string `json:"password,omitempty"` + Scope string `json:"scope"` + Locale string `json:"locale"` + LockPassword bool `json:"lockPassword"` + ViewMode string `json:"viewMode"` + SingleClick bool `json:"singleClick"` + Sorting Sorting `json:"sorting"` + Perm Permissions `json:"perm"` + Commands []string `json:"commands"` + Rules []Rule `json:"rules"` + ApiKeys map[string]AuthToken `json:"apiKeys,omitempty"` + ShowHidden bool `json:"showHidden"` + DateFormat bool `json:"dateFormat"` + GallerySize int `json:"gallerySize"` + ThemeColor string `json:"themeColor"` + QuickDownload bool `json:"quickDownload"` + DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` } var PublicUser = User{ Username: "publicUser", // temp user not registered Password: "publicUser", // temp user not registered - Scope: "./", + Scope: "/does/not/exist", ViewMode: "normal", LockPassword: true, Perm: Permissions{ diff --git a/frontend/package.json b/frontend/package.json index 6f90496f..3c3490a0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,6 +22,7 @@ "dependencies": { "@onlyoffice/document-editor-vue": "^1.4.0", "ace-builds": "^1.24.2", + "axios": "^1.7.9", "clipboard": "^2.0.4", "css-vars-ponyfill": "^2.4.3", "dompurify": "^3.2.4", @@ -29,6 +30,7 @@ "marked": "^15.0.6", "normalize.css": "^8.0.1", "qrcode.vue": "^3.4.1", + "srt-support-for-html5-videos": "^2.6.11", "vue": "^3.4.21", "vue-i18n": "^9.10.2", "vue-lazyload": "^3.0.0", diff --git a/frontend/src/api/files.js b/frontend/src/api/files.js index ac2775e5..394c1014 100644 --- a/frontend/src/api/files.js +++ b/frontend/src/api/files.js @@ -1,243 +1,244 @@ -import { fetchURL, adjustedData } from "./utils"; -import { removePrefix, getApiPath } from "@/utils/url.js"; -import { state } from "@/store"; -import { notify } from "@/notify"; -import { externalUrl } from "@/utils/constants"; +import { fetchURL, adjustedData } from './utils' +import { removePrefix, getApiPath } from '@/utils/url.js' +import { state } from '@/store' +import { notify } from '@/notify' +import { externalUrl } from '@/utils/constants' // Notify if errors occur -export async function fetchFiles(url, content = false) { +export async function fetchFiles (url, content = false) { try { - let path = encodeURIComponent(removePrefix(url, "files")); - const apiPath = getApiPath("api/resources",{path: path, content: content}); - const res = await fetchURL(apiPath); - const data = await res.json(); - const adjusted = adjustedData(data, url); - return adjusted; + let path = encodeURIComponent(removePrefix(url, 'files')) + const apiPath = getApiPath('api/resources', { + path: path, + content: content + }) + const res = await fetchURL(apiPath) + const data = await res.json() + const adjusted = adjustedData(data, url) + return adjusted } catch (err) { - notify.showError(err.message || "Error fetching data"); - throw err; + notify.showError(err.message || 'Error fetching data') + throw err } } -async function resourceAction(url, method, content) { +async function resourceAction (url, method, content) { try { - let opts = { method }; + let opts = { method } if (content) { - opts.body = content; + opts.body = content } - let path = encodeURIComponent(removePrefix(url, "files")); - const apiPath = getApiPath("api/resources", { path: path }); - const res = await fetchURL(apiPath, opts); - return res; + let path = encodeURIComponent(removePrefix(url, 'files')) + const apiPath = getApiPath('api/resources', { path: path }) + const res = await fetchURL(apiPath, opts) + return res } catch (err) { - notify.showError(err.message || "Error performing resource action"); - throw err; + notify.showError(err.message || 'Error performing resource action') + throw err } } -export async function remove(url) { +export async function remove (url) { try { - let path = encodeURIComponent(removePrefix(url, "files")); - return await resourceAction(path, "DELETE"); + let path = encodeURIComponent(removePrefix(url, 'files')) + return await resourceAction(path, 'DELETE') } catch (err) { - notify.showError(err.message || "Error deleting resource"); - throw err; + notify.showError(err.message || 'Error deleting resource') + throw err } } -export async function put(url, content = "") { +export async function put (url, content = '') { try { - let path = encodeURIComponent(removePrefix(url, "files")); - return await resourceAction(path, "PUT", content); + let path = encodeURIComponent(removePrefix(url, 'files')) + return await resourceAction(path, 'PUT', content) } catch (err) { - notify.showError(err.message || "Error putting resource"); - throw err; + notify.showError(err.message || 'Error putting resource') + throw err } } -export function download(format, files) { - if (format != "zip") { - format = "tar.gz" +export function download (format, files) { + if (format != 'zip') { + format = 'tar.gz' } try { - let fileargs = ""; + let fileargs = '' if (files.length === 1) { - fileargs = decodeURI(removePrefix(files[0], "files")) + fileargs = decodeURI(removePrefix(files[0], 'files')) } else { for (let file of files) { - fileargs += decodeURI(removePrefix(file,"files")) + ","; + fileargs += decodeURI(removePrefix(file, 'files')) + ',|' } - fileargs = fileargs.substring(0, fileargs.length - 1); + fileargs = fileargs.substring(0, fileargs.length - 1) } - const apiPath = getApiPath("api/raw", { files: encodeURIComponent(fileargs), algo: format }); - const url = window.origin+apiPath - window.open(url); + const apiPath = getApiPath('api/raw', { + files: encodeURIComponent(fileargs), + algo: format + }) + const url = window.origin + apiPath + window.open(url) } catch (err) { - notify.showError(err.message || "Error downloading files"); + notify.showError(err.message || 'Error downloading files') } } -export async function post(url, content = "", overwrite = false, onupload) { +export async function post (url, content = '', overwrite = false, onupload) { try { - url = removePrefix(url, "files"); + url = removePrefix(url, 'files') - let bufferContent; + let bufferContent if ( content instanceof Blob && - !["http:", "https:"].includes(window.location.protocol) + !['http:', 'https:'].includes(window.location.protocol) ) { - bufferContent = await new Response(content).arrayBuffer(); + bufferContent = await new Response(content).arrayBuffer() } - const apiPath = getApiPath("api/resources", { path: url, override: overwrite }); + const apiPath = getApiPath('api/resources', { + path: url, + override: overwrite + }) return new Promise((resolve, reject) => { - let request = new XMLHttpRequest(); - request.open( - "POST", - apiPath, - true - ); - request.setRequestHeader("X-Auth", state.jwt); + let request = new XMLHttpRequest() + request.open('POST', apiPath, true) + request.setRequestHeader('X-Auth', state.jwt) - if (typeof onupload === "function") { - request.upload.onprogress = (event) => { + if (typeof onupload === 'function') { + request.upload.onprogress = event => { if (event.lengthComputable) { - const percentComplete = Math.round((event.loaded / event.total) * 100); - onupload(percentComplete); // Pass the percentage to the callback + const percentComplete = Math.round( + (event.loaded / event.total) * 100 + ) + onupload(percentComplete) // Pass the percentage to the callback } - }; + } } request.onload = () => { if (request.status === 200) { - resolve(request.responseText); + resolve(request.responseText) } else if (request.status === 409) { - reject(request.status); + reject(request.status) } else { - reject(request.responseText); + reject(request.responseText) } - }; - - request.onerror = () => { - reject(new Error("001 Connection aborted")); - }; - - request.send(bufferContent || content); - }); + } + request.send(bufferContent || content) + }) } catch (err) { - notify.showError(err.message || "Error posting resource"); - throw err; + notify.showError(err.message || 'Error posting resource') + throw err } } -export async function moveCopy(items, action = "copy", overwrite = false, rename = false) { +export async function moveCopy ( + items, + action = 'copy', + overwrite = false, + rename = false +) { let params = { overwrite: overwrite, action: action, - rename: rename, - }; + rename: rename + } try { // Create an array of fetch calls - let promises = items.map((item) => { - let toPath = encodeURIComponent(removePrefix(decodeURI(item.to), "files")); - let fromPath = encodeURIComponent(removePrefix(decodeURI(item.from), "files")); - let localParams = { ...params, destination: toPath, from: fromPath }; - const apiPath = getApiPath("api/resources", localParams); - return fetch(apiPath, { method: "PATCH" }).then((response) => { + let promises = items.map(item => { + let toPath = encodeURIComponent(removePrefix(decodeURI(item.to), 'files')) + let fromPath = encodeURIComponent( + removePrefix(decodeURI(item.from), 'files') + ) + let localParams = { ...params, destination: toPath, from: fromPath } + const apiPath = getApiPath('api/resources', localParams) + return fetch(apiPath, { method: 'PATCH' }).then(response => { if (!response.ok) { // Throw an error if the fetch fails - return response.text().then((text) => { - throw new Error(`Failed to move/copy: ${text || response.statusText}`); - }); + return response.text().then(text => { + throw new Error( + `Failed to move/copy: ${text || response.statusText}` + ) + }) } - return response; - }); - }); + return response + }) + }) // Await all promises and ensure errors propagate - await Promise.all(promises); + await Promise.all(promises) } catch (err) { - notify.showError(err.message || "Error moving/copying resources"); - throw err; // Re-throw the error to propagate it back to the caller + notify.showError(err.message || 'Error moving/copying resources') + throw err // Re-throw the error to propagate it back to the caller } } - -export async function checksum(path, algo) { +export async function checksum (path, algo) { try { const params = { - path: encodeURIComponent(removePrefix(path, "files")), - checksum: algo, - }; - const apiPath = getApiPath("api/resources", params); - const res = await fetchURL(apiPath); - const data = await res.json(); - return data.checksums[algo]; - } catch (err) { - notify.showError(err.message || "Error fetching checksum"); - throw err; - } -} - -export function getDownloadURL(path, inline, useExternal) { - try { - const params = { - files: encodeURIComponent(removePrefix(decodeURI(path),"files")), - ...(inline && { inline: "true" }), - }; - const apiPath = getApiPath("api/raw", params); - if (externalUrl && useExternal) { - return externalUrl+apiPath + path: encodeURIComponent(removePrefix(path, 'files')), + checksum: algo } - return window.origin+apiPath + const apiPath = getApiPath('api/resources', params) + const res = await fetchURL(apiPath) + const data = await res.json() + return data.checksums[algo] } catch (err) { - notify.showError(err.message || "Error getting download URL"); - throw err; + notify.showError(err.message || 'Error fetching checksum') + throw err } } -export function getPreviewURL(path, size, modified) { +export function getDownloadURL (path, inline, useExternal) { try { const params = { - path: encodeURIComponent(removePrefix(decodeURI(path),"files")), + files: encodeURIComponent(removePrefix(decodeURI(path), 'files')), + ...(inline && { inline: 'true' }) + } + const apiPath = getApiPath('api/raw', params) + if (externalUrl && useExternal) { + return externalUrl + apiPath + } + return window.origin + apiPath + } catch (err) { + notify.showError(err.message || 'Error getting download URL') + throw err + } +} + +export function getPreviewURL (path, size, modified) { + try { + const params = { + path: encodeURIComponent(removePrefix(decodeURI(path), 'files')), size: size, key: Date.parse(modified), - inline: "true", - }; - const apiPath = getApiPath("api/preview", params); - return window.origin+apiPath - } catch (err) { - notify.showError(err.message || "Error getting preview URL"); - throw err; - } -} - -export function getSubtitlesURL(file) { - try { - const subtitles = []; - for (const sub of file.subtitles) { - const params = { - inline: "true", - path: encodeURIComponent(removePrefix(sub,"files")) - }; - const apiPath = getApiPath("api/raw", params); - return window.origin+apiPath + inline: 'true' } - - return subtitles; + const apiPath = getApiPath('api/preview', params) + return window.origin + apiPath } catch (err) { - notify.showError(err.message || "Error fetching subtitles URL"); - throw err; + notify.showError(err.message || 'Error getting preview URL') + throw err } } -export async function usage(source) { +export function getSubtitlesURL (path) { + const params = { + inline: true, + files: path, + source: 'default' + } + const apiPath = getApiPath('api/raw', params) + return window.origin + apiPath +} + +export async function usage (source) { try { - const apiPath = getApiPath("api/usage", { source: source }); - const res = await fetchURL(apiPath); - return await res.json(); + const apiPath = getApiPath('api/usage', { source: source }) + const res = await fetchURL(apiPath) + return await res.json() } catch (err) { - notify.showError(err.message || "Error fetching usage data"); - throw err; + notify.showError(err.message || 'Error fetching usage data') + throw err } } diff --git a/frontend/src/api/utils.js b/frontend/src/api/utils.js index 705b8e1f..6bce53f3 100644 --- a/frontend/src/api/utils.js +++ b/frontend/src/api/utils.js @@ -68,7 +68,12 @@ export function adjustedData(data, url) { data.items = [...(data.folders || []), ...(data.files || [])]; data.items = data.items.map((item) => { - item.url = `${data.url}${item.name}`; + item.url = `${data.url}${encodeURIComponent(item.name)}`; + if (data.path == "/") { + item.path = `/${item.name}` + } else { + item.path = `${data.path}/${item.name}` + } if (item.type === "directory") { item.url += "/"; } diff --git a/frontend/src/api/utils.test.js b/frontend/src/api/utils.test.js index 6b627228..5117fec4 100644 --- a/frontend/src/api/utils.test.js +++ b/frontend/src/api/utils.test.js @@ -13,21 +13,23 @@ describe('adjustedData', () => { { name: "file1.txt", type: "file" }, { name: "file2.txt", type: "file" }, ], + path: "/root" }; - const url = "http://example.com/unit-testing/files/path/to/directory"; + const url = "http://example.com/root/"; const expected = { type: "directory", - url: "http://example.com/unit-testing/files/path/to/directory/", + url: "http://example.com/root/", folders: [], files: [], items: [ - { name: "folder1", type: "directory", url: "http://example.com/unit-testing/files/path/to/directory/folder1/" }, - { name: "folder2", type: "directory", url: "http://example.com/unit-testing/files/path/to/directory/folder2/" }, - { name: "file1.txt", type: "file", url: "http://example.com/unit-testing/files/path/to/directory/file1.txt" }, - { name: "file2.txt", type: "file", url: "http://example.com/unit-testing/files/path/to/directory/file2.txt" }, + { name: "folder1", path: "/root/folder1", type: "directory", url: "http://example.com/root/folder1/" }, + { name: "folder2", path: "/root/folder2", type: "directory", url: "http://example.com/root/folder2/" }, + { name: "file1.txt", path: "/root/file1.txt", type: "file", url: "http://example.com/root/file1.txt" }, + { name: "file2.txt", path: "/root/file2.txt", type: "file", url: "http://example.com/root/file2.txt" }, ], + path: "/root", }; expect(adjustedData(input, url)).toEqual(expected); diff --git a/frontend/src/components/ContextMenu.vue b/frontend/src/components/ContextMenu.vue index 054d458d..65eaa998 100644 --- a/frontend/src/components/ContextMenu.vue +++ b/frontend/src/components/ContextMenu.vue @@ -13,27 +13,36 @@
{{ selectedCount }} selected
+ + + + 0) { + this.showCreate = false; + } else { + this.showCreate = true; + } const contextProps = getters.currentPrompt().props; let tempX = contextProps.posX; let tempY = contextProps.posY; diff --git a/frontend/src/components/Search.vue b/frontend/src/components/Search.vue index bf7a4ce0..942e89a9 100644 --- a/frontend/src/components/Search.vue +++ b/frontend/src/components/Search.vue @@ -35,7 +35,7 @@
-
Search Context: {{ getContext }}
+
Search Context: {{ getContext }}
diff --git a/frontend/src/components/prompts/Copy.vue b/frontend/src/components/prompts/Copy.vue index 8c2f97a3..b1d115e0 100644 --- a/frontend/src/components/prompts/Copy.vue +++ b/frontend/src/components/prompts/Copy.vue @@ -76,14 +76,14 @@ export default { if (state.isSearchActive) { this.items = [ { - from: "/files" + state.selected[0].url, + from: "/files" + state.selected[0].path, name: state.selected[0].name, }, ]; } else { for (let item of state.selected) { this.items.push({ - from: state.req.items[item].url, + from: state.req.items[item].path, // add to: dest name: state.req.items[item].name, }); diff --git a/frontend/src/components/prompts/Delete.vue b/frontend/src/components/prompts/Delete.vue index d60e5e4b..9335451d 100644 --- a/frontend/src/components/prompts/Delete.vue +++ b/frontend/src/components/prompts/Delete.vue @@ -7,7 +7,7 @@

{{ $t("prompts.deleteMessageMultiple", { count: selectedCount }) }}

-
+
{{ item }}
@@ -23,7 +23,7 @@