Skip to content

Commit 3f78599

Browse files
committed
Simplify code
1 parent bca553d commit 3f78599

41 files changed

Lines changed: 1613 additions & 3084 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ docker compose up # Starts MinIO at localhost:9000; app at localhost:8080
2626

2727
S3 Manager is a stateless Go web app for managing S3-compatible storage (AWS S3, MinIO, etc.). There is no database; S3 is the sole source of truth.
2828

29-
**Backend** (`main.go` + `internal/app/s3manager/`): Gorilla mux routes requests to handler factory functions. Each handler receives its dependencies (S3 client, templates, config flags) via closure, not global state. The `MultiS3Manager` wraps multiple S3 instances; instance selection happens via a `{instance}` URL prefix, enabling concurrent multi-instance sessions.
29+
**Backend** (`main.go` + `internal/app/s3manager/`): Gorilla mux routes requests to handler factory functions. Each handler receives its dependencies (S3 client, templates, `Options`) via closure, not global state. `S3Instances` is the ordered, immutable list of configured S3 instances; instance selection happens via a `{instance}` URL prefix, enabling concurrent multi-instance sessions. `WithInstance` resolves that prefix and hands the matching client to a single-instance handler, so most handlers never see the instance list.
3030

3131
**Frontend** (`web/`): Server-rendered HTML using three Go templates (`layout.html.tmpl`, `buckets.html.tmpl`, `bucket.html.tmpl`) styled with [BeerCSS](https://www.beercss.com/) 5.0.3 (Material Design 3). No JS framework and no jQuery — plain `fetch` plus BeerCSS's `ui()` helper for dialogs, menus and snackbars. `layout.html.tmpl` owns the page shell, the shared `appbar-actions` template (instance switcher, light/dark toggle) and the shared `toast`/`request` helpers; each page template renders its own `<header>` and `<main>`.
3232

@@ -40,7 +40,7 @@ Static assets and templates are embedded into the binary via `//go:embed`, and B
4040
HTTP request
4141
→ Gorilla mux (main.go)
4242
→ Handler factory (e.g. HandleBucketView)
43-
MultiS3Manager.GetS3Instance(instanceName)
43+
S3Instances.Get(instanceName) (via WithInstance for non-view handlers)
4444
→ S3 interface call (minio-go/v7 under the hood)
4545
→ Template render or JSON response
4646
```
@@ -54,8 +54,8 @@ HTTP request
5454

5555
### Configuration
5656

57-
Instances are configured via numbered environment variables (`1_ENDPOINT`, `1_ACCESS_KEY_ID`, …) or a single unnamed set for backward compatibility. Viper is used to read all config. `ROOT_URL` supports reverse-proxy deployments with a path prefix.
57+
Instances are configured via numbered environment variables (`1_ENDPOINT`, `1_ACCESS_KEY_ID`, …) or a single unnamed set for backward compatibility. Viper is used to read all config. `ROOT_URL` supports reverse-proxy deployments with a path prefix. The feature flags the handlers care about are bundled into a single `s3manager.Options` value that `main.go` fills in and passes down.
5858

5959
## Testing
6060

61-
Tests live alongside source files. Each handler file has a corresponding `_test.go`. The `S3` mock (`mocks/s3.go`) is generated — regenerate with `go generate ./...` if the interface changes. Tests use `github.com/matryer/is` for assertions.
61+
Tests live alongside source files: each handler file has a corresponding `_test.go` in package `s3manager_test`, and the few tests of unexported helpers use `*_internal_test.go` in package `s3manager`. The `S3` mock (`mocks/s3.go`) is generated — regenerate with `go generate ./...` if the interface changes. Tests use `github.com/matryer/is` for assertions.

README.md

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,71 @@ A Web GUI written in Go to manage S3 buckets from any provider.
99

1010
## Features
1111

12-
- List all buckets in your account
13-
- Create a new bucket
14-
- List all objects in a bucket
15-
- Upload new objects to a bucket
16-
- Download object from a bucket
12+
- Manage several S3 accounts side by side and switch between them
13+
- List, create and delete buckets
14+
- View and edit a bucket's policy
15+
- List a bucket's objects with search, sorting and pagination
16+
- Upload single objects or whole folders to a bucket
17+
- Download an object, or several selected ones as a ZIP archive
1718
- Open an object in the browser (click its name or use the `Open` action)
18-
- Delete an object in a bucket
19+
- Delete a single object or several selected ones
20+
- Create a time-limited download link for an object
21+
- Check whether an object is publicly accessible and copy its public link
1922
- Show object metadata (including user metadata) and object versions
2023

2124
## Usage
2225

2326
### Configuration
2427

25-
The application can be configured with the following environment variables:
28+
The application is configured with environment variables.
2629

27-
- `ENDPOINT`: The endpoint of your S3 server (defaults to `s3.amazonaws.com`)
30+
#### S3 instances
31+
32+
Every S3 account the app should manage is configured with a numbered set of
33+
variables, starting at `1_`. The app stops looking at the first number that has
34+
no `NAME` or no `ENDPOINT`, so the numbering must not have gaps. Each instance
35+
appears in the app under its `NAME` and is reachable under `/<NAME>/buckets`
36+
(or `/<NUMBER>/buckets`), so pick names that work in a URL:
37+
38+
```shell
39+
1_NAME=production
40+
1_ENDPOINT=s3.amazonaws.com
41+
1_ACCESS_KEY_ID=XXX
42+
1_SECRET_ACCESS_KEY=xxx
43+
44+
2_NAME=backups
45+
2_ENDPOINT=minio.example.com:9000
46+
2_ACCESS_KEY_ID=YYY
47+
2_SECRET_ACCESS_KEY=yyy
48+
```
49+
50+
A single instance may also be configured without a number (it is then named
51+
`Default`), which is how earlier versions of the app were configured:
52+
53+
```shell
54+
ENDPOINT=s3.amazonaws.com
55+
ACCESS_KEY_ID=XXX
56+
SECRET_ACCESS_KEY=xxx
57+
```
58+
59+
The variables below are read per instance, either with a `N_` prefix or, for a
60+
single unnamed instance, without one. At least one instance must be configured.
61+
62+
- `NAME`: The name the instance is shown and addressed under (required in the numbered form; a single unnamed instance is called `Default`)
63+
- `ENDPOINT`: The endpoint of your S3 server (required, for example `s3.amazonaws.com`)
2864
- `REGION`: The region of your S3 server (defaults to `""`)
2965
- `ACCESS_KEY_ID`: Your S3 access key ID (required) (works only if `USE_IAM` is `false`)
3066
- `SECRET_ACCESS_KEY`: Your S3 secret access key (required) (works only if `USE_IAM` is `false`)
67+
- `USE_IAM`: Use IAM role instead of key pair (defaults to `false`)
68+
- `IAM_ENDPOINT`: Endpoint for IAM role retrieving (Can be blank for AWS)
3169
- `USE_SSL`: Whether your S3 server uses SSL or not (defaults to `true`)
3270
- `SKIP_SSL_VERIFICATION`: Whether the HTTP client should skip SSL verification (defaults to `false`)
3371
- `SIGNATURE_TYPE`: The signature type to be used (defaults to `V4`; valid values are `V2, V4, V4Streaming, Anonymous`)
72+
73+
#### Application
74+
75+
These variables apply to the whole app and are never prefixed:
76+
3477
- `PORT`: The port the app should listen on (defaults to `8080`)
3578
- `ALLOW_DELETE`: Enable buttons to delete objects (defaults to `true`)
3679
- `FORCE_DOWNLOAD`: Add response headers for object downloading instead of opening in a new tab (defaults to `true`; only affects the `Download` action, not `Open`)
@@ -39,8 +82,6 @@ The application can be configured with the following environment variables:
3982
- `SHOW_METADATA`: Show the object metadata action and enable the metadata endpoint (defaults to `true`)
4083
- `TZ`: IANA timezone used when displaying object Last Modified times (defaults to UTC; for example `Europe/Berlin`)
4184
- `BUCKET_NAME`: Restrict the buckets view to a single named bucket (defaults to unset, showing all buckets)
42-
- `USE_IAM`: Use IAM role instead of key pair (defaults to `false`)
43-
- `IAM_ENDPOINT`: Endpoint for IAM role retrieving (Can be blank for AWS)
4485
- `SSE_TYPE`: Specified server side encryption (defaults blank) Valid values can be `SSE`, `KMS`, `SSE-C` all others values don't enable the SSE
4586
- `SSE_KEY`: The key needed for SSE method (only for `KMS` and `SSE-C`)
4687
- `TIMEOUT`: The read and write timeout in seconds (default to `600` - 10 minutes)
@@ -53,7 +94,7 @@ The application can be configured with the following environment variables:
5394

5495
### Run Container image
5596

56-
1. Run `docker run -p 8080:8080 -e 'ACCESS_KEY_ID=XXX' -e 'SECRET_ACCESS_KEY=xxx' cloudlena/s3manager`
97+
1. Run `docker run -p 8080:8080 -e 'ENDPOINT=s3.amazonaws.com' -e 'ACCESS_KEY_ID=XXX' -e 'SECRET_ACCESS_KEY=xxx' cloudlena/s3manager`
5798

5899
### Deploy to Kubernetes
59100

@@ -100,7 +141,7 @@ The image is available on [Docker Hub](https://hub.docker.com/r/cloudlena/s3mana
100141

101142
### Run Locally for Testing
102143

103-
There is an example [docker-compose.yml](https://github.com/cloudlena/s3manager/blob/main/docker-compose.yml) file that spins up an S3 service and the S3 Manager. You can try it by issuing the following command:
144+
There is an example [docker-compose.yml](https://github.com/cloudlena/s3manager/blob/main/docker-compose.yml) file that spins up two S3 services and the S3 Manager configured for both of them. You can try it by issuing the following command:
104145

105146
```shell
106147
$ docker-compose up

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/fsnotify/fsnotify v1.10.1 // indirect
1717
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
1818
github.com/google/uuid v1.6.0 // indirect
19-
github.com/klauspost/compress v1.19.2 // indirect
19+
github.com/klauspost/compress v1.20.0 // indirect
2020
github.com/klauspost/cpuid/v2 v2.4.0 // indirect
2121
github.com/klauspost/crc32 v1.3.0 // indirect
2222
github.com/minio/crc64nvme v1.1.1 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
1919
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
2020
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
2121
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
22-
github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
23-
github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
22+
github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA=
23+
github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
2424
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
2525
github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw=
2626
github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU=

0 commit comments

Comments
 (0)