add garbageCollector
This commit is contained in:
parent
5ed71bdcdd
commit
ee414d4b57
113
garbageCollector/collector.py
Normal file
113
garbageCollector/collector.py
Normal file
@ -0,0 +1,113 @@
|
||||
from flask import Flask, render_template_string, request, redirect, url_for, abort
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from config import BASE_DIRS, DEFAULT_BASE
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
|
||||
def get_base(name):
|
||||
if name not in BASE_DIRS:
|
||||
abort(400)
|
||||
return BASE_DIRS[name]
|
||||
|
||||
|
||||
def safe_path(base: Path, rel: str) -> Path:
|
||||
"""Resolve rel under base and prevent path traversal."""
|
||||
target = (base / rel).resolve()
|
||||
if not str(target).startswith(str(base)):
|
||||
abort(403)
|
||||
return target
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
base_name = request.args.get("base", DEFAULT_BASE)
|
||||
base = get_base(base_name)
|
||||
rel = request.args.get("path", "")
|
||||
current = safe_path(base, rel)
|
||||
|
||||
if not current.exists() or not current.is_dir():
|
||||
abort(404)
|
||||
|
||||
items = []
|
||||
for p in sorted(current.iterdir(), key=lambda x: (x.is_file(), x.name.lower())):
|
||||
items.append({
|
||||
"name": p.name,
|
||||
"is_dir": p.is_dir(),
|
||||
"rel": str(p.relative_to(base)),
|
||||
})
|
||||
|
||||
return render_template_string(TEMPLATE, items=items, base_name=base_name, rel=rel, bases=BASE_DIRS.keys())
|
||||
|
||||
|
||||
@app.post("/delete")
|
||||
def delete():
|
||||
base_name = request.form.get("base", DEFAULT_BASE)
|
||||
base = get_base(base_name)
|
||||
rel = request.form.get("path")
|
||||
target = safe_path(base, rel)
|
||||
|
||||
if not target.exists():
|
||||
abort(404)
|
||||
|
||||
if target.is_dir():
|
||||
shutil.rmtree(target)
|
||||
else:
|
||||
target.unlink()
|
||||
|
||||
parent = os.path.dirname(rel)
|
||||
return redirect(url_for("index", base=base_name, path=parent))
|
||||
|
||||
|
||||
# ---- UI ----
|
||||
|
||||
TEMPLATE = """
|
||||
<!doctype html>
|
||||
<title>Minimal File Browser</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; margin: 2rem; }
|
||||
.row { display: flex; gap: 1rem; align-items: center; }
|
||||
.file { margin-left: 1.5rem; }
|
||||
button { color: red; }
|
||||
</style>
|
||||
|
||||
<form method="get">
|
||||
Base folder:
|
||||
<select name="base" onchange="this.form.submit()">
|
||||
{% for b in bases %}
|
||||
<option value="{{b}}" {% if b==base_name %}selected{% endif %}>{{b}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
|
||||
<h3>Path: /{{ rel }}</h3>
|
||||
|
||||
<ul>
|
||||
{% if rel and '/' in rel %}
|
||||
<li><a href="/?base={{base_name}}&path={{ rel.rsplit('/',1)[0] }}">..</a></li>
|
||||
{% elif rel %}
|
||||
<li><a href="/?base={{base_name}}">..</a></li>
|
||||
{% endif %}
|
||||
|
||||
{% for i in items %}
|
||||
<li class="row">
|
||||
{% if i.is_dir %}
|
||||
<a href="/?base={{base_name}}&path={{ i.rel }}">📁 {{ i.name }}</a>
|
||||
{% else %}
|
||||
<span class="file">📄 {{ i.name }}</span>
|
||||
{% endif %}
|
||||
<form method="post" action="/delete" onsubmit="return confirm('Delete {{i.name}}?')">
|
||||
<input type="hidden" name="base" value="{{base_name}}">
|
||||
<input type="hidden" name="path" value="{{ i.rel }}">
|
||||
<button type="submit">Delete</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="192.168.101.13", port=8000)
|
||||
7
garbageCollector/config.py
Normal file
7
garbageCollector/config.py
Normal file
@ -0,0 +1,7 @@
|
||||
from pathlib import Path
|
||||
|
||||
BASE_DIRS = {
|
||||
"data": Path("/root/garbageCollector").resolve(),
|
||||
"uploads": Path("/srv/uploads").resolve(),
|
||||
}
|
||||
DEFAULT_BASE = "data"
|
||||
Loading…
x
Reference in New Issue
Block a user