281 lines
7.3 KiB
Python
281 lines
7.3 KiB
Python
import os
|
|
import shutil
|
|
import sqlite3
|
|
import time
|
|
from datetime import datetime
|
|
|
|
from flask import current_app as app
|
|
|
|
from .misc import file_date_human, file_size_human, file_time_human, random_token
|
|
|
|
|
|
def get_db():
|
|
db = sqlite3.connect(app.config["DB"], timeout=5)
|
|
c = db.cursor()
|
|
return db, c
|
|
|
|
|
|
def db_store_file(token, name, expires, max_dl, password, ips=None, hidden=None):
|
|
db, c = get_db()
|
|
c.execute(
|
|
"""
|
|
insert into files(token,name,added,expires,downloads,max_downloads,passhash,allowed_ip,hidden)
|
|
values (?,?,?,?,?,?,?,?,?)
|
|
""",
|
|
(token, name, int(time.time()), expires, 0, max_dl, password, ips, hidden),
|
|
)
|
|
if c.rowcount > 0:
|
|
db.commit()
|
|
return
|
|
|
|
|
|
def db_get_file(token, name):
|
|
db, c = get_db()
|
|
return db.execute(
|
|
"""
|
|
SELECT added,expires,downloads,max_downloads,passhash,hidden,allowed_ip
|
|
FROM files WHERE token = ? AND name = ?
|
|
""",
|
|
(token, name),
|
|
).fetchone()
|
|
|
|
|
|
def db_get_name(token):
|
|
db, c = get_db()
|
|
return db.execute(
|
|
"""
|
|
SELECT name
|
|
FROM files WHERE token = ?
|
|
""",
|
|
(token,),
|
|
).fetchone()
|
|
|
|
|
|
|
|
def db_get_files():
|
|
db, c = get_db()
|
|
return db.execute(
|
|
"""
|
|
SELECT token,name,added,expires,downloads,max_downloads,passhash,allowed_ip
|
|
FROM files
|
|
WHERE expires > ?
|
|
AND (downloads < max_downloads or max_downloads = -1)
|
|
AND (hidden IS NULL OR hidden = 0)
|
|
ORDER BY added
|
|
""",
|
|
(time.time(),),
|
|
)
|
|
|
|
|
|
def db_delete_file(token, name):
|
|
db, c = get_db()
|
|
c.execute(
|
|
"""
|
|
DELETE FROM files WHERE token = ? and name = ?
|
|
""",
|
|
(token, name),
|
|
)
|
|
if c.rowcount > 0:
|
|
db.commit()
|
|
|
|
|
|
def db_add_download(token, name):
|
|
db, c = get_db()
|
|
c.execute(
|
|
"""
|
|
UPDATE files SET downloads = downloads + 1 WHERE token = ? AND name = ?
|
|
""",
|
|
(token, name),
|
|
)
|
|
if c.rowcount > 0:
|
|
db.commit()
|
|
return
|
|
|
|
|
|
def db_maintenance():
|
|
messages = []
|
|
# === Delete DB entries where expiry or max DL is used up ===
|
|
db, c = get_db()
|
|
rows = db.execute(
|
|
"""
|
|
select
|
|
token, name
|
|
from files
|
|
where expires < ? or (downloads >= max_downloads and max_downloads != -1)
|
|
""",
|
|
(int(time.time()),),
|
|
)
|
|
deleted_tokens = []
|
|
for row in rows:
|
|
deleted_tokens.append((row[0],))
|
|
messages.append(f"Deleting DB {row[0]}/{row[1]}")
|
|
if len(deleted_tokens) > 0:
|
|
db, c = get_db()
|
|
c.executemany("DELETE FROM files WHERE token = ?", deleted_tokens)
|
|
if c.rowcount > 0:
|
|
db.commit()
|
|
# Delete files, if DB entry is gone
|
|
subdirs = next(os.walk(app.config["DATAFOLDER"]))[1]
|
|
db, c = get_db()
|
|
for d in subdirs:
|
|
keep = db.execute(
|
|
"SELECT 1 FROM files WHERE token = ?",
|
|
(d,),
|
|
).fetchone()
|
|
if not keep:
|
|
try:
|
|
for fname in os.listdir(os.path.join(app.config["DATAFOLDER"], d)):
|
|
os.remove(os.path.join(app.config["DATAFOLDER"], d, fname))
|
|
messages.append(f"Deleting file {d}/{fname}")
|
|
except Exception:
|
|
pass
|
|
shutil.rmtree(os.path.join(app.config["DATAFOLDER"], d), ignore_errors=True)
|
|
messages.append(f"Deleting folder {d}")
|
|
|
|
# Delete DB entries, if files have been deleted (probably manually)
|
|
db, c = get_db()
|
|
rows = db.execute(
|
|
"""
|
|
select
|
|
token, name
|
|
from files
|
|
"""
|
|
)
|
|
deleted_tokens = []
|
|
for row in rows:
|
|
full_path = file_full_path(row[0], row[1])
|
|
if not os.path.exists(full_path):
|
|
deleted_tokens.append((row[0],))
|
|
messages.append(f"Deleting DB {row[0]}/{row[1]} - files missing")
|
|
if len(deleted_tokens) > 0:
|
|
db, c = get_db()
|
|
c.executemany("DELETE FROM files WHERE token = ?", deleted_tokens)
|
|
if c.rowcount > 0:
|
|
db.commit()
|
|
|
|
# === Delete upload token entries where expiry is used up ===
|
|
db, c = get_db()
|
|
rows = db.execute(
|
|
"""
|
|
select
|
|
token
|
|
from upload_tokens
|
|
where expires < ?
|
|
""",
|
|
(int(time.time()),),
|
|
)
|
|
deleted_tokens = []
|
|
for row in rows:
|
|
deleted_tokens.append((row[0],))
|
|
messages.append(f"Deleting upload_token {row[0]}")
|
|
if len(deleted_tokens) > 0:
|
|
db, c = get_db()
|
|
c.executemany("DELETE FROM upload_tokens WHERE token = ?", deleted_tokens)
|
|
if c.rowcount > 0:
|
|
db.commit()
|
|
|
|
messages.append("Maintenance done.")
|
|
return "\n".join(messages)
|
|
|
|
|
|
def file_age(path):
|
|
now = datetime.now()
|
|
then = datetime.fromtimestamp(os.stat(path).st_mtime)
|
|
diff = now - then
|
|
return (
|
|
diff,
|
|
"%03d d %s" % (diff.days, datetime.utcfromtimestamp(diff.seconds).strftime("%H:%M:%S")),
|
|
)
|
|
|
|
|
|
def file_details(token, name):
|
|
full_path = file_full_path(token, name)
|
|
try:
|
|
s = os.stat(full_path)
|
|
db_stat = db_get_file(token, name)
|
|
if db_stat:
|
|
added, expires, downloads, max_dl, password, hidden, allowed_ip = db_stat
|
|
else:
|
|
return {}
|
|
return {
|
|
"size": s.st_size,
|
|
"hsize": file_size_human(s.st_size, HTML=False),
|
|
"added": file_time_human(added),
|
|
"name": name,
|
|
"url": file_full_url(token, name),
|
|
"expires": file_time_human(expires),
|
|
"downloaded": downloads,
|
|
"max-dl": max_dl,
|
|
"protected": password is not None,
|
|
"hidden": hidden,
|
|
"allowed_ip": allowed_ip,
|
|
}
|
|
except FileNotFoundError:
|
|
return {}
|
|
|
|
|
|
def file_full_path(token, name):
|
|
return os.path.join(app.config["DATAFOLDER"], token, name)
|
|
|
|
|
|
def file_full_url(token, name):
|
|
return f"{app.config['PUBLIC_URL']}/d/{token}/{name}"
|
|
|
|
|
|
def file_list():
|
|
details = []
|
|
details.append(" Added/Expiry DL/MaxDL ID URL")
|
|
details.append("=" * 75)
|
|
for file in db_get_files():
|
|
url = file_full_url(file[0], file[1])
|
|
added = file_date_human(file[2])
|
|
expiry = file_date_human(file[3])
|
|
pw = " (PW)" if file[6] else ""
|
|
ips = f" [{file[7]}]" if file[7] else ""
|
|
|
|
details.append(f"{added}/{expiry} {file[4]:4d}/{file[5]:4d} {file[0]} {url}{pw}{ips}")
|
|
|
|
return details
|
|
|
|
|
|
def file_list_simple():
|
|
return [f"{r[0]}/{r[1]}" for r in db_get_files()]
|
|
|
|
|
|
def new_upload_token(expires):
|
|
db, c = get_db()
|
|
token = random_token(32)
|
|
c.execute(
|
|
"""
|
|
insert into upload_tokens(token,added,expires)
|
|
values (?,?,?)
|
|
""",
|
|
(token, int(time.time()), expires),
|
|
)
|
|
if c.rowcount > 0:
|
|
db.commit()
|
|
return token
|
|
|
|
|
|
def validate_upload_token(token):
|
|
db, c = get_db()
|
|
return db.execute(
|
|
"""
|
|
SELECT 1
|
|
FROM upload_tokens WHERE token = ? AND expires > ?
|
|
""",
|
|
(token, int(time.time())),
|
|
).fetchone()
|
|
|
|
|
|
def invalidate_upload_token(token):
|
|
db, c = get_db()
|
|
c.execute(
|
|
"""
|
|
DELETE FROM upload_tokens WHERE token = ?
|
|
""",
|
|
(token,),
|
|
)
|
|
if c.rowcount > 0:
|
|
db.commit()
|