mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-26 13:49:21 +00:00
Merge pull request #250 from akuker/fix_uploads
Fix the file upload functionality
This commit is contained in:
commit
01443ec653
@ -1,5 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ractl_cmds import (
|
from ractl_cmds import (
|
||||||
@ -63,17 +62,23 @@ def delete_file(file_name):
|
|||||||
|
|
||||||
|
|
||||||
def unzip_file(file_name):
|
def unzip_file(file_name):
|
||||||
import zipfile
|
from subprocess import run
|
||||||
|
|
||||||
with zipfile.ZipFile(base_dir + file_name, "r") as zip_ref:
|
unzip_proc = run(
|
||||||
zip_ref.extractall(base_dir)
|
["unzip", "-d", base_dir, "-o", "-j", base_dir + file_name], capture_output=True
|
||||||
return True
|
)
|
||||||
|
if unzip_proc.returncode != 0:
|
||||||
|
logging.warning(f"Unzipping failed: {unzip_proc}")
|
||||||
|
return {"status": False, "msg": unzip_proc}
|
||||||
|
|
||||||
|
return {"status": True, "msg": f"{file_name} unzipped"}
|
||||||
|
|
||||||
|
|
||||||
def download_file_to_iso(scsi_id, url):
|
def download_file_to_iso(scsi_id, url):
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.error as error
|
import urllib.error as error
|
||||||
import time
|
import time
|
||||||
|
from subprocess import run
|
||||||
|
|
||||||
file_name = url.split("/")[-1]
|
file_name = url.split("/")[-1]
|
||||||
tmp_ts = int(time.time())
|
tmp_ts = int(time.time())
|
||||||
@ -91,7 +96,7 @@ def download_file_to_iso(scsi_id, url):
|
|||||||
return {"status": False, "msg": "Error loading the URL"}
|
return {"status": False, "msg": "Error loading the URL"}
|
||||||
|
|
||||||
# iso_filename = make_cd(tmp_full_path, None, None) # not working yet
|
# iso_filename = make_cd(tmp_full_path, None, None) # not working yet
|
||||||
iso_proc = subprocess.run(
|
iso_proc = run(
|
||||||
["genisoimage", "-hfs", "-o", iso_filename, tmp_full_path], capture_output=True
|
["genisoimage", "-hfs", "-o", iso_filename, tmp_full_path], capture_output=True
|
||||||
)
|
)
|
||||||
if iso_proc.returncode != 0:
|
if iso_proc.returncode != 0:
|
||||||
|
@ -39,3 +39,9 @@ def is_bridge_setup():
|
|||||||
if "rascsi_bridge" in output:
|
if "rascsi_bridge" in output:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def disk_space():
|
||||||
|
from shutil import disk_usage
|
||||||
|
total, used, free = disk_usage(__file__)
|
||||||
|
return {"total": total, "used": used, "free": free}
|
||||||
|
@ -11,3 +11,4 @@ waitress==1.4.4
|
|||||||
zope.event==4.5.0
|
zope.event==4.5.0
|
||||||
zope.interface==5.1.2
|
zope.interface==5.1.2
|
||||||
protobuf==3.17.3
|
protobuf==3.17.3
|
||||||
|
pydrop==0.0.6
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>RaSCSI-web is Starting</title>
|
<title>RaSCSI-Web is Starting</title>
|
||||||
<meta http-equiv="refresh" content="2">
|
<meta http-equiv="refresh" content="2">
|
||||||
</head>
|
</head>
|
||||||
</html>
|
</html>
|
||||||
<body>
|
<body>
|
||||||
<center>
|
<center>
|
||||||
<h1>RaSCSI Web is starting....</h1>
|
<h1>RaSCSI-Web is Starting....</h1>
|
||||||
<h2>This page will automatically refresh.</h2>
|
<h2>This page will automatically refresh.</h2>
|
||||||
<p>First boot and upgrades can take a second to resolve dependancies.</p>
|
<p>First boot and upgrades can take a second while resolving dependencies.</p>
|
||||||
<p>If you're seeing this page for over a minute please check the logs at <tt>sudo journalctl -f</tt></p>
|
<p>If you're seeing this page for over a minute please check the logs at <tt>sudo journalctl -f</tt></p>
|
||||||
</center>
|
</center>
|
||||||
</body>
|
</body>
|
||||||
|
@ -4,7 +4,7 @@ base_dir = getenv("BASE_DIR", "/home/pi/images/")
|
|||||||
home_dir = getcwd()
|
home_dir = getcwd()
|
||||||
|
|
||||||
DEFAULT_CONFIG = "default.json"
|
DEFAULT_CONFIG = "default.json"
|
||||||
MAX_FILE_SIZE = getenv("MAX_FILE_SIZE", 1024 * 1024 * 1024 * 2) # 2gb
|
MAX_FILE_SIZE = getenv("MAX_FILE_SIZE", 1024 * 1024 * 1024 * 4) # 4gb
|
||||||
|
|
||||||
HARDDRIVE_FILE_SUFFIX = ("hda", "hdn", "hdi", "nhd", "hdf", "hds")
|
HARDDRIVE_FILE_SUFFIX = ("hda", "hdn", "hdi", "nhd", "hdf", "hds")
|
||||||
CDROM_FILE_SUFFIX = ("iso", "cdr", "toast", "img")
|
CDROM_FILE_SUFFIX = ("iso", "cdr", "toast", "img")
|
||||||
|
@ -47,3 +47,61 @@ td.inactive {
|
|||||||
text-align:center;
|
text-align:center;
|
||||||
background-color:tan;
|
background-color:tan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropzone, .dropzone * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 120px;
|
||||||
|
margin: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-progress {
|
||||||
|
display: block;
|
||||||
|
height: 15px;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-progress .dz-upload {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 0;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-error-message {
|
||||||
|
color: red;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview.dz-error .dz-error-message {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview.dz-error .dz-error-mark {
|
||||||
|
display: block;
|
||||||
|
filter: drop-shadow(0px 0px 2px red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview.dz-success .dz-success-mark {
|
||||||
|
display: block;
|
||||||
|
filter: drop-shadow(0px 0px 2px green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-error-mark, .dropzone .dz-preview .dz-success-mark {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
left: 30px;
|
||||||
|
top: 30px;
|
||||||
|
width: 54px;
|
||||||
|
height: 58px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -27px;
|
||||||
|
}
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||||
|
|
||||||
|
<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js">
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span style="display: inline-block; width: 100%; color: white; background-color: green; text-align: center; vertical-align: center; font-family: Arial, Helvetica, sans-serif;">Service Running</span>
|
<span style="display: inline-block; width: 100%; color: white; background-color: green; text-align: center; vertical-align: center; font-family: Arial, Helvetica, sans-serif;">Service Running</span>
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
<input type="hidden" name="size" value="{{hd.size}}">
|
<input type="hidden" name="size" value="{{hd.size}}">
|
||||||
<input type="hidden" name="file_type" value="{{hd.file_type}}">
|
<input type="hidden" name="file_type" value="{{hd.file_type}}">
|
||||||
<label for="file_name">Save as:</label>
|
<label for="file_name">Save as:</label>
|
||||||
<input type="text" name="file_name" value="{{hd.name}}" />.{{hd.file_type}}
|
<input type="text" name="file_name" value="{{hd.secure_name}}" />.{{hd.file_type}}
|
||||||
<input type="submit" value="Create" />
|
<input type="submit" value="Create" />
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
@ -127,7 +127,7 @@
|
|||||||
<input type="hidden" name="size" value="{{rm.size}}">
|
<input type="hidden" name="size" value="{{rm.size}}">
|
||||||
<input type="hidden" name="file_type" value="{{rm.file_type}}">
|
<input type="hidden" name="file_type" value="{{rm.file_type}}">
|
||||||
<label for="file_name">Save as:</label>
|
<label for="file_name">Save as:</label>
|
||||||
<input type="text" name="file_name" value="{{rm.name}}" />.{{rm.file_type}}
|
<input type="text" name="file_name" value="{{rm.secure_name}}" />.{{rm.file_type}}
|
||||||
<input type="submit" value="Create" />
|
<input type="submit" value="Create" />
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
@ -135,5 +135,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<p><small>Available disk space on the Pi: {{free_disk}} MB</small></p>
|
||||||
|
<p><a href="javascript:history.back()">Cancel</a></p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -91,10 +91,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% for file in files %}
|
{% for file in files %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{file["name"].replace(base_dir, '')}}</td>
|
<td>{{file["name"]}}</td>
|
||||||
<td style="text-align:center">
|
<td style="text-align:center">
|
||||||
<form action="/files/download" method="post">
|
<form action="/files/download" method="post">
|
||||||
<input type="hidden" name="image" value="{{file["name"].replace(base_dir, '')}}">
|
<input type="hidden" name="image" value="{{file["name"]}}">
|
||||||
<input type="submit" value="{{file["size_mb"]}} MB ↓" />
|
<input type="submit" value="{{file["size_mb"]}} MB ↓" />
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
@ -107,28 +107,20 @@
|
|||||||
<option value="{{id}}">{{id}}</option>
|
<option value="{{id}}">{{id}}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
{% if not file["name"].lower().endswith(archive_file_suffix) %}
|
|
||||||
<input type="submit" value="Attach" />
|
<input type="submit" value="Attach" />
|
||||||
{% endif %}
|
|
||||||
</form>
|
</form>
|
||||||
<form action="/files/delete" method="post" onsubmit="return confirm('Delete file?')">
|
<form action="/files/delete" method="post" onsubmit="return confirm('Delete file?')">
|
||||||
<input type="hidden" name="image" value="{{file["name"].replace(base_dir, '')}}">
|
<input type="hidden" name="image" value="{{file["name"]}}">
|
||||||
<input type="submit" value="Delete" />
|
<input type="submit" value="Delete" />
|
||||||
</form>
|
</form>
|
||||||
{% if file["name"].lower().endswith(archive_file_suffix) %}
|
|
||||||
<form action="/files/unzip" method="post">
|
|
||||||
<input type="hidden" name="image" value="{{file["name"].replace(base_dir, '')}}">
|
|
||||||
<input type="submit" value="Unzip" />
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p><small>Supported file types: {{valid_file_suffix|string()}}</small></p>
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<h2>Attach Ethernet Adapter</h2>
|
<h2>Attach Ethernet Adapter</h2>
|
||||||
<p>Emulates a SCSI DaynaPORT Ethernet Adapter. <a href="https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-Link#-macintosh-setup-instructions">Host drivers required.</a></p>
|
<p>Emulates a SCSI DaynaPORT Ethernet Adapter. <a href="https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-Link#-macintosh-setup-instructions">Host drivers required.</a></p>
|
||||||
<p>If you have a DHCP setup, ignore the Static IP fields.</p>
|
<p>If you have a DHCP setup, ignore the Static IP fields.</p>
|
||||||
@ -167,33 +159,37 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<h2>Upload File</h2>
|
<h2>Upload File</h2>
|
||||||
<p>Uploads file to <tt>{{base_dir}}</tt>. Max file size is set to {{max_file_size / 1024 /1024 }}MB</p>
|
<p>Uploads file to <tt>{{base_dir}}</tt>. The largest file size accepted is {{max_file_size}} MB. Zip files will be unzipped.</p>
|
||||||
<table style="border: none">
|
<table style="border: none">
|
||||||
<tr style="border: none">
|
<tr style="border: none">
|
||||||
<td style="border: none; vertical-align:top;">
|
<td style="border: none; vertical-align:top;">
|
||||||
<form id="uploadForm" action="/files/upload/" onchange="fileSelect(event)" method="post" enctype="multipart/form-data">
|
<form method="POST" action="/files/upload" class="dropzone dz-clickable" id="dropper" enctype="multipart/form-data">
|
||||||
<label for="file">File:</label>
|
|
||||||
<input type="file" name="file"/>
|
|
||||||
<input type="submit" value="Upload" />
|
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<script>
|
<script type="application/javascript">
|
||||||
function fileSelect(e) {
|
Dropzone.options.dropper = {
|
||||||
document.getElementById("uploadForm").setAttribute('action', "/files/upload/" + e.target.files[0].name)
|
paramName: 'file',
|
||||||
console.log(e.target.files[0].name);
|
acceptedFiles: '{{valid_file_suffix}}',
|
||||||
|
chunking: true,
|
||||||
|
forceChunking: true,
|
||||||
|
url: '/files/upload',
|
||||||
|
maxFilesize: {{max_file_size}}, // MB
|
||||||
|
chunkSize: 1000000 // bytes
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<p><small>Recognized file types: {{valid_file_suffix}}</small></p>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<h2>Download File from Web</h2>
|
<h2>Download File from Web</h2>
|
||||||
<p>Given a URL, download that file to the <tt>{{base_dir}}</tt></p>
|
<p>Given a URL, download that file to the <tt>{{base_dir}}</tt></p>
|
||||||
<table style="border: none">
|
<table style="border: none">
|
||||||
<tr style="border: none">
|
<tr style="border: none">
|
||||||
<td style="border: none; vertical-align:top;">
|
<td style="border: none; vertical-align:top;">
|
||||||
<form action="/files/download_image" method="post">
|
<form action="/files/download_image" method="post">
|
||||||
<label for="url">URL:</label>
|
<label for="url">URL:</label>
|
||||||
<input type="text" placeholder="URL" name="url" />
|
<input type="text" placeholder="URL" name="url" />
|
||||||
@ -206,7 +202,7 @@
|
|||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<h2>Download File from web and create HFS CD (Macintosh)</h2>
|
<h2>Download File from web and create HFS CD (Macintosh)</h2>
|
||||||
<p>Given a URL this will download a file, create a HFS iso, and mount it on the device id given. Requires a <a href="https://github.com/akuker/RASCSI/wiki/Drive-Setup#Mounting_CD_ISO_or_MO_images">compatible CD-ROM driver</a>.</p>
|
<p>Given a URL this will download a file, create a HFS iso, and mount it on the SCSI ID given. Requires a <a href="https://github.com/akuker/RASCSI/wiki/Drive-Setup#Mounting_CD_ISO_or_MO_images">compatible CD-ROM driver</a>.</p>
|
||||||
<table style="border: none">
|
<table style="border: none">
|
||||||
<tr style="border: none">
|
<tr style="border: none">
|
||||||
<td style="border: none; vertical-align:top;">
|
<td style="border: none; vertical-align:top;">
|
||||||
@ -251,6 +247,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<p><small>Available disk space on the Pi: {{free_disk}} MB</small></p>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
109
src/web/web.py
109
src/web/web.py
@ -1,4 +1,15 @@
|
|||||||
from flask import Flask, render_template, request, flash, url_for, redirect, send_file, send_from_directory
|
import logging
|
||||||
|
from flask import (
|
||||||
|
Flask,
|
||||||
|
render_template,
|
||||||
|
request,
|
||||||
|
flash,
|
||||||
|
url_for,
|
||||||
|
redirect,
|
||||||
|
send_file,
|
||||||
|
send_from_directory,
|
||||||
|
make_response,
|
||||||
|
)
|
||||||
|
|
||||||
from file_cmds import (
|
from file_cmds import (
|
||||||
list_files,
|
list_files,
|
||||||
@ -19,6 +30,7 @@ from pi_cmds import (
|
|||||||
running_env,
|
running_env,
|
||||||
rascsi_service,
|
rascsi_service,
|
||||||
is_bridge_setup,
|
is_bridge_setup,
|
||||||
|
disk_space,
|
||||||
)
|
)
|
||||||
from ractl_cmds import (
|
from ractl_cmds import (
|
||||||
attach_image,
|
attach_image,
|
||||||
@ -41,6 +53,7 @@ app = Flask(__name__)
|
|||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
server_info = get_server_info()
|
server_info = get_server_info()
|
||||||
|
disk = disk_space()
|
||||||
devices = list_devices()
|
devices = list_devices()
|
||||||
files=list_files()
|
files=list_files()
|
||||||
config_files=list_config_files()
|
config_files=list_config_files()
|
||||||
@ -51,6 +64,7 @@ def index():
|
|||||||
reserved_scsi_ids = server_info["reserved_ids"]
|
reserved_scsi_ids = server_info["reserved_ids"]
|
||||||
formatted_devices = sort_and_format_devices(devices["device_list"])
|
formatted_devices = sort_and_format_devices(devices["device_list"])
|
||||||
scsi_ids = get_valid_scsi_ids(devices["device_list"], reserved_scsi_ids)
|
scsi_ids = get_valid_scsi_ids(devices["device_list"], reserved_scsi_ids)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"index.html",
|
"index.html",
|
||||||
bridge_configured=is_bridge_setup(),
|
bridge_configured=is_bridge_setup(),
|
||||||
@ -60,11 +74,12 @@ def index():
|
|||||||
base_dir=base_dir,
|
base_dir=base_dir,
|
||||||
scsi_ids=scsi_ids,
|
scsi_ids=scsi_ids,
|
||||||
reserved_scsi_ids=reserved_scsi_ids,
|
reserved_scsi_ids=reserved_scsi_ids,
|
||||||
max_file_size=MAX_FILE_SIZE,
|
max_file_size=int(MAX_FILE_SIZE / 1024 / 1024),
|
||||||
running_env=running_env(),
|
running_env=running_env(),
|
||||||
server_info=server_info,
|
server_info=server_info,
|
||||||
netinfo=get_network_info(),
|
netinfo=get_network_info(),
|
||||||
valid_file_suffix=VALID_FILE_SUFFIX,
|
free_disk=int(disk["free"] / 1024 / 1024),
|
||||||
|
valid_file_suffix="."+", .".join(VALID_FILE_SUFFIX),
|
||||||
removable_device_types=REMOVABLE_DEVICE_TYPES,
|
removable_device_types=REMOVABLE_DEVICE_TYPES,
|
||||||
harddrive_file_suffix=HARDDRIVE_FILE_SUFFIX,
|
harddrive_file_suffix=HARDDRIVE_FILE_SUFFIX,
|
||||||
cdrom_file_suffix=CDROM_FILE_SUFFIX,
|
cdrom_file_suffix=CDROM_FILE_SUFFIX,
|
||||||
@ -79,6 +94,7 @@ def drive_list():
|
|||||||
Sets up the data structures and kicks off the rendering of the drive list page
|
Sets up the data structures and kicks off the rendering of the drive list page
|
||||||
"""
|
"""
|
||||||
server_info = get_server_info()
|
server_info = get_server_info()
|
||||||
|
disk = disk_space()
|
||||||
|
|
||||||
# Reads the canonical drive properties into a dict
|
# Reads the canonical drive properties into a dict
|
||||||
# The file resides in the current dir of the web ui process
|
# The file resides in the current dir of the web ui process
|
||||||
@ -98,14 +114,17 @@ def drive_list():
|
|||||||
cd_conf = []
|
cd_conf = []
|
||||||
rm_conf = []
|
rm_conf = []
|
||||||
|
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
for d in conf:
|
for d in conf:
|
||||||
if d["device_type"] == "SCHD":
|
if d["device_type"] == "SCHD":
|
||||||
|
d["secure_name"] = secure_filename(d["name"])
|
||||||
d["size_mb"] = "{:,.2f}".format(d["size"] / 1024 / 1024)
|
d["size_mb"] = "{:,.2f}".format(d["size"] / 1024 / 1024)
|
||||||
hd_conf.append(d)
|
hd_conf.append(d)
|
||||||
elif d["device_type"] == "SCCD":
|
elif d["device_type"] == "SCCD":
|
||||||
d["size_mb"] = "N/A"
|
d["size_mb"] = "N/A"
|
||||||
cd_conf.append(d)
|
cd_conf.append(d)
|
||||||
elif d["device_type"] == "SCRM":
|
elif d["device_type"] == "SCRM":
|
||||||
|
d["secure_name"] = secure_filename(d["name"])
|
||||||
d["size_mb"] = "{:,.2f}".format(d["size"] / 1024 / 1024)
|
d["size_mb"] = "{:,.2f}".format(d["size"] / 1024 / 1024)
|
||||||
rm_conf.append(d)
|
rm_conf.append(d)
|
||||||
|
|
||||||
@ -124,6 +143,7 @@ def drive_list():
|
|||||||
rm_conf=rm_conf,
|
rm_conf=rm_conf,
|
||||||
running_env=running_env(),
|
running_env=running_env(),
|
||||||
server_info=server_info,
|
server_info=server_info,
|
||||||
|
free_disk=int(disk["free"] / 1024 / 1024),
|
||||||
cdrom_file_suffix=CDROM_FILE_SUFFIX,
|
cdrom_file_suffix=CDROM_FILE_SUFFIX,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -142,7 +162,7 @@ def drive_create():
|
|||||||
size = request.form.get("size")
|
size = request.form.get("size")
|
||||||
file_type = request.form.get("file_type")
|
file_type = request.form.get("file_type")
|
||||||
file_name = request.form.get("file_name")
|
file_name = request.form.get("file_name")
|
||||||
|
|
||||||
# Creating the image file
|
# Creating the image file
|
||||||
process = create_new_image(file_name, file_type, size)
|
process = create_new_image(file_name, file_type, size)
|
||||||
if process["status"] == True:
|
if process["status"] == True:
|
||||||
@ -464,29 +484,52 @@ def download_img():
|
|||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/files/upload/<filename>", methods=["POST"])
|
@app.route("/files/upload", methods=["POST"])
|
||||||
def upload_file(filename):
|
def upload_file():
|
||||||
if not filename:
|
from werkzeug.utils import secure_filename
|
||||||
flash("No file provided.", "error")
|
|
||||||
return redirect(url_for("index"))
|
|
||||||
|
|
||||||
from os import path
|
from os import path
|
||||||
file_path = path.join(app.config["UPLOAD_FOLDER"], filename)
|
import pydrop
|
||||||
if path.isfile(file_path):
|
|
||||||
flash(f"{filename} already exists.", "error")
|
|
||||||
return redirect(url_for("index"))
|
|
||||||
|
|
||||||
from io import DEFAULT_BUFFER_SIZE
|
log = logging.getLogger("pydrop")
|
||||||
binary_new_file = "bx"
|
file = request.files["file"]
|
||||||
with open(file_path, binary_new_file, buffering=DEFAULT_BUFFER_SIZE) as f:
|
filename = secure_filename(file.filename)
|
||||||
chunk_size = DEFAULT_BUFFER_SIZE
|
|
||||||
while True:
|
save_path = path.join(app.config["UPLOAD_FOLDER"], filename)
|
||||||
chunk = request.stream.read(chunk_size)
|
current_chunk = int(request.form['dzchunkindex'])
|
||||||
if len(chunk) == 0:
|
|
||||||
break
|
# Makes sure not to overwrite an existing file,
|
||||||
f.write(chunk)
|
# but continues writing to a file transfer in progress
|
||||||
# TODO: display an informative success message
|
if path.exists(save_path) and current_chunk == 0:
|
||||||
return redirect(url_for("index", filename=filename))
|
return make_response((f"The file {file.filename} already exists!", 400))
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(save_path, "ab") as f:
|
||||||
|
f.seek(int(request.form["dzchunkbyteoffset"]))
|
||||||
|
f.write(file.stream.read())
|
||||||
|
except OSError:
|
||||||
|
log.exception("Could not write to file")
|
||||||
|
return make_response(("Unable to write the file to disk!", 500))
|
||||||
|
|
||||||
|
total_chunks = int(request.form["dztotalchunkcount"])
|
||||||
|
|
||||||
|
if current_chunk + 1 == total_chunks:
|
||||||
|
# Validate the resulting file size after writing the last chunk
|
||||||
|
if path.getsize(save_path) != int(request.form["dztotalfilesize"]):
|
||||||
|
log.error(f"Finished transferring {file.filename}, "
|
||||||
|
f"but it has a size mismatch with the original file."
|
||||||
|
f"Got {path.getsize(save_path)} but we "
|
||||||
|
f"expected {request.form['dztotalfilesize']}.")
|
||||||
|
return make_response(("Transferred file corrupted!", 500))
|
||||||
|
else:
|
||||||
|
log.info(f"File {file.filename} has been uploaded successfully")
|
||||||
|
if filename.lower().endswith(".zip"):
|
||||||
|
unzip_file(filename)
|
||||||
|
else:
|
||||||
|
log.debug(f"Chunk {current_chunk + 1} of {total_chunks} "
|
||||||
|
f"for file {file.filename} completed.")
|
||||||
|
|
||||||
|
|
||||||
|
return make_response(("File upload successful!", 200))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/files/create", methods=["POST"])
|
@app.route("/files/create", methods=["POST"])
|
||||||
@ -495,6 +538,9 @@ def create_file():
|
|||||||
size = (int(request.form.get("size")) * 1024 * 1024)
|
size = (int(request.form.get("size")) * 1024 * 1024)
|
||||||
file_type = request.form.get("type")
|
file_type = request.form.get("type")
|
||||||
|
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
|
file_name = secure_filename(file_name)
|
||||||
|
|
||||||
process = create_new_image(file_name, file_type, size)
|
process = create_new_image(file_name, file_type, size)
|
||||||
if process["status"] == True:
|
if process["status"] == True:
|
||||||
flash(f"Drive image created as {file_name}.{file_type}")
|
flash(f"Drive image created as {file_name}.{file_type}")
|
||||||
@ -543,19 +589,6 @@ def delete():
|
|||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/files/unzip", methods=["POST"])
|
|
||||||
def unzip():
|
|
||||||
image = request.form.get("image")
|
|
||||||
|
|
||||||
if unzip_file(image):
|
|
||||||
flash("Unzipped file " + image)
|
|
||||||
return redirect(url_for("index"))
|
|
||||||
else:
|
|
||||||
flash("Failed to unzip " + image, "error")
|
|
||||||
return redirect(url_for("index"))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.secret_key = "rascsi_is_awesome_insecure_secret_key"
|
app.secret_key = "rascsi_is_awesome_insecure_secret_key"
|
||||||
app.config["SESSION_TYPE"] = "filesystem"
|
app.config["SESSION_TYPE"] = "filesystem"
|
||||||
|
Loading…
Reference in New Issue
Block a user