summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Jacq <mig@mig5.net>2018-10-27 17:51:20 +1100
committerGitHub <noreply@github.com>2018-10-27 17:51:20 +1100
commit7956b33a46f08dfc44cc1084e6e802f21389a5e2 (patch)
tree26bf744869ff965782fe60acae3a36871075bbe1
parent23a1ed9165324340024544679ac21e92d277c2e1 (diff)
parentf5e0e9dd62c920f6f5b7c98636d8ee156d3ed1ce (diff)
downloadonionshare-7956b33a46f08dfc44cc1084e6e802f21389a5e2.tar.gz
onionshare-7956b33a46f08dfc44cc1084e6e802f21389a5e2.zip
Merge pull request #814 from micahflee/743_receive_mode_organize
Receive mode organizes files for you
-rw-r--r--onionshare/__init__.py2
-rw-r--r--onionshare/common.py27
-rw-r--r--onionshare/web/receive_mode.py34
-rw-r--r--onionshare/web/web.py6
-rw-r--r--onionshare_gui/mode/__init__.py6
-rw-r--r--onionshare_gui/mode/history.py13
-rw-r--r--onionshare_gui/mode/receive_mode/__init__.py10
-rw-r--r--onionshare_gui/onionshare_gui.py8
-rw-r--r--onionshare_gui/receive_mode/uploads.py12
-rw-r--r--share/locale/en.json1
-rw-r--r--tests/GuiReceiveTest.py31
11 files changed, 91 insertions, 59 deletions
diff --git a/onionshare/__init__.py b/onionshare/__init__.py
index 069559c5..1e81333e 100644
--- a/onionshare/__init__.py
+++ b/onionshare/__init__.py
@@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, sys, time, argparse, threading
from . import strings
-from .common import Common, DownloadsDirErrorCannotCreate, DownloadsDirErrorNotWritable
+from .common import Common
from .web import Web
from .onion import *
from .onionshare import OnionShare
diff --git a/onionshare/common.py b/onionshare/common.py
index cab1e747..ffa6529f 100644
--- a/onionshare/common.py
+++ b/onionshare/common.py
@@ -32,20 +32,6 @@ import time
from .settings import Settings
-class DownloadsDirErrorCannotCreate(Exception):
- """
- Error creating the downloads dir (~/OnionShare by default).
- """
- pass
-
-
-class DownloadsDirErrorNotWritable(Exception):
- """
- Downloads dir is not writable.
- """
- pass
-
-
class Common(object):
"""
The Common object is shared amongst all parts of OnionShare.
@@ -390,19 +376,6 @@ class Common(object):
}"""
}
- def validate_downloads_dir(self):
- """
- Validate that downloads_dir exists, and create it if it doesn't
- """
- if not os.path.isdir(self.settings.get('downloads_dir')):
- try:
- os.mkdir(self.settings.get('downloads_dir'), 0o700)
- except:
- raise DownloadsDirErrorCannotCreate
-
- if not os.access(self.settings.get('downloads_dir'), os.W_OK):
- raise DownloadsDirErrorNotWritable
-
@staticmethod
def random_string(num_bytes, output_len=None):
"""
diff --git a/onionshare/web/receive_mode.py b/onionshare/web/receive_mode.py
index 4a6934a1..3149029f 100644
--- a/onionshare/web/receive_mode.py
+++ b/onionshare/web/receive_mode.py
@@ -4,7 +4,6 @@ from datetime import datetime
from flask import Request, request, render_template, make_response, flash, redirect
from werkzeug.utils import secure_filename
-from ..common import DownloadsDirErrorCannotCreate, DownloadsDirErrorNotWritable
from .. import strings
@@ -59,17 +58,19 @@ class ReceiveModeWeb(object):
"""
Upload files.
"""
- # Make sure downloads_dir exists
+ # Make sure the receive mode dir exists
+ now = datetime.now()
+ date_dir = now.strftime("%Y-%m-%d")
+ time_dir = now.strftime("%H.%M.%S")
+ receive_mode_dir = os.path.join(self.common.settings.get('downloads_dir'), date_dir, time_dir)
valid = True
try:
- self.common.validate_downloads_dir()
- except DownloadsDirErrorCannotCreate:
- self.web.add_request(self.web.REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE, request.path)
- print(strings._('error_cannot_create_downloads_dir').format(self.common.settings.get('downloads_dir')))
- valid = False
- except DownloadsDirErrorNotWritable:
- self.web.add_request(self.web.REQUEST_ERROR_DOWNLOADS_DIR_NOT_WRITABLE, request.path)
- print(strings._('error_downloads_dir_not_writable').format(self.common.settings.get('downloads_dir')))
+ os.makedirs(receive_mode_dir, 0o700)
+ except PermissionError:
+ self.web.add_request(self.web.REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE, request.path, {
+ "receive_mode_dir": receive_mode_dir
+ })
+ print(strings._('error_cannot_create_downloads_dir').format(receive_mode_dir))
valid = False
if not valid:
flash('Error uploading, please inform the OnionShare user', 'error')
@@ -86,7 +87,7 @@ class ReceiveModeWeb(object):
# Automatically rename the file, if a file of the same name already exists
filename = secure_filename(f.filename)
filenames.append(filename)
- local_path = os.path.join(self.common.settings.get('downloads_dir'), filename)
+ local_path = os.path.join(receive_mode_dir, filename)
if os.path.exists(local_path):
if '.' in filename:
# Add "-i", e.g. change "foo.txt" to "foo-2.txt"
@@ -98,7 +99,7 @@ class ReceiveModeWeb(object):
valid = False
while not valid:
new_filename = '{}-{}.{}'.format('.'.join(name), i, ext)
- local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
+ local_path = os.path.join(receive_mode_dir, new_filename)
if os.path.exists(local_path):
i += 1
else:
@@ -109,7 +110,7 @@ class ReceiveModeWeb(object):
valid = False
while not valid:
new_filename = '{}-{}'.format(filename, i)
- local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
+ local_path = os.path.join(receive_mode_dir, new_filename)
if os.path.exists(local_path):
i += 1
else:
@@ -124,6 +125,13 @@ class ReceiveModeWeb(object):
'new_filename': basename
})
+ # Tell the GUI the receive mode directory for this file
+ self.web.add_request(self.web.REQUEST_UPLOAD_SET_DIR, request.path, {
+ 'id': request.upload_id,
+ 'filename': basename,
+ 'dir': receive_mode_dir
+ })
+
self.common.log('ReceiveModeWeb', 'define_routes', '/upload, uploaded {}, saving to {}'.format(f.filename, local_path))
print(strings._('receive_mode_received_file').format(local_path))
f.save(local_path)
diff --git a/onionshare/web/web.py b/onionshare/web/web.py
index 52c4da16..a423b2e1 100644
--- a/onionshare/web/web.py
+++ b/onionshare/web/web.py
@@ -37,9 +37,9 @@ class Web(object):
REQUEST_RATE_LIMIT = 5
REQUEST_CLOSE_SERVER = 6
REQUEST_UPLOAD_FILE_RENAMED = 7
- REQUEST_UPLOAD_FINISHED = 8
- REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE = 9
- REQUEST_ERROR_DOWNLOADS_DIR_NOT_WRITABLE = 10
+ REQUEST_UPLOAD_SET_DIR = 8
+ REQUEST_UPLOAD_FINISHED = 9
+ REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE = 10
def __init__(self, common, is_gui, mode='share'):
self.common = common
diff --git a/onionshare_gui/mode/__init__.py b/onionshare_gui/mode/__init__.py
index 0971ff32..5110289f 100644
--- a/onionshare_gui/mode/__init__.py
+++ b/onionshare_gui/mode/__init__.py
@@ -324,6 +324,12 @@ class Mode(QtWidgets.QWidget):
"""
pass
+ def handle_request_upload_set_dir(self, event):
+ """
+ Handle REQUEST_UPLOAD_SET_DIR event.
+ """
+ pass
+
def handle_request_upload_finished(self, event):
"""
Handle REQUEST_UPLOAD_FINISHED event.
diff --git a/onionshare_gui/mode/history.py b/onionshare_gui/mode/history.py
index b446b9fb..38e0fed3 100644
--- a/onionshare_gui/mode/history.py
+++ b/onionshare_gui/mode/history.py
@@ -118,6 +118,7 @@ class UploadHistoryItemFile(QtWidgets.QWidget):
self.common.log('UploadHistoryItemFile', '__init__', 'filename: {}'.format(filename))
self.filename = filename
+ self.dir = None
self.started = datetime.now()
# Filename label
@@ -158,13 +159,20 @@ class UploadHistoryItemFile(QtWidgets.QWidget):
self.filename = new_filename
self.filename_label.setText(self.filename)
+ def set_dir(self, dir):
+ self.dir = dir
+
def open_folder(self):
"""
Open the downloads folder, with the file selected, in a cross-platform manner
"""
self.common.log('UploadHistoryItemFile', 'open_folder')
- abs_filename = os.path.join(self.common.settings.get('downloads_dir'), self.filename)
+ if not self.dir:
+ self.common.log('UploadHistoryItemFile', 'open_folder', "dir has not been set yet, can't open folder")
+ return
+
+ abs_filename = os.path.join(self.dir, self.filename)
# Linux
if self.common.platform == 'Linux' or self.common.platform == 'BSD':
@@ -266,6 +274,9 @@ class UploadHistoryItem(HistoryItem):
self.files[data['old_filename']].rename(data['new_filename'])
self.files[data['new_filename']] = self.files.pop(data['old_filename'])
+ elif data['action'] == 'set_dir':
+ self.files[data['filename']].set_dir(data['dir'])
+
elif data['action'] == 'finished':
# Hide the progress bar
self.progress_bar.hide()
diff --git a/onionshare_gui/mode/receive_mode/__init__.py b/onionshare_gui/mode/receive_mode/__init__.py
index f070f963..d6c0c351 100644
--- a/onionshare_gui/mode/receive_mode/__init__.py
+++ b/onionshare_gui/mode/receive_mode/__init__.py
@@ -168,6 +168,16 @@ class ReceiveMode(Mode):
'new_filename': event["data"]["new_filename"]
})
+ def handle_request_upload_set_dir(self, event):
+ """
+ Handle REQUEST_UPLOAD_SET_DIR event.
+ """
+ self.history.update(event["data"]["id"], {
+ 'action': 'set_dir',
+ 'filename': event["data"]["filename"],
+ 'dir': event["data"]["dir"]
+ })
+
def handle_request_upload_finished(self, event):
"""
Handle REQUEST_UPLOAD_FINISHED event.
diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py
index 8c8e4e73..eab3261e 100644
--- a/onionshare_gui/onionshare_gui.py
+++ b/onionshare_gui/onionshare_gui.py
@@ -390,14 +390,14 @@ class OnionShareGui(QtWidgets.QMainWindow):
elif event["type"] == Web.REQUEST_UPLOAD_FILE_RENAMED:
mode.handle_request_upload_file_renamed(event)
+ elif event["type"] == Web.REQUEST_UPLOAD_SET_DIR:
+ mode.handle_request_upload_set_dir(event)
+
elif event["type"] == Web.REQUEST_UPLOAD_FINISHED:
mode.handle_request_upload_finished(event)
if event["type"] == Web.REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE:
- Alert(self.common, strings._('error_cannot_create_downloads_dir').format(self.common.settings.get('downloads_dir')))
-
- if event["type"] == Web.REQUEST_ERROR_DOWNLOADS_DIR_NOT_WRITABLE:
- Alert(self.common, strings._('error_downloads_dir_not_writable').format(self.common.settings.get('downloads_dir')))
+ Alert(self.common, strings._('error_cannot_create_downloads_dir').format(event["data"]["receive_mode_dir"]))
if event["type"] == Web.REQUEST_OTHER:
if event["path"] != '/favicon.ico' and event["path"] != "/{}/shutdown".format(mode.web.shutdown_slug):
diff --git a/onionshare_gui/receive_mode/uploads.py b/onionshare_gui/receive_mode/uploads.py
index 33d993b3..68c94b1c 100644
--- a/onionshare_gui/receive_mode/uploads.py
+++ b/onionshare_gui/receive_mode/uploads.py
@@ -35,6 +35,7 @@ class File(QtWidgets.QWidget):
self.common.log('File', '__init__', 'filename: {}'.format(filename))
self.filename = filename
+ self.dir = None
self.started = datetime.now()
# Filename label
@@ -71,6 +72,9 @@ class File(QtWidgets.QWidget):
if complete:
self.folder_button.show()
+ def set_dir(self, dir):
+ self.dir = dir
+
def rename(self, new_filename):
self.filename = new_filename
self.filename_label.setText(self.filename)
@@ -81,7 +85,10 @@ class File(QtWidgets.QWidget):
"""
self.common.log('File', 'open_folder')
- abs_filename = os.path.join(self.common.settings.get('downloads_dir'), self.filename)
+ if not self.dir:
+ return
+
+ abs_filename = os.path.join(self.dir, self.filename)
# Linux
if self.common.platform == 'Linux' or self.common.platform == 'BSD':
@@ -182,6 +189,9 @@ class Upload(QtWidgets.QWidget):
self.files[old_filename].rename(new_filename)
self.files[new_filename] = self.files.pop(old_filename)
+ def set_dir(self, filename, dir):
+ self.files[filename].set_dir(dir)
+
def finished(self):
# Hide the progress bar
self.progress_bar.hide()
diff --git a/share/locale/en.json b/share/locale/en.json
index db416c9b..d57ef3f3 100644
--- a/share/locale/en.json
+++ b/share/locale/en.json
@@ -155,7 +155,6 @@
"info_in_progress_uploads_tooltip": "{} upload(s) in progress",
"info_completed_uploads_tooltip": "{} upload(s) completed",
"error_cannot_create_downloads_dir": "Could not create receive mode folder: {}",
- "error_downloads_dir_not_writable": "The receive mode folder is write protected: {}",
"receive_mode_downloads_dir": "Files sent to you appear in this folder: {}",
"receive_mode_warning": "Warning: Receive mode lets people upload files to your computer. Some files can potentially take control of your computer if you open them. Only open things from people you trust, or if you know what you are doing.",
"gui_receive_mode_warning": "Receive mode lets people upload files to your computer.<br><br><b>Some files can potentially take control of your computer if you open them. Only open things from people you trust, or if you know what you are doing.</b>",
diff --git a/tests/GuiReceiveTest.py b/tests/GuiReceiveTest.py
index a659a79f..eaed8343 100644
--- a/tests/GuiReceiveTest.py
+++ b/tests/GuiReceiveTest.py
@@ -1,10 +1,11 @@
import os
import requests
+from datetime import datetime, timedelta
from PyQt5 import QtCore, QtTest
from .GuiBaseTest import GuiBaseTest
class GuiReceiveTest(GuiBaseTest):
- def upload_file(self, public_mode, file_to_upload, expected_file):
+ def upload_file(self, public_mode, file_to_upload, expected_basename):
'''Test that we can upload the file'''
files = {'file[]': open(file_to_upload, 'rb')}
if not public_mode:
@@ -13,9 +14,23 @@ class GuiReceiveTest(GuiBaseTest):
path = 'http://127.0.0.1:{}/upload'.format(self.gui.app.port)
response = requests.post(path, files=files)
QtTest.QTest.qWait(2000)
- self.assertTrue(os.path.isfile(expected_file))
- def upload_file_should_fail(self, public_mode, expected_file):
+ # Make sure the file is within the last 10 seconds worth of filenames
+ exists = False
+ now = datetime.now()
+ for i in range(10):
+ date_dir = now.strftime("%Y-%m-%d")
+ time_dir = now.strftime("%H.%M.%S")
+ receive_mode_dir = os.path.join(self.gui.common.settings.get('downloads_dir'), date_dir, time_dir)
+ expected_filename = os.path.join(receive_mode_dir, expected_basename)
+ if os.path.exists(expected_filename):
+ exists = True
+ break
+ now = now - timedelta(seconds=1)
+
+ self.assertTrue(exists)
+
+ def upload_file_should_fail(self, public_mode):
'''Test that we can't upload the file when permissions are wrong, and expected content is shown'''
files = {'file[]': open('/tmp/test.txt', 'rb')}
if not public_mode:
@@ -73,14 +88,14 @@ class GuiReceiveTest(GuiBaseTest):
self.run_all_receive_mode_setup_tests(public_mode)
if not public_mode:
self.try_public_paths_in_non_public_mode()
- self.upload_file(public_mode, '/tmp/test.txt', '/tmp/OnionShare/test.txt')
+ self.upload_file(public_mode, '/tmp/test.txt', 'test.txt')
self.history_widgets_present(self.gui.receive_mode)
self.counter_incremented(self.gui.receive_mode, 1)
- self.upload_file(public_mode, '/tmp/test.txt', '/tmp/OnionShare/test-2.txt')
+ self.upload_file(public_mode, '/tmp/test.txt', 'test.txt')
self.counter_incremented(self.gui.receive_mode, 2)
- self.upload_file(public_mode, '/tmp/testdir/test', '/tmp/OnionShare/test')
+ self.upload_file(public_mode, '/tmp/testdir/test', 'test')
self.counter_incremented(self.gui.receive_mode, 3)
- self.upload_file(public_mode, '/tmp/testdir/test', '/tmp/OnionShare/test-2')
+ self.upload_file(public_mode, '/tmp/testdir/test', 'test')
self.counter_incremented(self.gui.receive_mode, 4)
self.history_indicator(self.gui.receive_mode, public_mode)
self.server_is_stopped(self.gui.receive_mode, False)
@@ -94,7 +109,7 @@ class GuiReceiveTest(GuiBaseTest):
'''Attempt to upload (unwritable) files in receive mode and stop the share'''
self.run_all_receive_mode_setup_tests(public_mode)
self.upload_dir_permissions(0o400)
- self.upload_file_should_fail(public_mode, '/tmp/OnionShare/test.txt')
+ self.upload_file_should_fail(public_mode)
self.server_is_stopped(self.gui.receive_mode, True)
self.web_server_is_stopped()
self.server_status_indicator_says_closed(self.gui.receive_mode, False)