This commit is contained in:
parent
456e3c0823
commit
e0fcf53788
@ -1,9 +1,8 @@
|
|||||||
# RUpload
|
# RUpload
|
||||||
|
|
||||||
## About
|
Easiest file manager for your server made for public use.
|
||||||
Easiest way to upload files to a server.
|
|
||||||
|
|
||||||
Since it doesn't have captcha or whatsoever, it's only usable with people you trust on a not listed domain. It's destined for public use, as long the domain isn't listed in a search engine. It has a limitation for file size, so it would never go terribly wrong.
|
It doesn't have captcha or whatsoever. It's designed for public use, as long the domain isn't listed in a search engine. It has a limitation for file size, that's it's only security. Rate limiting is in consideration. The default file size is 50Mb. The default storage quota for whole directory is 10Gb. Default config will prevent your server for heavy abuse.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
```
|
```
|
||||||
|
BIN
dist/rupload-1.3.37-py3-none-any.whl
vendored
BIN
dist/rupload-1.3.37-py3-none-any.whl
vendored
Binary file not shown.
BIN
dist/rupload-1.3.37.tar.gz
vendored
BIN
dist/rupload-1.3.37.tar.gz
vendored
Binary file not shown.
@ -12,10 +12,9 @@ Requires-Dist: dataset==1.6.2
|
|||||||
|
|
||||||
# RUpload
|
# RUpload
|
||||||
|
|
||||||
## About
|
Easiest file manager for your server made for public use.
|
||||||
Easiest way to upload files to a server.
|
|
||||||
|
|
||||||
Since it doesn't have captcha or whatsoever, it's only usable with people you trust on a not listed domain. It's destined for public use, as long the domain isn't listed in a search engine. It has a limitation for file size, so it would never go terribly wrong.
|
It doesn't have captcha or whatsoever. It's designed for public use, as long the domain isn't listed in a search engine. It has a limitation for file size, that's it's only security. Rate limiting is in consideration. The default file size is 50Mb. The default storage quota for whole directory is 10Gb. Default config will prevent your server for heavy abuse.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
```
|
```
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -5,12 +5,26 @@ import pathlib
|
|||||||
|
|
||||||
|
|
||||||
class Rupload(web.Application):
|
class Rupload(web.Application):
|
||||||
def __init__(self, upload_url:str="/uploads/", upload_path:str="uploads", max_file_size:int=1024*1024*50):
|
def __init__(
|
||||||
self.upload_path = upload_path
|
self,
|
||||||
|
upload_url: str = "/uploads/",
|
||||||
|
upload_path: str = "uploads",
|
||||||
|
max_file_size: int = 1024 * 1024 * 50,
|
||||||
|
upload_folder_quota: int = 10 * 1024 * 1024 * 1024,
|
||||||
|
):
|
||||||
|
self.upload_path = upload_path.rstrip("/")
|
||||||
self.max_file_size = max_file_size
|
self.max_file_size = max_file_size
|
||||||
self.upload_url = upload_url
|
self.upload_url = upload_url.rstrip("/")
|
||||||
|
self.upload_folder_quota = upload_folder_quota
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_upload_folder_quota_reached(self):
|
||||||
|
return pathlib.Path(self.upload_path).stat().st_size > self.upload_folder_quota
|
||||||
|
|
||||||
|
def generate_upload_url(self, filename):
|
||||||
|
return self.upload_url + filename
|
||||||
|
|
||||||
|
|
||||||
UPLOAD_PAGE = """
|
UPLOAD_PAGE = """
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -129,6 +143,7 @@ UPLOAD_PAGE = """
|
|||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def format_size(size):
|
def format_size(size):
|
||||||
if size < 1024:
|
if size < 1024:
|
||||||
return f"{size} B"
|
return f"{size} B"
|
||||||
@ -141,13 +156,21 @@ def format_size(size):
|
|||||||
else:
|
else:
|
||||||
return f"{size / 1024 * 1024 * 1024 * 1024:.2f} TB"
|
return f"{size / 1024 * 1024 * 1024 * 1024:.2f} TB"
|
||||||
|
|
||||||
|
|
||||||
def get_images(path):
|
def get_images(path):
|
||||||
images = []
|
images = []
|
||||||
for image in pathlib.Path(path).iterdir():
|
for image in pathlib.Path(path).iterdir():
|
||||||
if image.is_file() and image.suffix in [".png", ".jpg", ".gif", ".jpeg", ".bmp"]:
|
if image.is_file() and image.suffix in [
|
||||||
|
".png",
|
||||||
|
".jpg",
|
||||||
|
".gif",
|
||||||
|
".jpeg",
|
||||||
|
".bmp",
|
||||||
|
]:
|
||||||
images.append(image)
|
images.append(image)
|
||||||
return images
|
return images
|
||||||
|
|
||||||
|
|
||||||
def get_files(path):
|
def get_files(path):
|
||||||
images = get_images(path)
|
images = get_images(path)
|
||||||
files = []
|
files = []
|
||||||
@ -156,6 +179,7 @@ def get_files(path):
|
|||||||
files.append(file)
|
files.append(file)
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
def create_images_html(url, image_paths):
|
def create_images_html(url, image_paths):
|
||||||
images_html = ""
|
images_html = ""
|
||||||
for image_path in image_paths:
|
for image_path in image_paths:
|
||||||
@ -163,6 +187,7 @@ def create_images_html(url, image_paths):
|
|||||||
images_html += f'<img class="thumbnail" src="{path}" alt="{image_path.name}">'
|
images_html += f'<img class="thumbnail" src="{path}" alt="{image_path.name}">'
|
||||||
return images_html
|
return images_html
|
||||||
|
|
||||||
|
|
||||||
def create_files_html(url, file_paths):
|
def create_files_html(url, file_paths):
|
||||||
files_html = ""
|
files_html = ""
|
||||||
for file_path in file_paths:
|
for file_path in file_paths:
|
||||||
@ -170,7 +195,13 @@ def create_files_html(url, file_paths):
|
|||||||
files_html += f'<a href="{path}">{file_path.name}</a> ({format_size(file_path.stat().st_size)})<br>'
|
files_html += f'<a href="{path}">{file_path.name}</a> ({format_size(file_path.stat().st_size)})<br>'
|
||||||
return files_html
|
return files_html
|
||||||
|
|
||||||
async def handle_upload(request:web.Request):
|
|
||||||
|
async def handle_upload(request: web.Request):
|
||||||
|
if request.app.is_upload_folder_quota_reached:
|
||||||
|
return web.HTTPFound(
|
||||||
|
"/?message=Server%20reached%20quota!%20Contact%20administrator."
|
||||||
|
)
|
||||||
|
|
||||||
reader = await request.multipart()
|
reader = await request.multipart()
|
||||||
field = await reader.next()
|
field = await reader.next()
|
||||||
app = request.app
|
app = request.app
|
||||||
@ -212,32 +243,55 @@ async def handle_upload(request:web.Request):
|
|||||||
)
|
)
|
||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
print(f"File {filename} uploaded successfully.")
|
print(f"File {filename} uploaded successfully.")
|
||||||
uploaded_url = app.upload_url.rstrip("/") + "/" + filename
|
uploaded_url = self.generate_upload_url(filename)
|
||||||
print(f"File {filename} is now available at: {uploaded_url}.")
|
print(f"File {filename} is now available at: {uploaded_url}.")
|
||||||
return web.HTTPFound("/?message=File is succesfully uploaded and is available here:" + uploaded_url)
|
return web.HTTPFound(
|
||||||
|
"/?message=File is succesfully uploaded and is available here:"
|
||||||
|
+ uploaded_url
|
||||||
|
)
|
||||||
print("No file uploaded.")
|
print("No file uploaded.")
|
||||||
return web.Response(status=400, text="No file uploaded.")
|
return web.Response(status=400, text="No file uploaded.")
|
||||||
|
|
||||||
|
|
||||||
async def handle_index(request:web.Request):
|
async def handle_index(request: web.Request):
|
||||||
image_paths = get_images(request.app.upload_path)
|
image_paths = get_images(request.app.upload_path)
|
||||||
images_html = create_images_html(url=request.app.upload_url,image_paths=image_paths)
|
images_html = create_images_html(
|
||||||
|
url=request.app.upload_url, image_paths=image_paths
|
||||||
|
)
|
||||||
file_paths = get_files(request.app.upload_path)
|
file_paths = get_files(request.app.upload_path)
|
||||||
files_html = create_files_html(url=request.app.upload_url,file_paths=file_paths)
|
files_html = create_files_html(url=request.app.upload_url, file_paths=file_paths)
|
||||||
html_content = UPLOAD_PAGE.replace("[images_html]",images_html)
|
html_content = UPLOAD_PAGE.replace("[images_html]", images_html)
|
||||||
html_content = html_content.replace("[files_html]",files_html)
|
html_content = html_content.replace("[files_html]", files_html)
|
||||||
message = request.query.get("message", "")
|
message = request.query.get("message", "")
|
||||||
|
if request.app.is_upload_folder_quota_reached:
|
||||||
|
message = "Server reached quota! Contact administrator."
|
||||||
if request.app.upload_url in message:
|
if request.app.upload_url in message:
|
||||||
url = message[message.find(request.app.upload_url):]
|
url = message[message.find(request.app.upload_url) :]
|
||||||
message = message.replace(request.app.upload_url, f" <a href=\"{url}")
|
message = message.replace(request.app.upload_url, f' <a href="{url}')
|
||||||
message += f"\">{url}</a>"
|
message += f'">{url}</a>'
|
||||||
if message:
|
if message:
|
||||||
message += "<br /><br />"
|
message += "<br /><br />"
|
||||||
html_content = html_content.replace("[message]",message)
|
html_content = html_content.replace("[message]", message)
|
||||||
return web.Response(text=html_content, content_type="text/html")
|
return web.Response(text=html_content, content_type="text/html")
|
||||||
|
|
||||||
|
|
||||||
def create_app(upload_url:str="/", upload_path:str="upload", max_file_size:int=1024 * 1024 * 50):
|
def create_app(
|
||||||
app = Rupload(upload_url=upload_url, upload_path=upload_path, max_file_size=max_file_size)
|
upload_url: str = "/",
|
||||||
app.add_routes([web.get("/", handle_index), web.post("/upload", handle_upload),web.static("/uploads", "uploads")])
|
upload_path: str = "upload",
|
||||||
|
max_file_size: int = 1024 * 1024 * 50,
|
||||||
|
upload_folder_quota: int = 10 * 1024 * 1024 * 1024,
|
||||||
|
):
|
||||||
|
app = Rupload(
|
||||||
|
upload_url=upload_url,
|
||||||
|
upload_path=upload_path,
|
||||||
|
max_file_size=max_file_size,
|
||||||
|
upload_folder_quota=upload_folder_quota,
|
||||||
|
)
|
||||||
|
app.add_routes(
|
||||||
|
[
|
||||||
|
web.get("/", handle_index),
|
||||||
|
web.post("/upload", handle_upload),
|
||||||
|
web.static("/uploads", "uploads"),
|
||||||
|
]
|
||||||
|
)
|
||||||
return app
|
return app
|
||||||
|
@ -29,12 +29,23 @@ def parse_args():
|
|||||||
default=50 * 1024 * 1024,
|
default=50 * 1024 * 1024,
|
||||||
help="Maximum file size in bytes (default is 50MB).",
|
help="Maximum file size in bytes (default is 50MB).",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--upload_folder_quota",
|
||||||
|
type=int,
|
||||||
|
default=10 * 1024 * 1024 * 1024,
|
||||||
|
help="Quata upload folder in bytes (default is 10GB).",
|
||||||
|
)
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
app = create_app(upload_url=args.upload_url, upload_path=args.upload_folder, max_file_size=args.max_file_size)
|
app = create_app(
|
||||||
|
upload_url=args.upload_url,
|
||||||
|
upload_path=args.upload_folder,
|
||||||
|
max_file_size=args.max_file_size,
|
||||||
|
upload_folder_quota=args.upload_folder_quota,
|
||||||
|
)
|
||||||
web.run_app(app, host=args.hostname, port=args.port)
|
web.run_app(app, host=args.hostname, port=args.port)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user