mirror of
https://github.com/onionshare/onionshare.git
synced 2024-12-29 09:16:24 -05:00
Merge branch 'share-code' of https://github.com/hiromipaw/onionshare into hiromipaw-share-code
This commit is contained in:
commit
328b1500ab
218
onionshare/web/base_mode.py
Normal file
218
onionshare/web/base_mode.py
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import mimetypes
|
||||||
|
from flask import Response, request, render_template, make_response, send_from_directory
|
||||||
|
|
||||||
|
from .. import strings
|
||||||
|
|
||||||
|
class BaseModeWeb(object):
|
||||||
|
"""
|
||||||
|
All of the web logic shared between share and website mode
|
||||||
|
"""
|
||||||
|
def __init__(self, common, web):
|
||||||
|
super(BaseModeWeb, self).__init__()
|
||||||
|
self.common = common
|
||||||
|
self.web = web
|
||||||
|
|
||||||
|
# Information about the file to be shared
|
||||||
|
self.file_info = []
|
||||||
|
self.is_zipped = False
|
||||||
|
self.download_filename = None
|
||||||
|
self.download_filesize = None
|
||||||
|
self.gzip_filename = None
|
||||||
|
self.gzip_filesize = None
|
||||||
|
self.zip_writer = None
|
||||||
|
|
||||||
|
# Dictionary mapping file paths to filenames on disk
|
||||||
|
self.files = {}
|
||||||
|
# This is only the root files and dirs, as opposed to all of them
|
||||||
|
self.root_files = {}
|
||||||
|
self.cleanup_filenames = []
|
||||||
|
self.file_info = {'files': [], 'dirs': []}
|
||||||
|
|
||||||
|
self.visit_count = 0
|
||||||
|
self.download_count = 0
|
||||||
|
|
||||||
|
# If "Stop After First Download" is checked (stay_open == False), only allow
|
||||||
|
# one download at a time.
|
||||||
|
self.download_in_progress = False
|
||||||
|
|
||||||
|
self.define_routes()
|
||||||
|
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
"""
|
||||||
|
Add custom initialization here.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def directory_listing(self, filenames, path='', filesystem_path=None):
|
||||||
|
# If filesystem_path is None, this is the root directory listing
|
||||||
|
files = []
|
||||||
|
dirs = []
|
||||||
|
r = ''
|
||||||
|
|
||||||
|
files, dirs = self.build_directory_listing(filenames, filesystem_path)
|
||||||
|
|
||||||
|
if self.web.mode == 'website':
|
||||||
|
r = make_response(render_template('listing.html',
|
||||||
|
path=path,
|
||||||
|
files=files,
|
||||||
|
dirs=dirs,
|
||||||
|
static_url_path=self.web.static_url_path))
|
||||||
|
|
||||||
|
elif self.web.mode == 'share':
|
||||||
|
r = make_response(render_template(
|
||||||
|
'send.html',
|
||||||
|
file_info=self.file_info,
|
||||||
|
files=files,
|
||||||
|
dirs=dirs,
|
||||||
|
filename=os.path.basename(self.download_filename),
|
||||||
|
filesize=self.filesize,
|
||||||
|
filesize_human=self.common.human_readable_filesize(self.download_filesize),
|
||||||
|
is_zipped=self.is_zipped,
|
||||||
|
static_url_path=self.web.static_url_path))
|
||||||
|
|
||||||
|
return self.web.add_security_headers(r)
|
||||||
|
|
||||||
|
|
||||||
|
def build_directory_listing(self, filenames, filesystem_path):
|
||||||
|
files = []
|
||||||
|
dirs = []
|
||||||
|
|
||||||
|
for filename in filenames:
|
||||||
|
if filesystem_path:
|
||||||
|
this_filesystem_path = os.path.join(filesystem_path, filename)
|
||||||
|
else:
|
||||||
|
this_filesystem_path = self.files[filename]
|
||||||
|
|
||||||
|
is_dir = os.path.isdir(this_filesystem_path)
|
||||||
|
|
||||||
|
if is_dir:
|
||||||
|
dirs.append({
|
||||||
|
'basename': filename
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
size = os.path.getsize(this_filesystem_path)
|
||||||
|
size_human = self.common.human_readable_filesize(size)
|
||||||
|
files.append({
|
||||||
|
'basename': filename,
|
||||||
|
'size_human': size_human
|
||||||
|
})
|
||||||
|
return files, dirs
|
||||||
|
|
||||||
|
|
||||||
|
def set_file_info(self, filenames, processed_size_callback=None):
|
||||||
|
"""
|
||||||
|
Build a data structure that describes the list of files
|
||||||
|
"""
|
||||||
|
|
||||||
|
# If there's just one folder, replace filenames with a list of files inside that folder
|
||||||
|
if len(filenames) == 1 and os.path.isdir(filenames[0]):
|
||||||
|
filenames = [os.path.join(filenames[0], x) for x in os.listdir(filenames[0])]
|
||||||
|
|
||||||
|
self.build_file_list(filenames)
|
||||||
|
|
||||||
|
if self.web.mode == 'share':
|
||||||
|
self.common.log("ShareModeWeb", "set_file_info")
|
||||||
|
self.web.cancel_compression = False
|
||||||
|
self.build_zipfile_list(filenames, processed_size_callback)
|
||||||
|
|
||||||
|
elif self.web.mode == 'website':
|
||||||
|
self.common.log("WebsiteModeWeb", "set_file_info")
|
||||||
|
self.web.cancel_compression = True
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def build_file_list(self, filenames):
|
||||||
|
"""
|
||||||
|
Build a data structure that describes the list of files that make up
|
||||||
|
the static website.
|
||||||
|
"""
|
||||||
|
self.common.log("BaseModeWeb", "build_file_list")
|
||||||
|
|
||||||
|
# Loop through the files
|
||||||
|
for filename in filenames:
|
||||||
|
basename = os.path.basename(filename.rstrip('/'))
|
||||||
|
|
||||||
|
# If it's a filename, add it
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
self.files[basename] = filename
|
||||||
|
self.root_files[basename] = filename
|
||||||
|
|
||||||
|
# If it's a directory, add it recursively
|
||||||
|
elif os.path.isdir(filename):
|
||||||
|
self.root_files[basename + '/'] = filename
|
||||||
|
|
||||||
|
for root, _, nested_filenames in os.walk(filename):
|
||||||
|
# Normalize the root path. So if the directory name is "/home/user/Documents/some_folder",
|
||||||
|
# and it has a nested folder foobar, the root is "/home/user/Documents/some_folder/foobar".
|
||||||
|
# The normalized_root should be "some_folder/foobar"
|
||||||
|
normalized_root = os.path.join(basename, root[len(filename):].lstrip('/')).rstrip('/')
|
||||||
|
|
||||||
|
# Add the dir itself
|
||||||
|
self.files[normalized_root + '/'] = root
|
||||||
|
|
||||||
|
# Add the files in this dir
|
||||||
|
for nested_filename in nested_filenames:
|
||||||
|
self.files[os.path.join(normalized_root, nested_filename)] = os.path.join(root, nested_filename)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def render_logic(self, path=''):
|
||||||
|
if path in self.files:
|
||||||
|
filesystem_path = self.files[path]
|
||||||
|
|
||||||
|
# If it's a directory
|
||||||
|
if os.path.isdir(filesystem_path):
|
||||||
|
# Is there an index.html?
|
||||||
|
index_path = os.path.join(path, 'index.html')
|
||||||
|
if self.web.mode == 'website' and index_path in self.files:
|
||||||
|
# Render it
|
||||||
|
dirname = os.path.dirname(self.files[index_path])
|
||||||
|
basename = os.path.basename(self.files[index_path])
|
||||||
|
|
||||||
|
return send_from_directory(dirname, basename)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Otherwise, render directory listing
|
||||||
|
filenames = []
|
||||||
|
for filename in os.listdir(filesystem_path):
|
||||||
|
if os.path.isdir(os.path.join(filesystem_path, filename)):
|
||||||
|
filenames.append(filename + '/')
|
||||||
|
else:
|
||||||
|
filenames.append(filename)
|
||||||
|
filenames.sort()
|
||||||
|
return self.directory_listing(filenames, path, filesystem_path)
|
||||||
|
|
||||||
|
# If it's a file
|
||||||
|
elif os.path.isfile(filesystem_path):
|
||||||
|
dirname = os.path.dirname(filesystem_path)
|
||||||
|
basename = os.path.basename(filesystem_path)
|
||||||
|
return send_from_directory(dirname, basename)
|
||||||
|
|
||||||
|
# If it's not a directory or file, throw a 404
|
||||||
|
else:
|
||||||
|
return self.web.error404()
|
||||||
|
else:
|
||||||
|
# Special case loading /
|
||||||
|
|
||||||
|
if path == '':
|
||||||
|
index_path = 'index.html'
|
||||||
|
if self.web.mode == 'website' and index_path in self.files:
|
||||||
|
# Render it
|
||||||
|
dirname = os.path.dirname(self.files[index_path])
|
||||||
|
basename = os.path.basename(self.files[index_path])
|
||||||
|
return send_from_directory(dirname, basename)
|
||||||
|
else:
|
||||||
|
# Root directory listing
|
||||||
|
filenames = list(self.root_files)
|
||||||
|
filenames.sort()
|
||||||
|
return self.directory_listing(filenames, path)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# If the path isn't found, throw a 404
|
||||||
|
return self.web.error404()
|
@ -18,9 +18,6 @@ class ReceiveModeWeb(object):
|
|||||||
|
|
||||||
self.web = web
|
self.web = web
|
||||||
|
|
||||||
# Reset assets path
|
|
||||||
self.web.app.static_folder=self.common.get_resource_path('static')
|
|
||||||
|
|
||||||
self.can_upload = True
|
self.can_upload = True
|
||||||
self.upload_count = 0
|
self.upload_count = 0
|
||||||
self.uploads_in_progress = []
|
self.uploads_in_progress = []
|
||||||
|
@ -6,46 +6,26 @@ import mimetypes
|
|||||||
import gzip
|
import gzip
|
||||||
from flask import Response, request, render_template, make_response
|
from flask import Response, request, render_template, make_response
|
||||||
|
|
||||||
|
from .base_mode import BaseModeWeb
|
||||||
from .. import strings
|
from .. import strings
|
||||||
|
|
||||||
|
|
||||||
class ShareModeWeb(object):
|
class ShareModeWeb(BaseModeWeb):
|
||||||
"""
|
"""
|
||||||
All of the web logic for share mode
|
All of the web logic for share mode
|
||||||
"""
|
"""
|
||||||
def __init__(self, common, web):
|
def init(self):
|
||||||
self.common = common
|
|
||||||
self.common.log('ShareModeWeb', '__init__')
|
self.common.log('ShareModeWeb', '__init__')
|
||||||
|
|
||||||
self.web = web
|
|
||||||
|
|
||||||
# Information about the file to be shared
|
|
||||||
self.file_info = []
|
|
||||||
self.is_zipped = False
|
|
||||||
self.download_filename = None
|
|
||||||
self.download_filesize = None
|
|
||||||
self.gzip_filename = None
|
|
||||||
self.gzip_filesize = None
|
|
||||||
self.zip_writer = None
|
|
||||||
|
|
||||||
self.download_count = 0
|
|
||||||
|
|
||||||
# If "Stop After First Download" is checked (stay_open == False), only allow
|
|
||||||
# one download at a time.
|
|
||||||
self.download_in_progress = False
|
|
||||||
|
|
||||||
# Reset assets path
|
|
||||||
self.web.app.static_folder=self.common.get_resource_path('static')
|
|
||||||
|
|
||||||
|
|
||||||
self.define_routes()
|
self.define_routes()
|
||||||
|
|
||||||
def define_routes(self):
|
def define_routes(self):
|
||||||
"""
|
"""
|
||||||
The web app routes for sharing files
|
The web app routes for sharing files
|
||||||
"""
|
"""
|
||||||
@self.web.app.route("/")
|
@self.web.app.route('/', defaults={'path': ''})
|
||||||
def index():
|
@self.web.app.route('/<path:path>')
|
||||||
|
def index(path):
|
||||||
"""
|
"""
|
||||||
Render the template for the onionshare landing page.
|
Render the template for the onionshare landing page.
|
||||||
"""
|
"""
|
||||||
@ -65,15 +45,8 @@ class ShareModeWeb(object):
|
|||||||
else:
|
else:
|
||||||
self.filesize = self.download_filesize
|
self.filesize = self.download_filesize
|
||||||
|
|
||||||
r = make_response(render_template(
|
return self.render_logic(path)
|
||||||
'send.html',
|
|
||||||
file_info=self.file_info,
|
|
||||||
filename=os.path.basename(self.download_filename),
|
|
||||||
filesize=self.filesize,
|
|
||||||
filesize_human=self.common.human_readable_filesize(self.download_filesize),
|
|
||||||
is_zipped=self.is_zipped,
|
|
||||||
static_url_path=self.web.static_url_path))
|
|
||||||
return self.web.add_security_headers(r)
|
|
||||||
|
|
||||||
@self.web.app.route("/download")
|
@self.web.app.route("/download")
|
||||||
def download():
|
def download():
|
||||||
@ -198,19 +171,8 @@ class ShareModeWeb(object):
|
|||||||
r.headers.set('Content-Type', content_type)
|
r.headers.set('Content-Type', content_type)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def set_file_info(self, filenames, processed_size_callback=None):
|
def build_zipfile_list(self, filenames, processed_size_callback=None):
|
||||||
"""
|
self.common.log("ShareModeWeb", "build_zipfile_list")
|
||||||
Using the list of filenames being shared, fill in details that the web
|
|
||||||
page will need to display. This includes zipping up the file in order to
|
|
||||||
get the zip file's name and size.
|
|
||||||
"""
|
|
||||||
self.common.log("ShareModeWeb", "set_file_info")
|
|
||||||
self.web.cancel_compression = False
|
|
||||||
|
|
||||||
self.cleanup_filenames = []
|
|
||||||
|
|
||||||
# build file info list
|
|
||||||
self.file_info = {'files': [], 'dirs': []}
|
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
info = {
|
info = {
|
||||||
'filename': filename,
|
'filename': filename,
|
||||||
|
@ -51,12 +51,16 @@ class Web(object):
|
|||||||
self.common = common
|
self.common = common
|
||||||
self.common.log('Web', '__init__', 'is_gui={}, mode={}'.format(is_gui, mode))
|
self.common.log('Web', '__init__', 'is_gui={}, mode={}'.format(is_gui, mode))
|
||||||
|
|
||||||
|
# The static URL path has a 128-bit random number in it to avoid having name
|
||||||
|
# collisions with files that might be getting shared
|
||||||
|
self.static_url_path = '/static_{}'.format(self.common.random_string(16))
|
||||||
|
|
||||||
# The flask app
|
# The flask app
|
||||||
self.app = Flask(__name__,
|
self.app = Flask(__name__,
|
||||||
|
static_url_path=self.static_url_path,
|
||||||
static_folder=self.common.get_resource_path('static'),
|
static_folder=self.common.get_resource_path('static'),
|
||||||
template_folder=self.common.get_resource_path('templates'))
|
template_folder=self.common.get_resource_path('templates'))
|
||||||
self.app.secret_key = self.common.random_string(8)
|
self.app.secret_key = self.common.random_string(8)
|
||||||
self.generate_static_url_path()
|
|
||||||
self.auth = HTTPBasicAuth()
|
self.auth = HTTPBasicAuth()
|
||||||
self.auth.error_handler(self.error401)
|
self.auth.error_handler(self.error401)
|
||||||
|
|
||||||
@ -225,18 +229,6 @@ class Web(object):
|
|||||||
self.password = self.common.build_password()
|
self.password = self.common.build_password()
|
||||||
self.common.log('Web', 'generate_password', 'built random password: "{}"'.format(self.password))
|
self.common.log('Web', 'generate_password', 'built random password: "{}"'.format(self.password))
|
||||||
|
|
||||||
def generate_static_url_path(self):
|
|
||||||
# The static URL path has a 128-bit random number in it to avoid having name
|
|
||||||
# collisions with files that might be getting shared
|
|
||||||
self.static_url_path = '/static_{}'.format(self.common.random_string(16))
|
|
||||||
self.common.log('Web', 'generate_static_url_path', 'new static_url_path is {}'.format(self.static_url_path))
|
|
||||||
|
|
||||||
# Update the flask route to handle the new static URL path
|
|
||||||
self.app.static_url_path = self.static_url_path
|
|
||||||
self.app.add_url_rule(
|
|
||||||
self.static_url_path + '/<path:filename>',
|
|
||||||
endpoint='static', view_func=self.app.send_static_file)
|
|
||||||
|
|
||||||
def verbose_mode(self):
|
def verbose_mode(self):
|
||||||
"""
|
"""
|
||||||
Turn on verbose mode, which will log flask errors to a file.
|
Turn on verbose mode, which will log flask errors to a file.
|
||||||
|
@ -2,30 +2,21 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from flask import Response, request, render_template, make_response, send_from_directory
|
from flask import Response, request, render_template, make_response
|
||||||
|
|
||||||
|
from .base_mode import BaseModeWeb
|
||||||
from .. import strings
|
from .. import strings
|
||||||
|
|
||||||
|
|
||||||
class WebsiteModeWeb(object):
|
class WebsiteModeWeb(BaseModeWeb):
|
||||||
"""
|
"""
|
||||||
All of the web logic for share mode
|
All of the web logic for website mode
|
||||||
"""
|
"""
|
||||||
def __init__(self, common, web):
|
def init(self):
|
||||||
self.common = common
|
|
||||||
self.common.log('WebsiteModeWeb', '__init__')
|
self.common.log('WebsiteModeWeb', '__init__')
|
||||||
|
|
||||||
self.web = web
|
|
||||||
|
|
||||||
# Dictionary mapping file paths to filenames on disk
|
|
||||||
self.files = {}
|
|
||||||
self.visit_count = 0
|
|
||||||
|
|
||||||
# Reset assets path
|
|
||||||
self.web.app.static_folder=self.common.get_resource_path('static')
|
|
||||||
|
|
||||||
self.define_routes()
|
self.define_routes()
|
||||||
|
|
||||||
|
|
||||||
def define_routes(self):
|
def define_routes(self):
|
||||||
"""
|
"""
|
||||||
The web app routes for sharing a website
|
The web app routes for sharing a website
|
||||||
@ -51,131 +42,4 @@ class WebsiteModeWeb(object):
|
|||||||
'action': 'visit'
|
'action': 'visit'
|
||||||
})
|
})
|
||||||
|
|
||||||
if path in self.files:
|
return self.render_logic(path)
|
||||||
filesystem_path = self.files[path]
|
|
||||||
|
|
||||||
# If it's a directory
|
|
||||||
if os.path.isdir(filesystem_path):
|
|
||||||
# Is there an index.html?
|
|
||||||
index_path = os.path.join(path, 'index.html')
|
|
||||||
if index_path in self.files:
|
|
||||||
# Render it
|
|
||||||
dirname = os.path.dirname(self.files[index_path])
|
|
||||||
basename = os.path.basename(self.files[index_path])
|
|
||||||
return send_from_directory(dirname, basename)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Otherwise, render directory listing
|
|
||||||
filenames = []
|
|
||||||
for filename in os.listdir(filesystem_path):
|
|
||||||
if os.path.isdir(os.path.join(filesystem_path, filename)):
|
|
||||||
filenames.append(filename + '/')
|
|
||||||
else:
|
|
||||||
filenames.append(filename)
|
|
||||||
filenames.sort()
|
|
||||||
return self.directory_listing(path, filenames, filesystem_path)
|
|
||||||
|
|
||||||
# If it's a file
|
|
||||||
elif os.path.isfile(filesystem_path):
|
|
||||||
dirname = os.path.dirname(filesystem_path)
|
|
||||||
basename = os.path.basename(filesystem_path)
|
|
||||||
return send_from_directory(dirname, basename)
|
|
||||||
|
|
||||||
# If it's not a directory or file, throw a 404
|
|
||||||
else:
|
|
||||||
return self.web.error404()
|
|
||||||
else:
|
|
||||||
# Special case loading /
|
|
||||||
if path == '':
|
|
||||||
index_path = 'index.html'
|
|
||||||
if index_path in self.files:
|
|
||||||
# Render it
|
|
||||||
dirname = os.path.dirname(self.files[index_path])
|
|
||||||
basename = os.path.basename(self.files[index_path])
|
|
||||||
return send_from_directory(dirname, basename)
|
|
||||||
else:
|
|
||||||
# Root directory listing
|
|
||||||
filenames = list(self.root_files)
|
|
||||||
filenames.sort()
|
|
||||||
return self.directory_listing(path, filenames)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# If the path isn't found, throw a 404
|
|
||||||
return self.web.error404()
|
|
||||||
|
|
||||||
def directory_listing(self, path, filenames, filesystem_path=None):
|
|
||||||
# If filesystem_path is None, this is the root directory listing
|
|
||||||
files = []
|
|
||||||
dirs = []
|
|
||||||
|
|
||||||
for filename in filenames:
|
|
||||||
if filesystem_path:
|
|
||||||
this_filesystem_path = os.path.join(filesystem_path, filename)
|
|
||||||
else:
|
|
||||||
this_filesystem_path = self.files[filename]
|
|
||||||
|
|
||||||
is_dir = os.path.isdir(this_filesystem_path)
|
|
||||||
|
|
||||||
if is_dir:
|
|
||||||
dirs.append({
|
|
||||||
'basename': filename
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
size = os.path.getsize(this_filesystem_path)
|
|
||||||
size_human = self.common.human_readable_filesize(size)
|
|
||||||
files.append({
|
|
||||||
'basename': filename,
|
|
||||||
'size_human': size_human
|
|
||||||
})
|
|
||||||
|
|
||||||
r = make_response(render_template('listing.html',
|
|
||||||
path=path,
|
|
||||||
files=files,
|
|
||||||
dirs=dirs,
|
|
||||||
static_url_path=self.web.static_url_path))
|
|
||||||
return self.web.add_security_headers(r)
|
|
||||||
|
|
||||||
def set_file_info(self, filenames):
|
|
||||||
"""
|
|
||||||
Build a data structure that describes the list of files that make up
|
|
||||||
the static website.
|
|
||||||
"""
|
|
||||||
self.common.log("WebsiteModeWeb", "set_file_info")
|
|
||||||
|
|
||||||
# This is a dictionary that maps HTTP routes to filenames on disk
|
|
||||||
self.files = {}
|
|
||||||
|
|
||||||
# This is only the root files and dirs, as opposed to all of them
|
|
||||||
self.root_files = {}
|
|
||||||
|
|
||||||
# If there's just one folder, replace filenames with a list of files inside that folder
|
|
||||||
if len(filenames) == 1 and os.path.isdir(filenames[0]):
|
|
||||||
filenames = [os.path.join(filenames[0], x) for x in os.listdir(filenames[0])]
|
|
||||||
|
|
||||||
# Loop through the files
|
|
||||||
for filename in filenames:
|
|
||||||
basename = os.path.basename(filename.rstrip('/'))
|
|
||||||
|
|
||||||
# If it's a filename, add it
|
|
||||||
if os.path.isfile(filename):
|
|
||||||
self.files[basename] = filename
|
|
||||||
self.root_files[basename] = filename
|
|
||||||
|
|
||||||
# If it's a directory, add it recursively
|
|
||||||
elif os.path.isdir(filename):
|
|
||||||
self.root_files[basename + '/'] = filename
|
|
||||||
|
|
||||||
for root, _, nested_filenames in os.walk(filename):
|
|
||||||
# Normalize the root path. So if the directory name is "/home/user/Documents/some_folder",
|
|
||||||
# and it has a nested folder foobar, the root is "/home/user/Documents/some_folder/foobar".
|
|
||||||
# The normalized_root should be "some_folder/foobar"
|
|
||||||
normalized_root = os.path.join(basename, root[len(filename):].lstrip('/')).rstrip('/')
|
|
||||||
|
|
||||||
# Add the dir itself
|
|
||||||
self.files[normalized_root + '/'] = root
|
|
||||||
|
|
||||||
# Add the files in this dir
|
|
||||||
for nested_filename in nested_filenames:
|
|
||||||
self.files[os.path.join(normalized_root, nested_filename)] = os.path.join(root, nested_filename)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
@ -42,9 +42,6 @@ class OnionThread(QtCore.QThread):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.mode.common.log('OnionThread', 'run')
|
self.mode.common.log('OnionThread', 'run')
|
||||||
|
|
||||||
# Make a new static URL path for each new share
|
|
||||||
self.mode.web.generate_static_url_path()
|
|
||||||
|
|
||||||
# Choose port and password early, because we need them to exist in advance for scheduled shares
|
# Choose port and password early, because we need them to exist in advance for scheduled shares
|
||||||
self.mode.app.stay_open = not self.mode.common.settings.get('close_after_first_download')
|
self.mode.app.stay_open = not self.mode.common.settings.get('close_after_first_download')
|
||||||
if not self.mode.app.port:
|
if not self.mode.app.port:
|
||||||
|
@ -28,24 +28,27 @@
|
|||||||
<th id="size-header">Size</th>
|
<th id="size-header">Size</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for info in file_info.dirs %}
|
{% for info in dirs %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_folder.png" />
|
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_folder.png" />
|
||||||
|
<a href="{{ info.basename }}">
|
||||||
{{ info.basename }}
|
{{ info.basename }}
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ info.size_human }}</td>
|
<td>—</td>
|
||||||
<td></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for info in file_info.files %}
|
|
||||||
|
{% for info in files %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_file.png" />
|
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_file.png" />
|
||||||
|
<a href="{{ info.basename }}">
|
||||||
{{ info.basename }}
|
{{ info.basename }}
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ info.size_human }}</td>
|
<td>{{ info.size_human }}</td>
|
||||||
<td></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
Loading…
Reference in New Issue
Block a user