herfy-gcs 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- herfy_gcs-0.1.0/PKG-INFO +227 -0
- herfy_gcs-0.1.0/README.md +195 -0
- herfy_gcs-0.1.0/herfy_gcs/__init__.py +54 -0
- herfy_gcs-0.1.0/herfy_gcs/client.py +614 -0
- herfy_gcs-0.1.0/herfy_gcs/exceptions.py +46 -0
- herfy_gcs-0.1.0/herfy_gcs/models.py +143 -0
- herfy_gcs-0.1.0/herfy_gcs.egg-info/PKG-INFO +227 -0
- herfy_gcs-0.1.0/herfy_gcs.egg-info/SOURCES.txt +11 -0
- herfy_gcs-0.1.0/herfy_gcs.egg-info/dependency_links.txt +1 -0
- herfy_gcs-0.1.0/herfy_gcs.egg-info/requires.txt +12 -0
- herfy_gcs-0.1.0/herfy_gcs.egg-info/top_level.txt +1 -0
- herfy_gcs-0.1.0/pyproject.toml +65 -0
- herfy_gcs-0.1.0/setup.cfg +4 -0
herfy_gcs-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: herfy-gcs
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: GCS storage SDK for Herfy applications — upload/download via Control Center
|
|
5
|
+
Author: Herfy Development Team
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/herfy/herfy-shared
|
|
8
|
+
Project-URL: Documentation, https://github.com/herfy/herfy-shared/tree/main/herfy-gcs
|
|
9
|
+
Keywords: gcs,storage,upload,download,google-cloud,herfy
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: httpx>=0.24.0
|
|
23
|
+
Provides-Extra: fastapi
|
|
24
|
+
Requires-Dist: fastapi>=0.100.0; extra == "fastapi"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: respx>=0.20.0; extra == "dev"
|
|
30
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
32
|
+
|
|
33
|
+
# herfy-gcs
|
|
34
|
+
|
|
35
|
+
GCS storage SDK for Herfy applications.
|
|
36
|
+
Files are uploaded to and downloaded from Google Cloud Storage **through the Herfy Control Center** — apps never handle raw GCS credentials directly.
|
|
37
|
+
|
|
38
|
+
## How it works
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
App ──(client_id + secret)──► Control Center ──(service account)──► GCS bucket
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
1. Your app registered with the Control Center and received a `client_id` + `client_secret`.
|
|
45
|
+
2. The SDK exchanges those credentials for a short-lived CC access token (OAuth2 client credentials flow).
|
|
46
|
+
3. Upload / download requests go to the CC storage API; the CC proxies them to GCS under its own service account.
|
|
47
|
+
4. The CC enforces per-app bucket/prefix scoping — your app can only touch its own folder.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# From PyPI (once published)
|
|
53
|
+
pip install herfy-gcs==0.1.0
|
|
54
|
+
|
|
55
|
+
# Local editable install (monorepo / during development)
|
|
56
|
+
pip install -e /path/to/herfy-shared/herfy-gcs
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
### Environment variables
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
CONTROL_CENTER_URL=https://controlcenter-xxx.run.app
|
|
65
|
+
AUTH_CLIENT_ID=app_your_client_id # from CC registration
|
|
66
|
+
AUTH_CLIENT_SECRET=your_client_secret # from CC registration
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Optional overrides:
|
|
70
|
+
|
|
71
|
+
| Variable | Default | Description |
|
|
72
|
+
|------------------------|----------------|----------------------------------------------|
|
|
73
|
+
| `GCS_STORAGE_API_PATH` | `/api/storage` | CC storage endpoint prefix |
|
|
74
|
+
| `GCS_TOKEN_CACHE_TTL` | `240` | Seconds to cache the CC token |
|
|
75
|
+
| `GCS_UPLOAD_TIMEOUT` | `120` | HTTP timeout for upload/download (seconds) |
|
|
76
|
+
| `GCS_REQUEST_TIMEOUT` | `15` | HTTP timeout for metadata requests (seconds) |
|
|
77
|
+
|
|
78
|
+
### Sync client (default — works in FastAPI sync endpoints)
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from herfy_gcs import HerfyGCSClient
|
|
82
|
+
|
|
83
|
+
client = HerfyGCSClient.from_env()
|
|
84
|
+
|
|
85
|
+
# Upload a file
|
|
86
|
+
with open("deposit.pdf", "rb") as f:
|
|
87
|
+
result = client.upload(
|
|
88
|
+
content=f,
|
|
89
|
+
filename="deposit.pdf",
|
|
90
|
+
content_type="application/pdf",
|
|
91
|
+
folder="daily-cash/2025",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
print(result.file_ref) # store this in your database
|
|
95
|
+
|
|
96
|
+
# Get a signed download URL (valid for 1 hour)
|
|
97
|
+
url = client.get_download_url(result.file_ref, expires_in=3600)
|
|
98
|
+
|
|
99
|
+
# Download raw bytes
|
|
100
|
+
data = client.download(result.file_ref)
|
|
101
|
+
|
|
102
|
+
# Resolve any existing reference (GCS URL or CC ref) to a usable URL
|
|
103
|
+
url = client.resolve_url(existing_db_ref)
|
|
104
|
+
|
|
105
|
+
# Delete a file
|
|
106
|
+
client.delete(result.file_ref)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Async client (for async FastAPI endpoints)
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from herfy_gcs import AsyncHerfyGCSClient
|
|
113
|
+
|
|
114
|
+
client = AsyncHerfyGCSClient.from_env()
|
|
115
|
+
|
|
116
|
+
result = await client.upload(content=pdf_bytes, filename="doc.pdf", folder="daily-cash")
|
|
117
|
+
url = await client.get_download_url(result.file_ref)
|
|
118
|
+
data = await client.download(result.file_ref)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Explicit credentials (no env vars)
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
client = HerfyGCSClient.from_credentials(
|
|
125
|
+
client_id="app_7c144431f50c",
|
|
126
|
+
client_secret="your-secret",
|
|
127
|
+
control_center_url="https://controlcenter-xxx.run.app",
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### FastAPI dependency example
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from functools import lru_cache
|
|
135
|
+
from fastapi import Depends
|
|
136
|
+
from herfy_gcs import HerfyGCSClient
|
|
137
|
+
|
|
138
|
+
@lru_cache(maxsize=1)
|
|
139
|
+
def get_gcs_client() -> HerfyGCSClient:
|
|
140
|
+
return HerfyGCSClient.from_env()
|
|
141
|
+
|
|
142
|
+
@app.post("/upload")
|
|
143
|
+
async def upload_file(
|
|
144
|
+
file: UploadFile,
|
|
145
|
+
gcs: HerfyGCSClient = Depends(get_gcs_client),
|
|
146
|
+
):
|
|
147
|
+
result = gcs.upload(
|
|
148
|
+
content=await file.read(),
|
|
149
|
+
filename=file.filename,
|
|
150
|
+
content_type=file.content_type or "application/octet-stream",
|
|
151
|
+
folder="daily-cash",
|
|
152
|
+
)
|
|
153
|
+
return {"file_ref": result.file_ref, "url": result.url}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Control Center storage API
|
|
157
|
+
|
|
158
|
+
The CC must expose these endpoints (authenticated with a CC bearer token):
|
|
159
|
+
|
|
160
|
+
| Method | Path | Description |
|
|
161
|
+
|----------|--------------------------|---------------------------------|
|
|
162
|
+
| `POST` | `/api/storage/upload` | Multipart file upload |
|
|
163
|
+
| `POST` | `/api/storage/signed-url`| Generate a signed download URL |
|
|
164
|
+
| `GET` | `/api/storage/file` | Get file metadata (`?ref=<ref>`) |
|
|
165
|
+
| `GET` | `/api/storage/download` | Stream file bytes (`?ref=<ref>`) |
|
|
166
|
+
| `DELETE` | `/api/storage/file` | Delete a file (`?ref=<ref>`) |
|
|
167
|
+
|
|
168
|
+
### Upload request
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
POST /api/storage/upload
|
|
172
|
+
Authorization: Bearer <cc_token>
|
|
173
|
+
Content-Type: multipart/form-data
|
|
174
|
+
|
|
175
|
+
file=<bytes>
|
|
176
|
+
filename=deposit.pdf
|
|
177
|
+
folder=daily-cash/2025
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Response `200 OK`:
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"file_ref": "cc:bucket_herfy_datacloud/daily-cash/2025/deposit.pdf",
|
|
184
|
+
"url": "https://storage.googleapis.com/bucket_herfy_datacloud/...",
|
|
185
|
+
"filename": "deposit.pdf",
|
|
186
|
+
"content_type": "application/pdf",
|
|
187
|
+
"size": 204800,
|
|
188
|
+
"folder": "daily-cash/2025"
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Signed URL request
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
POST /api/storage/signed-url
|
|
196
|
+
Authorization: Bearer <cc_token>
|
|
197
|
+
Content-Type: application/json
|
|
198
|
+
|
|
199
|
+
{"file_ref": "cc:...", "expires_in": 3600}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Response `200 OK`:
|
|
203
|
+
```json
|
|
204
|
+
{"url": "https://storage.googleapis.com/...?X-Goog-Signature=...", "file_ref": "cc:...", "expires_in": 3600}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Error handling
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from herfy_gcs import HerfyGCSClient, UploadError, AuthError, FileNotFoundError, GCSError
|
|
211
|
+
|
|
212
|
+
client = HerfyGCSClient.from_env()
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
result = client.upload(content=data, filename="doc.pdf")
|
|
216
|
+
except AuthError as e:
|
|
217
|
+
# Invalid client_id/secret or CC unreachable
|
|
218
|
+
print(f"Auth failed: {e.message}")
|
|
219
|
+
except UploadError as e:
|
|
220
|
+
print(f"Upload failed (HTTP {e.status_code}): {e.message}")
|
|
221
|
+
except GCSError as e:
|
|
222
|
+
print(f"Storage error: {e.message}")
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# herfy-gcs
|
|
2
|
+
|
|
3
|
+
GCS storage SDK for Herfy applications.
|
|
4
|
+
Files are uploaded to and downloaded from Google Cloud Storage **through the Herfy Control Center** — apps never handle raw GCS credentials directly.
|
|
5
|
+
|
|
6
|
+
## How it works
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
App ──(client_id + secret)──► Control Center ──(service account)──► GCS bucket
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
1. Your app registered with the Control Center and received a `client_id` + `client_secret`.
|
|
13
|
+
2. The SDK exchanges those credentials for a short-lived CC access token (OAuth2 client credentials flow).
|
|
14
|
+
3. Upload / download requests go to the CC storage API; the CC proxies them to GCS under its own service account.
|
|
15
|
+
4. The CC enforces per-app bucket/prefix scoping — your app can only touch its own folder.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# From PyPI (once published)
|
|
21
|
+
pip install herfy-gcs==0.1.0
|
|
22
|
+
|
|
23
|
+
# Local editable install (monorepo / during development)
|
|
24
|
+
pip install -e /path/to/herfy-shared/herfy-gcs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
### Environment variables
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
CONTROL_CENTER_URL=https://controlcenter-xxx.run.app
|
|
33
|
+
AUTH_CLIENT_ID=app_your_client_id # from CC registration
|
|
34
|
+
AUTH_CLIENT_SECRET=your_client_secret # from CC registration
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Optional overrides:
|
|
38
|
+
|
|
39
|
+
| Variable | Default | Description |
|
|
40
|
+
|------------------------|----------------|----------------------------------------------|
|
|
41
|
+
| `GCS_STORAGE_API_PATH` | `/api/storage` | CC storage endpoint prefix |
|
|
42
|
+
| `GCS_TOKEN_CACHE_TTL` | `240` | Seconds to cache the CC token |
|
|
43
|
+
| `GCS_UPLOAD_TIMEOUT` | `120` | HTTP timeout for upload/download (seconds) |
|
|
44
|
+
| `GCS_REQUEST_TIMEOUT` | `15` | HTTP timeout for metadata requests (seconds) |
|
|
45
|
+
|
|
46
|
+
### Sync client (default — works in FastAPI sync endpoints)
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from herfy_gcs import HerfyGCSClient
|
|
50
|
+
|
|
51
|
+
client = HerfyGCSClient.from_env()
|
|
52
|
+
|
|
53
|
+
# Upload a file
|
|
54
|
+
with open("deposit.pdf", "rb") as f:
|
|
55
|
+
result = client.upload(
|
|
56
|
+
content=f,
|
|
57
|
+
filename="deposit.pdf",
|
|
58
|
+
content_type="application/pdf",
|
|
59
|
+
folder="daily-cash/2025",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
print(result.file_ref) # store this in your database
|
|
63
|
+
|
|
64
|
+
# Get a signed download URL (valid for 1 hour)
|
|
65
|
+
url = client.get_download_url(result.file_ref, expires_in=3600)
|
|
66
|
+
|
|
67
|
+
# Download raw bytes
|
|
68
|
+
data = client.download(result.file_ref)
|
|
69
|
+
|
|
70
|
+
# Resolve any existing reference (GCS URL or CC ref) to a usable URL
|
|
71
|
+
url = client.resolve_url(existing_db_ref)
|
|
72
|
+
|
|
73
|
+
# Delete a file
|
|
74
|
+
client.delete(result.file_ref)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Async client (for async FastAPI endpoints)
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from herfy_gcs import AsyncHerfyGCSClient
|
|
81
|
+
|
|
82
|
+
client = AsyncHerfyGCSClient.from_env()
|
|
83
|
+
|
|
84
|
+
result = await client.upload(content=pdf_bytes, filename="doc.pdf", folder="daily-cash")
|
|
85
|
+
url = await client.get_download_url(result.file_ref)
|
|
86
|
+
data = await client.download(result.file_ref)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Explicit credentials (no env vars)
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
client = HerfyGCSClient.from_credentials(
|
|
93
|
+
client_id="app_7c144431f50c",
|
|
94
|
+
client_secret="your-secret",
|
|
95
|
+
control_center_url="https://controlcenter-xxx.run.app",
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### FastAPI dependency example
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from functools import lru_cache
|
|
103
|
+
from fastapi import Depends
|
|
104
|
+
from herfy_gcs import HerfyGCSClient
|
|
105
|
+
|
|
106
|
+
@lru_cache(maxsize=1)
|
|
107
|
+
def get_gcs_client() -> HerfyGCSClient:
|
|
108
|
+
return HerfyGCSClient.from_env()
|
|
109
|
+
|
|
110
|
+
@app.post("/upload")
|
|
111
|
+
async def upload_file(
|
|
112
|
+
file: UploadFile,
|
|
113
|
+
gcs: HerfyGCSClient = Depends(get_gcs_client),
|
|
114
|
+
):
|
|
115
|
+
result = gcs.upload(
|
|
116
|
+
content=await file.read(),
|
|
117
|
+
filename=file.filename,
|
|
118
|
+
content_type=file.content_type or "application/octet-stream",
|
|
119
|
+
folder="daily-cash",
|
|
120
|
+
)
|
|
121
|
+
return {"file_ref": result.file_ref, "url": result.url}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Control Center storage API
|
|
125
|
+
|
|
126
|
+
The CC must expose these endpoints (authenticated with a CC bearer token):
|
|
127
|
+
|
|
128
|
+
| Method | Path | Description |
|
|
129
|
+
|----------|--------------------------|---------------------------------|
|
|
130
|
+
| `POST` | `/api/storage/upload` | Multipart file upload |
|
|
131
|
+
| `POST` | `/api/storage/signed-url`| Generate a signed download URL |
|
|
132
|
+
| `GET` | `/api/storage/file` | Get file metadata (`?ref=<ref>`) |
|
|
133
|
+
| `GET` | `/api/storage/download` | Stream file bytes (`?ref=<ref>`) |
|
|
134
|
+
| `DELETE` | `/api/storage/file` | Delete a file (`?ref=<ref>`) |
|
|
135
|
+
|
|
136
|
+
### Upload request
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
POST /api/storage/upload
|
|
140
|
+
Authorization: Bearer <cc_token>
|
|
141
|
+
Content-Type: multipart/form-data
|
|
142
|
+
|
|
143
|
+
file=<bytes>
|
|
144
|
+
filename=deposit.pdf
|
|
145
|
+
folder=daily-cash/2025
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Response `200 OK`:
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"file_ref": "cc:bucket_herfy_datacloud/daily-cash/2025/deposit.pdf",
|
|
152
|
+
"url": "https://storage.googleapis.com/bucket_herfy_datacloud/...",
|
|
153
|
+
"filename": "deposit.pdf",
|
|
154
|
+
"content_type": "application/pdf",
|
|
155
|
+
"size": 204800,
|
|
156
|
+
"folder": "daily-cash/2025"
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Signed URL request
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
POST /api/storage/signed-url
|
|
164
|
+
Authorization: Bearer <cc_token>
|
|
165
|
+
Content-Type: application/json
|
|
166
|
+
|
|
167
|
+
{"file_ref": "cc:...", "expires_in": 3600}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Response `200 OK`:
|
|
171
|
+
```json
|
|
172
|
+
{"url": "https://storage.googleapis.com/...?X-Goog-Signature=...", "file_ref": "cc:...", "expires_in": 3600}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Error handling
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from herfy_gcs import HerfyGCSClient, UploadError, AuthError, FileNotFoundError, GCSError
|
|
179
|
+
|
|
180
|
+
client = HerfyGCSClient.from_env()
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
result = client.upload(content=data, filename="doc.pdf")
|
|
184
|
+
except AuthError as e:
|
|
185
|
+
# Invalid client_id/secret or CC unreachable
|
|
186
|
+
print(f"Auth failed: {e.message}")
|
|
187
|
+
except UploadError as e:
|
|
188
|
+
print(f"Upload failed (HTTP {e.status_code}): {e.message}")
|
|
189
|
+
except GCSError as e:
|
|
190
|
+
print(f"Storage error: {e.message}")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Herfy GCS SDK — upload and download files via the Herfy Control Center.
|
|
3
|
+
|
|
4
|
+
Apps authenticate using their CC-registered client_id and client_secret.
|
|
5
|
+
The Control Center manages GCS bucket access and enforces per-app scoping.
|
|
6
|
+
|
|
7
|
+
Quick start::
|
|
8
|
+
|
|
9
|
+
from herfy_gcs import HerfyGCSClient
|
|
10
|
+
|
|
11
|
+
client = HerfyGCSClient.from_env() # reads AUTH_CLIENT_ID / AUTH_CLIENT_SECRET
|
|
12
|
+
|
|
13
|
+
# Upload
|
|
14
|
+
result = client.upload(content=pdf_bytes, filename="deposit.pdf", folder="daily-cash")
|
|
15
|
+
file_ref = result.file_ref # store in database
|
|
16
|
+
|
|
17
|
+
# Download URL (signed, expires in 1 hour)
|
|
18
|
+
url = client.get_download_url(file_ref, expires_in=3600)
|
|
19
|
+
|
|
20
|
+
# Or resolve any existing ref (GCS URL or CC ref) to a usable URL
|
|
21
|
+
url = client.resolve_url(existing_ref)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from .client import AsyncHerfyGCSClient, HerfyGCSClient
|
|
25
|
+
from .exceptions import (
|
|
26
|
+
AuthError,
|
|
27
|
+
ConfigurationError,
|
|
28
|
+
DownloadError,
|
|
29
|
+
FileNotFoundError,
|
|
30
|
+
GCSError,
|
|
31
|
+
UploadError,
|
|
32
|
+
)
|
|
33
|
+
from .models import FileInfo, GCSConfig, SignedUrlResult, UploadResult
|
|
34
|
+
|
|
35
|
+
__version__ = "0.1.0"
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
# Clients
|
|
39
|
+
"HerfyGCSClient",
|
|
40
|
+
"AsyncHerfyGCSClient",
|
|
41
|
+
# Config
|
|
42
|
+
"GCSConfig",
|
|
43
|
+
# Models
|
|
44
|
+
"UploadResult",
|
|
45
|
+
"FileInfo",
|
|
46
|
+
"SignedUrlResult",
|
|
47
|
+
# Exceptions
|
|
48
|
+
"GCSError",
|
|
49
|
+
"AuthError",
|
|
50
|
+
"UploadError",
|
|
51
|
+
"DownloadError",
|
|
52
|
+
"FileNotFoundError",
|
|
53
|
+
"ConfigurationError",
|
|
54
|
+
]
|