|
from flask import Flask |
|
|
|
import os |
|
import json |
|
from functools import cached_property |
|
|
|
|
|
def log(level, *args, sep=" ", end="\n"): |
|
print(f"[{level.upper()}] \t| {sep.join(args) + end}") |
|
|
|
|
|
def info(*args, sep=" ", end="\n"): |
|
return log("info", *args, sep, end) |
|
|
|
|
|
def warn(*args, sep=" ", end="\n"): |
|
return log("warn", *args, sep, end) |
|
|
|
|
|
def error(*args, sep=" ", end="\n"): |
|
return log("error", *args, sep, end) |
|
|
|
|
|
def namefrompath(path): |
|
return os.path.split(path.rstrip("/"))[-1] |
|
|
|
|
|
def getindir(path, dir): |
|
return os.path.join(path, dir) |
|
|
|
|
|
class File: |
|
def __init__( |
|
self, path=None, name=None, access=[], hidden=False, files=[]): |
|
self.path = path |
|
self.name = name |
|
self.access = access |
|
self.is_hidden = hidden |
|
self.files = files |
|
|
|
if self.is_virtual: |
|
if not self.name: |
|
error("`Name` parameter is required " |
|
"when the object is virtual.") |
|
exit(1) |
|
else: |
|
if self.files: |
|
warn("`files` parameter is ignored " |
|
"when the object is not virtual.") |
|
self.files = [] |
|
|
|
if self.path: |
|
if not isinstance(self.path, str): |
|
error("`Path` parameter should be a string.") |
|
exit(1) |
|
if not os.path.exists(self.path): |
|
warn(f"{self.path} doesn't exist!") |
|
|
|
if self.name: |
|
if not isinstance(self.name, str): |
|
error("`Name` parameter should be a string.") |
|
exit(1) |
|
else: |
|
self.name = namefrompath(self.path) |
|
|
|
@classmethod |
|
def create_from_json(cls, data): |
|
return cls( |
|
data.get('path'), |
|
data.get('name'), |
|
data.get('access', []), |
|
data.get('hidden', False), |
|
[cls.create_from_json(file) for file in data.get('files', [])] |
|
) |
|
|
|
@cached_property |
|
def is_virtual(self): |
|
return not bool(self.path) |
|
|
|
@property |
|
def is_anyone(self): |
|
return not bool(self.access) |
|
|
|
@property |
|
def is_file(self): |
|
return not self.is_virtual and os.path.isfile(self.path) |
|
|
|
@property |
|
def is_dir(self): |
|
return not self.is_file |
|
|
|
@property |
|
def exists(self): |
|
if self.is_virtual: |
|
return True |
|
else: |
|
return os.path.exists(self.path) |
|
|
|
@property |
|
def filemap(self): |
|
if self.is_file: |
|
raise TypeError("This object is a file.") |
|
|
|
if not self.is_virtual: |
|
self.update_files() |
|
|
|
return {x.name: x for x in self.files} |
|
|
|
def update_files(self): |
|
print(self.name, "update_files") |
|
if self.is_virtual or self.is_file: |
|
raise TypeError("This method only works with real folder.") |
|
|
|
path = self.path |
|
filemap = {namefrompath(x.path): x for x in self.files} |
|
newlist = [] |
|
|
|
for filename in os.listdir(path): |
|
if filename in filemap: |
|
newlist.append(filemap[filename]) |
|
else: |
|
filepath = os.path.join(path, filename) |
|
newlist.append(File(filepath, hidden=filename.startswith("."))) |
|
|
|
self.files = newlist |
|
return self.files |
|
|
|
|
|
def load_data(file="data.json"): |
|
with open("data.json") as f: |
|
data = json.load(f) |
|
files = [File.create_from_json(x) for x in data['files']] |
|
|
|
return File(name="/", files=files), None |
|
|
|
|
|
rootdir, users = load_data() |
|
|
|
app = Flask("__name__") |
|
|
|
|
|
@app.get("/favicon.ico") |
|
def meow(): |
|
return "", 404 |
|
|
|
|
|
@app.get("/") |
|
@app.get("/<path:itempath>") |
|
def get_file(itempath=""): |
|
obj = rootdir |
|
for name in itempath.rstrip("/").split("/"): |
|
if not name: |
|
continue |
|
|
|
print("searching", name) |
|
|
|
obj = obj.filemap.get(name) |
|
if obj is None: |
|
return "Not found", 404 |
|
elif not obj.exists: |
|
return "Doesn't exist", 404 |
|
|
|
if obj.is_dir: |
|
if not obj.is_virtual: |
|
obj.update_files() |
|
|
|
files_sort = sorted(sorted(obj.files, key=lambda x: x.name, reverse=False), key=lambda x: x.is_file) |
|
|
|
parentdirentry = "<tr><td></td><td><a href=\"..\">..</a></td></tr>" |
|
tableentry = "".join([f"<tr><td>{'File' if x.is_file else 'Dir'}</td><td><a href=\"/{getindir(itempath, x.name)}\">{x.name}</a></td></tr>" for x in files_sort if not x.is_hidden]) |
|
tablehtml = f"<table><thead><tr><th>Type</th><th>Name</th></tr></thead><tbody>{parentdirentry if obj is not rootdir else ''}{tableentry}</tbody></table>" |
|
html = f"<head></head><body><h1>Current Directory: /{itempath}</h1><br><br>{tablehtml}</body>" |
|
return html |
|
|
|
else: |
|
return "This is a file but I'm too lazy to actually send it towards you" |
|
|
|
|
|
app.run("0.0.0.0", 4199) |