lfss 0.9.2__py3-none-any.whl → 0.11.4__py3-none-any.whl
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.
- Readme.md +4 -4
- docs/Enviroment_variables.md +4 -2
- docs/Permission.md +4 -4
- docs/Webdav.md +3 -3
- docs/changelog.md +58 -0
- frontend/api.js +66 -4
- frontend/login.js +0 -1
- frontend/popup.js +18 -3
- frontend/scripts.js +46 -39
- frontend/utils.js +98 -1
- lfss/api/__init__.py +7 -4
- lfss/api/connector.py +47 -11
- lfss/cli/cli.py +9 -9
- lfss/cli/log.py +77 -0
- lfss/cli/vacuum.py +69 -19
- lfss/eng/config.py +7 -5
- lfss/eng/connection_pool.py +12 -8
- lfss/eng/database.py +350 -140
- lfss/eng/error.py +6 -2
- lfss/eng/log.py +91 -21
- lfss/eng/thumb.py +20 -23
- lfss/eng/utils.py +50 -29
- lfss/sql/init.sql +9 -4
- lfss/svc/app.py +1 -1
- lfss/svc/app_base.py +8 -3
- lfss/svc/app_dav.py +74 -61
- lfss/svc/app_native.py +95 -59
- lfss/svc/common_impl.py +72 -37
- {lfss-0.9.2.dist-info → lfss-0.11.4.dist-info}/METADATA +10 -8
- lfss-0.11.4.dist-info/RECORD +52 -0
- {lfss-0.9.2.dist-info → lfss-0.11.4.dist-info}/entry_points.txt +1 -0
- lfss-0.9.2.dist-info/RECORD +0 -50
- {lfss-0.9.2.dist-info → lfss-0.11.4.dist-info}/WHEEL +0 -0
lfss/svc/common_impl.py
CHANGED
@@ -7,7 +7,7 @@ from ..eng.datatype import UserRecord, FileRecord, PathContents, AccessLevel, Fi
|
|
7
7
|
from ..eng.database import FileConn, UserConn, delayed_log_access, check_file_read_permission, check_path_permission
|
8
8
|
from ..eng.thumb import get_thumb
|
9
9
|
from ..eng.utils import format_last_modified, ensure_uri_compnents
|
10
|
-
from ..eng.config import CHUNK_SIZE
|
10
|
+
from ..eng.config import CHUNK_SIZE, DEBUG_MODE
|
11
11
|
|
12
12
|
from .app_base import skip_request_log, db, logger
|
13
13
|
|
@@ -60,10 +60,15 @@ async def emit_file(
|
|
60
60
|
else:
|
61
61
|
arng_e = range_end
|
62
62
|
|
63
|
-
if
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
if file_record.file_size > 0:
|
64
|
+
if arng_s >= file_record.file_size or arng_e >= file_record.file_size:
|
65
|
+
if DEBUG_MODE: print(f"[Invalid range] Actual range: {arng_s}-{arng_e} (size: {file_record.file_size})")
|
66
|
+
raise HTTPException(status_code=416, detail="Range not satisfiable")
|
67
|
+
if arng_s > arng_e:
|
68
|
+
raise HTTPException(status_code=416, detail="Invalid range")
|
69
|
+
else:
|
70
|
+
if not (arng_s == 0 and arng_e == -1):
|
71
|
+
raise HTTPException(status_code=416, detail="Invalid range (file size is 0)")
|
67
72
|
|
68
73
|
headers = {
|
69
74
|
"Content-Disposition": f"{disposition}; filename={fname}",
|
@@ -87,7 +92,7 @@ async def emit_file(
|
|
87
92
|
status_code=206 if range_start != -1 or range_end != -1 else 200
|
88
93
|
)
|
89
94
|
|
90
|
-
async def
|
95
|
+
async def get_impl(
|
91
96
|
request: Request,
|
92
97
|
user: UserRecord,
|
93
98
|
path: str,
|
@@ -96,40 +101,19 @@ async def get_file_impl(
|
|
96
101
|
is_head = False,
|
97
102
|
):
|
98
103
|
path = ensure_uri_compnents(path)
|
104
|
+
if path.startswith("/"): path = path[1:]
|
99
105
|
|
100
106
|
# handle directory query
|
101
107
|
if path == "": path = "/"
|
102
108
|
if path.endswith("/"):
|
103
|
-
|
104
|
-
async with unique_cursor() as cur:
|
105
|
-
fconn = FileConn(cur)
|
106
|
-
if user.id == 0:
|
107
|
-
raise HTTPException(status_code=401, detail="Permission denied, credential required")
|
108
|
-
if thumb:
|
109
|
-
return await emit_thumbnail(path, download, create_time=None)
|
110
|
-
|
111
|
-
if path == "/":
|
112
|
-
peer_users = await UserConn(cur).list_peer_users(user.id, AccessLevel.READ)
|
113
|
-
return PathContents(
|
114
|
-
dirs = await fconn.list_root_dirs(user.username, *[x.username for x in peer_users], skim=True) \
|
115
|
-
if not user.is_admin else await fconn.list_root_dirs(skim=True),
|
116
|
-
files = []
|
117
|
-
)
|
118
|
-
|
119
|
-
if not await check_path_permission(path, user, cursor=cur) >= AccessLevel.READ:
|
120
|
-
raise HTTPException(status_code=403, detail="Permission denied")
|
121
|
-
|
122
|
-
return await fconn.list_path(path)
|
109
|
+
return await _get_dir_impl(user=user, path=path, download=download, thumb=thumb, is_head=is_head)
|
123
110
|
|
124
111
|
# handle file query
|
125
112
|
async with unique_cursor() as cur:
|
126
113
|
fconn = FileConn(cur)
|
127
114
|
file_record = await fconn.get_file_record(path, throw=True)
|
128
|
-
uconn = UserConn(cur)
|
129
|
-
owner = await uconn.get_user_by_id(file_record.owner_id, throw=True)
|
130
|
-
|
131
115
|
if not await check_path_permission(path, user, cursor=cur) >= AccessLevel.READ:
|
132
|
-
allow_access, reason = check_file_read_permission(user,
|
116
|
+
allow_access, reason = await check_file_read_permission(user, file_record, cursor=cur)
|
133
117
|
if not allow_access:
|
134
118
|
raise HTTPException(status_code=403 if user.id != 0 else 401, detail=reason)
|
135
119
|
|
@@ -147,6 +131,9 @@ async def get_file_impl(
|
|
147
131
|
else:
|
148
132
|
range_start, range_end = -1, -1
|
149
133
|
|
134
|
+
if DEBUG_MODE:
|
135
|
+
print(f"Get range: {range_start}-{range_end}")
|
136
|
+
|
150
137
|
if thumb:
|
151
138
|
if (range_start != -1 or range_end != -1): logger.warning("Range request for thumbnail")
|
152
139
|
return await emit_thumbnail(path, download, create_time=file_record.create_time, is_head=is_head)
|
@@ -156,11 +143,55 @@ async def get_file_impl(
|
|
156
143
|
else:
|
157
144
|
return await emit_file(file_record, None, "inline", is_head = is_head, range_start=range_start, range_end=range_end)
|
158
145
|
|
146
|
+
async def _get_dir_impl(
|
147
|
+
user: UserRecord,
|
148
|
+
path: str,
|
149
|
+
download: bool = False,
|
150
|
+
thumb: bool = False,
|
151
|
+
is_head = False,
|
152
|
+
):
|
153
|
+
""" handle directory query, return file under the path as json """
|
154
|
+
assert path.endswith("/")
|
155
|
+
async with unique_cursor() as cur:
|
156
|
+
fconn = FileConn(cur)
|
157
|
+
if user.id == 0:
|
158
|
+
raise HTTPException(status_code=401, detail="Permission denied, credential required")
|
159
|
+
if thumb:
|
160
|
+
return await emit_thumbnail(path, download, create_time=None)
|
161
|
+
|
162
|
+
if path == "/":
|
163
|
+
if is_head: return Response(status_code=200)
|
164
|
+
peer_users = await UserConn(cur).list_peer_users(user.id, AccessLevel.READ)
|
165
|
+
return PathContents(
|
166
|
+
dirs = await fconn.list_root_dirs(user.username, *[x.username for x in peer_users], skim=True) \
|
167
|
+
if not user.is_admin else await fconn.list_root_dirs(skim=True),
|
168
|
+
files = []
|
169
|
+
)
|
170
|
+
|
171
|
+
if not await check_path_permission(path, user, cursor=cur) >= AccessLevel.READ:
|
172
|
+
raise HTTPException(status_code=403, detail="Permission denied")
|
173
|
+
|
174
|
+
path_sp = path.split("/")
|
175
|
+
if is_head:
|
176
|
+
if len(path_sp) == 2:
|
177
|
+
assert path_sp[1] == ""
|
178
|
+
if await UserConn(cur).get_user(path_sp[0]):
|
179
|
+
return Response(status_code=200)
|
180
|
+
else:
|
181
|
+
raise HTTPException(status_code=404, detail="User not found")
|
182
|
+
else:
|
183
|
+
if await FileConn(cur).count_dir_files(path, flat=True) > 0:
|
184
|
+
return Response(status_code=200)
|
185
|
+
else:
|
186
|
+
raise HTTPException(status_code=404, detail="Path not found")
|
187
|
+
|
188
|
+
return await fconn.list_path(path)
|
189
|
+
|
159
190
|
async def put_file_impl(
|
160
191
|
request: Request,
|
161
192
|
user: UserRecord,
|
162
193
|
path: str,
|
163
|
-
conflict: Literal["overwrite", "skip", "abort"] = "
|
194
|
+
conflict: Literal["overwrite", "skip", "abort"] = "overwrite",
|
164
195
|
permission: int = 0,
|
165
196
|
):
|
166
197
|
path = ensure_uri_compnents(path)
|
@@ -187,7 +218,9 @@ async def put_file_impl(
|
|
187
218
|
exists_flag = True
|
188
219
|
if await check_path_permission(path, user) < AccessLevel.WRITE:
|
189
220
|
raise HTTPException(status_code=403, detail="Permission denied, cannot overwrite other's file")
|
190
|
-
await db.delete_file(path)
|
221
|
+
old_record = await db.delete_file(path)
|
222
|
+
if old_record and permission == FileReadPermission.UNSET.value:
|
223
|
+
permission = old_record.permission.value # inherit permission
|
191
224
|
|
192
225
|
# check content-type
|
193
226
|
content_type = request.headers.get("Content-Type", "application/octet-stream")
|
@@ -213,7 +246,7 @@ async def post_file_impl(
|
|
213
246
|
path: str,
|
214
247
|
user: UserRecord,
|
215
248
|
file: UploadFile,
|
216
|
-
conflict: Literal["overwrite", "skip", "abort"] = "
|
249
|
+
conflict: Literal["overwrite", "skip", "abort"] = "overwrite",
|
217
250
|
permission: int = 0,
|
218
251
|
):
|
219
252
|
path = ensure_uri_compnents(path)
|
@@ -240,7 +273,9 @@ async def post_file_impl(
|
|
240
273
|
exists_flag = True
|
241
274
|
if await check_path_permission(path, user) < AccessLevel.WRITE:
|
242
275
|
raise HTTPException(status_code=403, detail="Permission denied, cannot overwrite other's file")
|
243
|
-
await db.delete_file(path)
|
276
|
+
old_record = await db.delete_file(path)
|
277
|
+
if old_record and permission == FileReadPermission.UNSET.value:
|
278
|
+
permission = old_record.permission.value # inherit permission
|
244
279
|
|
245
280
|
async def blob_reader():
|
246
281
|
nonlocal file
|
@@ -260,7 +295,7 @@ async def delete_impl(path: str, user: UserRecord):
|
|
260
295
|
logger.info(f"DELETE {path}, user: {user.username}")
|
261
296
|
|
262
297
|
if path.endswith("/"):
|
263
|
-
res = await db.
|
298
|
+
res = await db.delete_dir(path, user)
|
264
299
|
else:
|
265
300
|
res = await db.delete_file(path, user)
|
266
301
|
|
@@ -292,8 +327,8 @@ async def copy_impl(
|
|
292
327
|
else:
|
293
328
|
async with unique_cursor() as cur:
|
294
329
|
fconn = FileConn(cur)
|
295
|
-
dst_fcount = await fconn.
|
330
|
+
dst_fcount = await fconn.count_dir_files(dst_path, flat=True)
|
296
331
|
if dst_fcount > 0:
|
297
332
|
raise HTTPException(status_code=409, detail="Destination exists")
|
298
|
-
await db.
|
333
|
+
await db.copy_dir(src_path, dst_path, op_user)
|
299
334
|
return Response(status_code=201, content="OK")
|
@@ -1,28 +1,30 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lfss
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.11.4
|
4
4
|
Summary: Lightweight file storage service
|
5
5
|
Home-page: https://github.com/MenxLi/lfss
|
6
|
-
Author:
|
7
|
-
Author-email:
|
6
|
+
Author: Li, Mengxun
|
7
|
+
Author-email: mengxunli@whu.edu.cn
|
8
8
|
Requires-Python: >=3.10
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
13
|
-
Requires-Dist: aiofiles (==
|
13
|
+
Requires-Dist: aiofiles (==24.*)
|
14
14
|
Requires-Dist: aiosqlite (==0.*)
|
15
15
|
Requires-Dist: fastapi (==0.*)
|
16
16
|
Requires-Dist: mimesniff (==1.*)
|
17
17
|
Requires-Dist: pillow
|
18
18
|
Requires-Dist: python-multipart
|
19
19
|
Requires-Dist: requests (==2.*)
|
20
|
+
Requires-Dist: rich
|
21
|
+
Requires-Dist: stream-zip (==0.*)
|
20
22
|
Requires-Dist: uvicorn (==0.*)
|
21
23
|
Project-URL: Repository, https://github.com/MenxLi/lfss
|
22
24
|
Description-Content-Type: text/markdown
|
23
25
|
|
24
|
-
#
|
25
|
-
[](https://pypi.org/project/lfss/)
|
26
|
+
# Lite File Storage Service (LFSS)
|
27
|
+
[](https://pypi.org/project/lfss/) [](https://pypi.org/project/lfss/)
|
26
28
|
|
27
29
|
My experiment on a lightweight and high-performance file/object storage service...
|
28
30
|
|
@@ -55,8 +57,8 @@ Or, you can start a web server at `/frontend` and open `index.html` in your brow
|
|
55
57
|
|
56
58
|
The API usage is simple, just `GET`, `PUT`, `DELETE` to the `/<username>/file/url` path.
|
57
59
|
The authentication can be acheived through one of the following methods:
|
58
|
-
1. `Authorization` header with the value `Bearer sha256(<username
|
59
|
-
2. `token` query parameter with the value `sha256(<username
|
60
|
+
1. `Authorization` header with the value `Bearer sha256(<username>:<password>)`.
|
61
|
+
2. `token` query parameter with the value `sha256(<username>:<password>)`.
|
60
62
|
3. HTTP Basic Authentication with the username and password (If WebDAV is enabled).
|
61
63
|
|
62
64
|
You can refer to `frontend` as an application example, `lfss/api/connector.py` for more APIs.
|
@@ -0,0 +1,52 @@
|
|
1
|
+
Readme.md,sha256=B-foESzFWoSI5MEd89AWUzKcVRrTwipM28TK8GN0o8c,1920
|
2
|
+
docs/Enviroment_variables.md,sha256=CZ5DrrXSLU5RLBEVQ-gLMaOIuFthd7dEiTzO7ODrPRQ,788
|
3
|
+
docs/Known_issues.md,sha256=ZqETcWP8lzTOel9b2mxEgCnADFF8IxOrEtiVO1NoMAk,251
|
4
|
+
docs/Permission.md,sha256=thUJx7YRoU63Pb-eqo5l5450DrZN3QYZ36GCn8r66no,3152
|
5
|
+
docs/Webdav.md,sha256=-Ja-BTWSY1BEMAyZycvEMNnkNTPZ49gSPzmf3Lbib70,1547
|
6
|
+
docs/changelog.md,sha256=fE0rE2IcovbxMhdTeqhnCnknT1vtVr7A860zIh7AEnE,1581
|
7
|
+
frontend/api.js,sha256=F35jQjWF2LITkuO-wZJuEKyafLWFx_M4C2tEYJV8zak,22631
|
8
|
+
frontend/index.html,sha256=-k0bJ5FRqdl_H-O441D_H9E-iejgRCaL_z5UeYaS2qc,3384
|
9
|
+
frontend/info.css,sha256=Ny0N3GywQ3a9q1_Qph_QFEKB4fEnTe_2DJ1Y5OsLLmQ,595
|
10
|
+
frontend/info.js,sha256=xGUJPCSrtDhuSu0ELLQZ77PmVWldg-prU1mwQGbdEoA,5797
|
11
|
+
frontend/login.css,sha256=VMM0QfbDFYerxKWKSGhMI1yg5IRBXg0TTdLJEEhQZNk,355
|
12
|
+
frontend/login.js,sha256=xJkulk8dlvV4BhevADLeUrnZwShiFTWv3Wg2iJFUZlY,2423
|
13
|
+
frontend/popup.css,sha256=TJZYFW1ZcdD1IVTlNPYNtMWKPbN6XDbQ4hKBOFK8uLg,1284
|
14
|
+
frontend/popup.js,sha256=cyUjtO0wbtqbEodHfwyUsak9iWbcDXeWMGDhpCPbcoE,5453
|
15
|
+
frontend/scripts.js,sha256=T3kMjTxrjOkp93OV4ZMGgCLRRaQgRmNzzxriOMGVeZM,24412
|
16
|
+
frontend/state.js,sha256=vbNL5DProRKmSEY7xu9mZH6IY0PBenF8WGxPtGgDnLI,1680
|
17
|
+
frontend/styles.css,sha256=xcNLqI3KBsY5TLnku8UIP0Jfr7QLajr1_KNlZj9eheM,4935
|
18
|
+
frontend/thumb.css,sha256=rNsx766amYS2DajSQNabhpQ92gdTpNoQKmV69OKvtpI,295
|
19
|
+
frontend/thumb.js,sha256=46ViD2TlTTWy0fx6wjoAs_5CQ4ajYB90vVzM7UO2IHw,6182
|
20
|
+
frontend/utils.js,sha256=XP5hM_mROYaxK5dqn9qZVwv7GdQuiDzByilFskbrnxA,6068
|
21
|
+
lfss/api/__init__.py,sha256=zT1JCiUM76wX-GtRrmKhTUzSYYfcmoyI1vYwN0fCcLw,6818
|
22
|
+
lfss/api/connector.py,sha256=o0_Ws1cmDJdM5YFKy5EhwStU9nW9a05CrjVYDex0Hmo,13931
|
23
|
+
lfss/cli/__init__.py,sha256=lPwPmqpa7EXQ4zlU7E7LOe6X2kw_xATGdwoHphUEirA,827
|
24
|
+
lfss/cli/balance.py,sha256=fUbKKAUyaDn74f7mmxMfBL4Q4voyBLHu6Lg_g8GfMOQ,4121
|
25
|
+
lfss/cli/cli.py,sha256=QLItJBjCJv6mWMUp5T6M0tUBuBzWr8yxoqn6V55Mb7I,8193
|
26
|
+
lfss/cli/log.py,sha256=TBlt8mhHMouv8ZBUMHYfGZiV6-0yPdajJQ5mkGHEojI,3016
|
27
|
+
lfss/cli/panel.py,sha256=Xq3I_n-ctveym-Gh9LaUpzHiLlvt3a_nuDiwUS-MGrg,1597
|
28
|
+
lfss/cli/serve.py,sha256=vTo6_BiD7Dn3VLvHsC5RKRBC3lMu45JVr_0SqpgHdj0,1086
|
29
|
+
lfss/cli/user.py,sha256=1mTroQbaKxHjFCPHT67xwd08v-zxH0RZ_OnVc-4MzL0,5364
|
30
|
+
lfss/cli/vacuum.py,sha256=arEY89kYJKEpzuzjKtf21V7s0QzM1t3QWa1hNghhT0Q,6611
|
31
|
+
lfss/eng/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
|
+
lfss/eng/bounded_pool.py,sha256=BI1dU-MBf82TMwJBYbjhEty7w1jIUKc5Bn9SnZ_-hoY,1288
|
33
|
+
lfss/eng/config.py,sha256=0dncHYn3tYw4pKBwXuP_huz0u7ud23fJ6SUmUPfLmeM,967
|
34
|
+
lfss/eng/connection_pool.py,sha256=1aq7nSgd7hB9YNV4PjD1RDRyl_moDw3ubBtSLyfgGBs,6320
|
35
|
+
lfss/eng/database.py,sha256=fd0ICcOYO5yQbXfYO9OaKk280-jSbJO2c008JUvHVcs,57238
|
36
|
+
lfss/eng/datatype.py,sha256=27UB7-l9SICy5lAvKjdzpTL_GohZjzstQcr9PtAq7nM,2709
|
37
|
+
lfss/eng/error.py,sha256=JGf5NV-f4rL6tNIDSAx5-l9MG8dEj7F2w_MuOjj1d1o,732
|
38
|
+
lfss/eng/log.py,sha256=yciFQ7Utz1AItNekS4YtdP6bM7i1krA6qSAU2wVQv24,7698
|
39
|
+
lfss/eng/thumb.py,sha256=AFyWEkkpuCKGWOB9bLlaDwPKzQ9JtCSSmHMhX2Gu3CI,3096
|
40
|
+
lfss/eng/utils.py,sha256=jQUJWWmzOPmXdTCId2Y307m1cZfB4hpzHcTjO0mkOrU,6683
|
41
|
+
lfss/sql/init.sql,sha256=FBmVzkNjYUnWjEELRFzf7xb50GngmzmeDVffT1Uk8u8,1625
|
42
|
+
lfss/sql/pragma.sql,sha256=uENx7xXjARmro-A3XAK8OM8v5AxDMdCCRj47f86UuXg,206
|
43
|
+
lfss/svc/app.py,sha256=r1KUO3sPaaJWbkJF0bcVTD7arPKLs2jFlq52Ixicomo,220
|
44
|
+
lfss/svc/app_base.py,sha256=s5ieQVI4BT0CBYavRx0dyBqwts7PYnjyCovHNYPHul8,7014
|
45
|
+
lfss/svc/app_dav.py,sha256=H3aL3MEdYaPK1w3FQvTzrGYGaaow4m8LZ7R35MN351A,18238
|
46
|
+
lfss/svc/app_native.py,sha256=zQM9o6HKtMVpq2WDZ77oc8tRnBdUdTkYHeV92NonGoo,10601
|
47
|
+
lfss/svc/common_impl.py,sha256=7QflWnxRqghLOSMpDz2UCRqEn49X1GLS3agCb5msia8,13729
|
48
|
+
lfss/svc/request_log.py,sha256=v8yXEIzPjaksu76Oh5vgdbUEUrw8Kt4etLAXBWSGie8,3207
|
49
|
+
lfss-0.11.4.dist-info/METADATA,sha256=qEO9CaHZXLivlr5de-3nYtpyFsGfIv-L1AMA_Ae4mWI,2732
|
50
|
+
lfss-0.11.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
51
|
+
lfss-0.11.4.dist-info/entry_points.txt,sha256=R4uOP1y6eD0Qp3j1ySA8kRPVMdt6_W_9o-Zj9Ra4D0A,232
|
52
|
+
lfss-0.11.4.dist-info/RECORD,,
|
lfss-0.9.2.dist-info/RECORD
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
Readme.md,sha256=JVe9T6N1Rz4hTiiCVoDYe2VB0dAi60VcBgb2twQdfZc,1834
|
2
|
-
docs/Enviroment_variables.md,sha256=LUZF1o70emp-5UPsvXPjcxapP940OqEZzSyyUUT9bEQ,569
|
3
|
-
docs/Known_issues.md,sha256=ZqETcWP8lzTOel9b2mxEgCnADFF8IxOrEtiVO1NoMAk,251
|
4
|
-
docs/Permission.md,sha256=mvK8gVBBgoIFJqikcaReU_bUo-mTq_ECqJaDDJoQF7Q,3126
|
5
|
-
docs/Webdav.md,sha256=9Q41ROEJodVVAnlo1Tf0jqsyrbuHhv_ElSsXbIPXYIg,1547
|
6
|
-
frontend/api.js,sha256=GlQsNoZFEcy7QUUsLbXv7aP-KxRnIxM37FQHTaakGiQ,19387
|
7
|
-
frontend/index.html,sha256=-k0bJ5FRqdl_H-O441D_H9E-iejgRCaL_z5UeYaS2qc,3384
|
8
|
-
frontend/info.css,sha256=Ny0N3GywQ3a9q1_Qph_QFEKB4fEnTe_2DJ1Y5OsLLmQ,595
|
9
|
-
frontend/info.js,sha256=xGUJPCSrtDhuSu0ELLQZ77PmVWldg-prU1mwQGbdEoA,5797
|
10
|
-
frontend/login.css,sha256=VMM0QfbDFYerxKWKSGhMI1yg5IRBXg0TTdLJEEhQZNk,355
|
11
|
-
frontend/login.js,sha256=QoO8yKmBHDVP-ZomCMOaV7xVUVIhpl7esJrb6T5aHQE,2466
|
12
|
-
frontend/popup.css,sha256=TJZYFW1ZcdD1IVTlNPYNtMWKPbN6XDbQ4hKBOFK8uLg,1284
|
13
|
-
frontend/popup.js,sha256=3PgaGZmxSdV1E-D_MWgcR7aHWkcsHA1BNKSOkmP66tA,5191
|
14
|
-
frontend/scripts.js,sha256=2-Omsb1-s4Wc859_SYw8JGyeUSiADaH9va4w87Mozns,24134
|
15
|
-
frontend/state.js,sha256=vbNL5DProRKmSEY7xu9mZH6IY0PBenF8WGxPtGgDnLI,1680
|
16
|
-
frontend/styles.css,sha256=xcNLqI3KBsY5TLnku8UIP0Jfr7QLajr1_KNlZj9eheM,4935
|
17
|
-
frontend/thumb.css,sha256=rNsx766amYS2DajSQNabhpQ92gdTpNoQKmV69OKvtpI,295
|
18
|
-
frontend/thumb.js,sha256=46ViD2TlTTWy0fx6wjoAs_5CQ4ajYB90vVzM7UO2IHw,6182
|
19
|
-
frontend/utils.js,sha256=IYUZl77ugiXKcLxSNOWC4NSS0CdD5yRgUsDb665j0xM,2556
|
20
|
-
lfss/api/__init__.py,sha256=8IJqrpWK1doIyVVbntvVic82A57ncwl5b0BRHX4Ri6A,6660
|
21
|
-
lfss/api/connector.py,sha256=hHSEEWecKQGZH6oxAmYoG3q7lFfacCbOKVZiUIXT2y8,11819
|
22
|
-
lfss/cli/__init__.py,sha256=lPwPmqpa7EXQ4zlU7E7LOe6X2kw_xATGdwoHphUEirA,827
|
23
|
-
lfss/cli/balance.py,sha256=fUbKKAUyaDn74f7mmxMfBL4Q4voyBLHu6Lg_g8GfMOQ,4121
|
24
|
-
lfss/cli/cli.py,sha256=aYjB8d4k6JUd9efxZK-XOj-mlG4JeOr_0lnj2qqCiK0,8066
|
25
|
-
lfss/cli/panel.py,sha256=Xq3I_n-ctveym-Gh9LaUpzHiLlvt3a_nuDiwUS-MGrg,1597
|
26
|
-
lfss/cli/serve.py,sha256=vTo6_BiD7Dn3VLvHsC5RKRBC3lMu45JVr_0SqpgHdj0,1086
|
27
|
-
lfss/cli/user.py,sha256=1mTroQbaKxHjFCPHT67xwd08v-zxH0RZ_OnVc-4MzL0,5364
|
28
|
-
lfss/cli/vacuum.py,sha256=GOG72d3NYe9bYCNc3y8JecEmM-DrKlGq3JQcisv_xBg,3702
|
29
|
-
lfss/eng/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
|
-
lfss/eng/bounded_pool.py,sha256=BI1dU-MBf82TMwJBYbjhEty7w1jIUKc5Bn9SnZ_-hoY,1288
|
31
|
-
lfss/eng/config.py,sha256=DmnUYMeLOL-45OstysyMpSBPmLofgzvcSrsWjHvssYs,915
|
32
|
-
lfss/eng/connection_pool.py,sha256=-tePasJxiZZ73ymgWf_kFnaKouc4Rrr4K6EXwjb7Mm4,6141
|
33
|
-
lfss/eng/database.py,sha256=cfMq7Hgj8cHFtynDzpRiqb0XYNb6OKWMYc8PcWl8eVw,47285
|
34
|
-
lfss/eng/datatype.py,sha256=27UB7-l9SICy5lAvKjdzpTL_GohZjzstQcr9PtAq7nM,2709
|
35
|
-
lfss/eng/error.py,sha256=sDbXo2R3APJAV0KtoYGCHx2qVZso7svtDzq-WjnzhAw,595
|
36
|
-
lfss/eng/log.py,sha256=u6WRZZsE7iOx6_CV2NHh1ugea26p408FI4WstZh896A,5139
|
37
|
-
lfss/eng/thumb.py,sha256=YO1yTI8WzW7pBpQN9x5PtPayxhftb32IJl1zPSS9mks,3243
|
38
|
-
lfss/eng/utils.py,sha256=zZ7r9BsNV8XJJVNOxfIqRCO1bxNzh7bc9vEJiCkgbKI,6208
|
39
|
-
lfss/sql/init.sql,sha256=8LjHx0TBCkBD62xFfssSeHDqKYVQQJkZAg4rSm046f4,1496
|
40
|
-
lfss/sql/pragma.sql,sha256=uENx7xXjARmro-A3XAK8OM8v5AxDMdCCRj47f86UuXg,206
|
41
|
-
lfss/svc/app.py,sha256=ftWCpepBx-gTSG7i-TB-IdinPPstAYYQjCgnTfeMZeI,219
|
42
|
-
lfss/svc/app_base.py,sha256=nc02DP4iMKP41fRl8M-iAhbHwyb4QJJTKKSJwtdCox4,6617
|
43
|
-
lfss/svc/app_dav.py,sha256=nPMdPsYNcgxqHOt5bDaaA0Wy8AdRDJajEda_-KxOoHA,17466
|
44
|
-
lfss/svc/app_native.py,sha256=xwMCOWp4ne3rmtiiYhfxETi__V-zPEfHw-c4iWNtXWc,9471
|
45
|
-
lfss/svc/common_impl.py,sha256=_biK0F_AAw4PnMNWR0WuHJSRyIp1iTSOOIPBauZCJ9M,12143
|
46
|
-
lfss/svc/request_log.py,sha256=v8yXEIzPjaksu76Oh5vgdbUEUrw8Kt4etLAXBWSGie8,3207
|
47
|
-
lfss-0.9.2.dist-info/METADATA,sha256=0Q5klZ2iwBF1ZUQ5iximW02mMmoAM5ib08s0IsdyuLE,2594
|
48
|
-
lfss-0.9.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
49
|
-
lfss-0.9.2.dist-info/entry_points.txt,sha256=VJ8svMz7RLtMCgNk99CElx7zo7M-N-z7BWDVw2HA92E,205
|
50
|
-
lfss-0.9.2.dist-info/RECORD,,
|
File without changes
|