aboutsummaryrefslogtreecommitdiff
path: root/backend/main.py
blob: 8af66ca5e6d1b7bc5b8f929d412e42f161c18cad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import json
import config
import cgi
import os
import sqlite3
import mimetypes

def playout(filename, content = "text/html"):
	return ["", [('Content-Type', content if content else "application/octet-stream"), ("X-Accel-Redirect", filename)], None]

def home():
	return ["", [('Content-Type','text/html'), ("Location", config.homepage)], "302 Home"]

def target_filename_internal(session, filename):
	target = session["path"] + "/"
	if filename:
		target += filename
	if config.user_subdirs:
		target = session["user"] + "/" + target
	return target

def target_filename(session, file):
	return config.fileroot + target_filename_internal(session, file)

def resolve_alias(alias):
	session = None
	db = sqlite3.connect(config.database, check_same_thread = False)
	cursor = db.cursor()
	cursor.execute("SELECT user, real, access, storage, display FROM aliases WHERE alias=:alias", {"alias": alias})
	data = cursor.fetchone()
	if data:
		session = {"user": data[0], "path": data[1], "access": data[2], "limit": data[3], "display": data[4]}
	else:
		print("Unknown alias " + alias)
	db.close()
	return session

def listing(session):
	listing = {"total": 0, "files": [], "access": session["access"], "display": session["display"]}

	# TODO make sorting configurable
	if 'r' in session["access"]:
		directory = target_filename(session, None)
		files = sorted(os.listdir(directory))

		for filename in files:
			if os.path.isfile(directory + filename):
				size = os.path.getsize(directory + filename)
				listing["files"].append({"name": filename, "size": size})
				listing["total"] += size

	return [json.dumps(listing), [('Content-Type','application/json')], "200 OK"]

def upload(session, post):
	if 'c' not in session["access"]:
		return ["", [('Content-Type','text/html')], "403 No"]
	if post["file"].filename:
		target = target_filename(session, os.path.basename(post["file"].filename))

		while os.path.isfile(target):
			target += "_dup"

		try:
			open(target, 'wb').write(post["file"].file.read())
			print("Uploaded " + target)
			return ["", [('Content-Type','text/html')], "200 OK"]
		except PermissionError as e:
			print("Failed to store " + target + ": " + e.msg)
			return ["", [('Content-Type','text/html')], "500 Error"]
	else:
		print("Upload failed")
		return ["", [('Content-Type','text/html')], "500 Error"]

def route(path, env, session, post):
	# Get mapped user/path/limits
	session = resolve_alias(path[0])

	if not session:
		return home()

	#print(json.dumps(session))

	# Redirect if no slash after alias
	if len(path) == 1:
		return ["", [('Content-Type','text/html'), ("Location", path[0] + "/")], "302 Redirect"]

	if len(path) > 1 and path[1] == "upload":
		return upload(session, post)

	if len(path) > 1 and path[1] == "listing":
		return listing(session)

	if len(path) > 1 and path[1] == "file":
		print("/data/" + target_filename_internal(session, path[2]))
		return playout("/data/" + target_filename_internal(session, path[2]), mimetypes.guess_type(path[2])[0])

	if len(path) > 1 and path[1] == "preview" and session["display"] == "gallery":
		return playout("/data/" + target_filename_internal(session, "preview/" + path[2]), mimetypes.guess_type(path[2])[0])

	return playout("/interface/listing.htm")

def handle_request(env, response):
	path = env.get('PATH_INFO', '').lstrip('/').split('/')
	post = None
	headers = []
	session = None

	# Read POST data
	try:
		if env.get('CONTENT_TYPE', '').startswith("multipart/form-data"):
			post = cgi.FieldStorage(environ=env, fp=env['wsgi.input'], keep_blank_values=True)
		else:
			content_length = int(env.get('CONTENT_LENGTH', '0'))
			post_raw = env["wsgi.input"].read(content_length).decode('utf-8')
			post = post_raw
	except ValueError as e:
		post = None

	# Route request
	data, addtl_headers, code = route(path, env, session, post)
	headers.extend(addtl_headers)
	response(code if code else "200 OK", headers)
	return [bytes(data, "utf-8")]