diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index cbe1f78e..7f026079 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -6,7 +6,32 @@ on: - "main" jobs: + test_frontend: + name: Test Playwright + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + - uses: actions/setup-node@v4 + - working-directory: frontend + run: npm i && npm run build + - uses: actions/setup-go@v5 + with: + go-version: 'stable' + - working-directory: backend + run: go build -o filebrowser . + - name: Build + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile.playwright + push: false push_latest_to_registry: + needs: [ test_frontend ] name: Push latest runs-on: ubuntu-latest steps: @@ -14,9 +39,9 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Find latest tag + - name: Find latest beta tag run: | - echo "LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_ENV + echo "LATEST_TAG=$(git describe --tags $(git rev-list --tags="*-beta*" --max-count=1)) >> $GITHUB_ENV echo "latest tag is $LATEST_TAG" - name: Set up QEMU uses: docker/setup-qemu-action@v3.0.0 diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 5105ef0d..47f1e6c1 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -1,28 +1,37 @@ -name: pr-request +name: PR Request on: pull_request: branches: - - "main" - - "v[0-9]+.[0-9]+.[0-9]+" + - "dev/v[0-9]+.[0-9]+.[0-9]+" + - "beta/v[0-9]+.[0-9]+.[0-9]+" + - "stable/v[0-9]+.[0-9]+.[0-9]+" jobs: - #test_frontend: - # name: Push release - # runs-on: ubuntu-latest - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - # - name: Set up QEMU - # uses: docker/setup-qemu-action@v3.0.0 - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v3.0.0 - # - name: Build - # uses: docker/build-push-action@v6 - # with: - # context: . - # file: ./Dockerfile.playwright - # push: false + test_frontend: + name: Test Playwright + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + - uses: actions/setup-node@v4 + - working-directory: frontend + run: npm i && npm run build + - uses: actions/setup-go@v5 + with: + go-version: 'stable' + - working-directory: backend + run: go build -o filebrowser . + - name: Build + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile.playwright + push: false push_pr_to_registry: name: Push PR runs-on: ubuntu-latest diff --git a/.github/workflows/release_beta.yaml b/.github/workflows/release_beta.yaml index 07a7afbb..e07e6df5 100644 --- a/.github/workflows/release_beta.yaml +++ b/.github/workflows/release_beta.yaml @@ -9,7 +9,32 @@ permissions: contents: write jobs: + test_frontend: + name: Test Playwright + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + - uses: actions/setup-node@v4 + - working-directory: frontend + run: npm i && npm run build + - uses: actions/setup-go@v5 + with: + go-version: 'stable' + - working-directory: backend + run: go build -o filebrowser . + - name: Build + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile.playwright + push: false create_release_tag: + needs: [ test_frontend ] name: Create Release runs-on: ubuntu-latest steps: @@ -41,6 +66,7 @@ jobs: name: ${{ steps.extract_branch.outputs.tag_name }} push_release_to_registry: + needs: [ test_frontend ] name: Push release runs-on: ubuntu-latest steps: diff --git a/.github/workflows/release_stable.yaml b/.github/workflows/release_stable.yaml index 7d989f9f..3bf398af 100644 --- a/.github/workflows/release_stable.yaml +++ b/.github/workflows/release_stable.yaml @@ -9,7 +9,32 @@ permissions: contents: write jobs: + test_frontend: + name: Test Playwright + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + - uses: actions/setup-node@v4 + - working-directory: frontend + run: npm i && npm run build + - uses: actions/setup-go@v5 + with: + go-version: 'stable' + - working-directory: backend + run: go build -o filebrowser . + - name: Build + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile.playwright + push: false create_release_tag: + needs: [ test_frontend ] name: Create Release runs-on: ubuntu-latest steps: @@ -40,6 +65,7 @@ jobs: name: ${{ steps.extract_branch.outputs.tag_name }} push_release_to_registry: + needs: [ test_frontend ] name: Push release runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 570bdb7d..6da80487 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ rice-box.go /frontend/dist /frontend/pkg /frontend/test-results +/frontend/loginAuth.json /frontend/package-lock.json /backend/vendor /backend/*.cov diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ac55085..17a352c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,18 @@ 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.3.6 +## v0.3.7-beta + + **Notes**: + - Adding windows builds back to automated process... will replace manually if they throw malicious defender warnings. + - Adding playwright tests to all pr's against dev/beta/release branches. + - These playwright tests should help keep release more reliably stable. + + **Bugfixes**: + - closing with the default bar issue. + - tar.gz archive creation issue + +## v0.3.6-beta **New Features** - Adds "externalUrl" server config https://github.com/gtsteffaniak/filebrowser/issues/272 diff --git a/Dockerfile.playwright b/Dockerfile.playwright index 37af3608..7f13307d 100644 --- a/Dockerfile.playwright +++ b/Dockerfile.playwright @@ -1,19 +1,5 @@ -FROM golang:1.23-alpine AS base +FROM gtstef/playwright-base WORKDIR /app -COPY ./backend ./ -RUN go build -ldflags="-w -s" -o filebrowser . - -FROM node:slim -WORKDIR /app -COPY ./frontend/package.json ./ -RUN npm i --maxsockets 1 -RUN npx playwright install --with-deps firefox -COPY [ "backend/config.yaml", "./" ] -COPY ./frontend/ ./frontend -WORKDIR /app/frontend -RUN npm run build-docker -WORKDIR /app -COPY --from=base /app/filebrowser* ./ -RUN cp -R frontend/tests/ srv -ENV FILEBROWSER_NO_EMBEDED="true" -RUN ./filebrowser & sleep 2 && cd frontend && npx playwright test +COPY [ "./backend/filebrowser*", "./"] +COPY [ "./frontend/", "./" ] +RUN ./filebrowser -c filebrowser-playwright.yaml & sleep 2 && npx playwright test diff --git a/Dockerfile.playwright-base b/Dockerfile.playwright-base new file mode 100644 index 00000000..8647b45a --- /dev/null +++ b/Dockerfile.playwright-base @@ -0,0 +1,5 @@ +FROM node:22-slim +WORKDIR /app +COPY ./frontend/package.json ./ +RUN npm i @playwright/test +RUN npx playwright install --with-deps firefox \ No newline at end of file diff --git a/README.md b/README.md index 108b8639..9019a672 100644 --- a/README.md +++ b/README.md @@ -153,3 +153,6 @@ Starred/pinned files | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | Content preview icons | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | Plugins support | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | Chromecast support | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +Share collections of files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | +Can archive selected files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | +Can browse archive files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ \ No newline at end of file diff --git a/backend/.goreleaser.yaml b/backend/.goreleaser.yaml index 50a7a4fa..c6f1036d 100644 --- a/backend/.goreleaser.yaml +++ b/backend/.goreleaser.yaml @@ -24,14 +24,18 @@ builds: - upx --force-macos {{ .Path }} # Compress the binary with UPX # Build configuration for windows without arm -# - id: windows -# ldflags: *ldflags -# main: main.go -# binary: filebrowser -# goos: -# - windows -# goarch: -# - amd64 + - id: windows + ldflags: *ldflags + main: main.go + binary: filebrowser + goos: + - windows + goarch: + - amd64 + - arm64 + hooks: + post: + - upx {{ .Path }} # Compress the binary with UPX archives: - name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}" diff --git a/backend/filebrowser-playwright.yaml b/backend/filebrowser-playwright.yaml new file mode 100644 index 00000000..b9aca8f9 --- /dev/null +++ b/backend/filebrowser-playwright.yaml @@ -0,0 +1,21 @@ +server: + port: 80 + baseURL: "/" + root: "./tests/playwright-files" +auth: + method: password + signup: false +userDefaults: + darkMode: true + disableSettings: false + scope: "." + hideDotfiles: true + singleClick: false + permissions: + admin: false + create: false + rename: false + modify: false + delete: false + share: false + download: false diff --git a/backend/files/indexingFiles.go b/backend/files/indexingFiles.go index 125fc143..c2bb27f0 100644 --- a/backend/files/indexingFiles.go +++ b/backend/files/indexingFiles.go @@ -192,7 +192,6 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err } func (idx *Index) makeIndexPath(subPath string) string { - subPath = strings.ReplaceAll(subPath, "\\", "/") if strings.HasPrefix(subPath, "./") { subPath = strings.TrimPrefix(subPath, ".") } @@ -203,6 +202,7 @@ func (idx *Index) makeIndexPath(subPath string) string { subPath = strings.TrimSuffix(subPath, "/") // remove index prefix adjustedPath := strings.TrimPrefix(subPath, idx.Source.Path) + adjustedPath = strings.ReplaceAll(adjustedPath, "\\", "/") // remove trailing slash adjustedPath = strings.TrimSuffix(adjustedPath, "/") if !strings.HasPrefix(adjustedPath, "/") { @@ -250,7 +250,6 @@ func (idx *Index) RefreshFileInfo(opts FileOptions) error { Path: opts.Path, IsDir: opts.IsDir, } - if !refreshOptions.IsDir { refreshOptions.Path = idx.makeIndexPath(filepath.Dir(refreshOptions.Path)) refreshOptions.IsDir = true diff --git a/backend/files/indexing_test.go b/backend/files/indexing_test.go index d7b74916..40116ff4 100644 --- a/backend/files/indexing_test.go +++ b/backend/files/indexing_test.go @@ -91,9 +91,6 @@ func TestMakeIndexPath(t *testing.T) { {"Trailing slash removed", "/test/", "/test"}, {"Subpath without root prefix", "/other/test", "/other/test"}, {"Complex nested paths", "/nested/path", "/nested/path"}, - // Windows - {"Mixed slash", "/first\\second", "/first/second"}, - {"Windows slash", "\\first\\second", "/first/second"}, } for _, tt := range tests { @@ -105,6 +102,27 @@ func TestMakeIndexPath(t *testing.T) { } }) } + + tests = []struct { + name string + subPath string + expected string + }{ + // Windows + {"Mixed slash", "/first\\second", "/first/second"}, + {"Windows slash", "\\first\\second", "/first/second"}, + {"Windows full path", "C:\\Users\\testfolder\\nestedfolder", "/testfolder/nestedfolder"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + idx := &Index{Source: settings.Source{Path: "C:\\Users"}} + result := idx.makeIndexPath(tt.subPath) + if result != tt.expected { + t.Errorf("makeIndexPath(%q)\ngot %q\nwant %q", tt.name, result, tt.expected) + } + }) + } } func TestMakeIndexPathRoot(t *testing.T) { diff --git a/backend/go.mod b/backend/go.mod index 6e933955..b850e62b 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -17,7 +17,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/swaggo/http-swagger v1.3.4 github.com/swaggo/swag v1.16.4 - golang.org/x/crypto v0.31.0 + golang.org/x/crypto v0.32.0 golang.org/x/image v0.23.0 golang.org/x/text v0.21.0 ) @@ -43,9 +43,9 @@ require ( github.com/swaggo/files v1.0.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/bbolt v1.3.11 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/tools v0.28.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/tools v0.29.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 6855c652..8df0c77a 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -114,8 +114,8 @@ go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68= golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= @@ -133,8 +133,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.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +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/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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= @@ -153,8 +153,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -168,8 +168,8 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 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.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +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/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/raw.go b/backend/http/raw.go index 45ba80b2..29874af5 100644 --- a/backend/http/raw.go +++ b/backend/http/raw.go @@ -63,8 +63,7 @@ func rawHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (int, } return rawFilesHandler(w, r, d, fileList) } - -func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *zip.Writer) error { +func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *zip.Writer, flatten bool) error { idx := files.GetIndex("default") realPath, _, _ := idx.GetRealPath(d.user.Scope, path) if !d.user.Check(realPath) { @@ -75,16 +74,36 @@ func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *z return err } + // Get the base name of the top-level folder or file + baseName := filepath.Base(realPath) + if info.IsDir() { // Walk through directory contents return filepath.Walk(realPath, func(filePath string, fileInfo os.FileInfo, err error) error { if err != nil { return err } - relPath, err := filepath.Rel(filepath.Dir(realPath), filePath) // Relative path including base dir + + // Calculate the relative path + relPath, err := filepath.Rel(realPath, filePath) // Use realPath directly if err != nil { return err } + + // Normalize for tar: convert \ to / + relPath = filepath.ToSlash(relPath) + + // Skip adding `.` (current directory) + if relPath == "." { + return nil + } + + // Prepend base folder name unless flatten is true + if !flatten { + relPath = filepath.Join(baseName, relPath) + relPath = filepath.ToSlash(relPath) // Ensure normalized separators + } + if fileInfo.IsDir() { if tarWriter != nil { header := &tar.Header{ @@ -105,8 +124,8 @@ func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *z }) } - // Add a single file if it's not a directory - return addSingleFile(realPath, filepath.Base(realPath), zipWriter, tarWriter) + // For a single file, use the base name as the archive path + return addSingleFile(realPath, baseName, zipWriter, tarWriter) } func addSingleFile(realPath, archivePath string, zipWriter *zip.Writer, tarWriter *tar.Writer) error { @@ -122,11 +141,12 @@ func addSingleFile(realPath, archivePath string, zipWriter *zip.Writer, tarWrite } if tarWriter != nil { - header, err := tar.FileInfoHeader(info, realPath) + header, err := tar.FileInfoHeader(info, "") if err != nil { return err } - header.Name = archivePath + // Ensure correct relative path + header.Name = filepath.ToSlash(archivePath) if err = tarWriter.WriteHeader(header); err != nil { return err } @@ -217,8 +237,10 @@ func createZip(w io.Writer, d *requestContext, filenames ...string) error { zipWriter := zip.NewWriter(w) defer zipWriter.Close() + // Check if we have exactly one directory + //flatten := len(filenames) == 1 for _, fname := range filenames { - err := addFile(fname, d, nil, zipWriter) + err := addFile(fname, d, nil, zipWriter, false) if err != nil { log.Printf("Failed to add %s to ZIP: %v", fname, err) } @@ -234,8 +256,10 @@ func createTarGz(w io.Writer, d *requestContext, filenames ...string) error { tarWriter := tar.NewWriter(gzWriter) defer tarWriter.Close() + // Check if we have exactly one directory + //flatten := len(filenames) == 1 for _, fname := range filenames { - err := addFile(fname, d, tarWriter, nil) + err := addFile(fname, d, tarWriter, nil, false) if err != nil { log.Printf("Failed to add %s to TAR.GZ: %v", fname, err) } diff --git a/backend/settings/config.go b/backend/settings/config.go index f1eac01b..a902bff8 100644 --- a/backend/settings/config.go +++ b/backend/settings/config.go @@ -114,6 +114,9 @@ func setDefaults() Settings { Host: "", }, }, + Frontend: Frontend{ + Name: "FileBrowser Quantum", + }, UserDefaults: UserDefaults{ StickySidebar: true, Scope: ".", diff --git a/frontend/global-setup.ts b/frontend/global-setup.ts new file mode 100644 index 00000000..c103f018 --- /dev/null +++ b/frontend/global-setup.ts @@ -0,0 +1,20 @@ +import { Browser, firefox, expect, Page } from "@playwright/test"; + + +async function globalSetup() { + const browser: Browser = await firefox.launch(); + const context = await browser.newContext(); + const page: Page = await context.newPage(); + await page.goto("http://127.0.0.1/login"); + await page.getByPlaceholder("Username").fill("admin"); + await page.getByPlaceholder("Password").fill("admin"); + await page.getByRole("button", { name: "Login" }).click(); + await page.waitForURL("**/files/", { timeout: 100 }); + await expect(page).toHaveTitle('FileBrowser Quantum - Files'); + let cookies = await context.cookies(); + expect(cookies.find((c) => c.name == "auth")?.value).toBeDefined(); + await page.context().storageState({ path: "./loginAuth.json" }); + await browser.close(); +} + +export default globalSetup \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index f9abca0a..1028b60e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,10 +17,10 @@ "lint": "eslint --ext .js,.vue,ts src", "lint:fix": "eslint --fix src/", "format": "prettier --write .", - "integration-test": "npx playwright test", "test": "vitest run " }, "dependencies": { + "@playwright/test": "^1.49.1", "ace-builds": "^1.24.2", "clipboard": "^2.0.4", "css-vars-ponyfill": "^2.4.3", @@ -34,7 +34,6 @@ }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^4.0.0", - "@playwright/test": "^1.42.1", "@vitejs/plugin-vue": "^5.0.4", "@vue/eslint-config-typescript": "^13.0.0", "eslint": "^8.57.0", diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index 9ab87e19..5cafb7b0 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -10,6 +10,8 @@ import { defineConfig, devices } from "@playwright/test"; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ + globalSetup: "./global-setup", + timeout: 3000, testDir: "./tests", /* Run tests in files in parallel */ fullyParallel: true, @@ -18,11 +20,13 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, + workers: process.env.CI ? 1 : 1, // required for now! todo parallel some tests /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "line", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { + actionTimeout: 500, + storageState: "loginAuth.json", /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: "http://127.0.0.1", diff --git a/frontend/public/index.html b/frontend/public/index.html index c03e1b87..4b78a701 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -32,7 +32,7 @@