Implement 'move to subdir' logic & store in settings

Fixes #251 by implementing the logic for archiving a document after
conversion into a default sub-directory.
This commit is contained in:
deeplow 2022-11-16 19:01:49 +00:00
parent d3e125de55
commit bbd0d98f50
No known key found for this signature in database
GPG key ID: 577982871529A52A
4 changed files with 57 additions and 11 deletions

View file

@ -282,6 +282,9 @@ def convert(
) )
shutil.move(container_output_filename, document.output_filename) shutil.move(container_output_filename, document.output_filename)
if document.archive_after_conversion:
document.archive()
# We did it # We did it
success = True success = True

View file

@ -13,6 +13,7 @@ import appdirs
from . import errors from . import errors
SAFE_EXTENSION = "-safe.pdf" SAFE_EXTENSION = "-safe.pdf"
ARCHIVE_SUBDIR = "unsafe"
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -35,12 +36,14 @@ class Document:
input_filename: str = None, input_filename: str = None,
output_filename: str = None, output_filename: str = None,
suffix: str = SAFE_EXTENSION, suffix: str = SAFE_EXTENSION,
archive: bool = False,
) -> None: ) -> None:
# NOTE: See https://github.com/freedomofpress/dangerzone/pull/216#discussion_r1015449418 # NOTE: See https://github.com/freedomofpress/dangerzone/pull/216#discussion_r1015449418
self.id = secrets.token_urlsafe(6)[0:6] self.id = secrets.token_urlsafe(6)[0:6]
self._input_filename: Optional[str] = None self._input_filename: Optional[str] = None
self._output_filename: Optional[str] = None self._output_filename: Optional[str] = None
self._archive = False
self._suffix = suffix self._suffix = suffix
if input_filename: if input_filename:
@ -51,6 +54,8 @@ class Document:
self.state = Document.STATE_UNCONVERTED self.state = Document.STATE_UNCONVERTED
self.archive_after_conversion = archive
@staticmethod @staticmethod
def normalize_filename(filename: str) -> str: def normalize_filename(filename: str) -> str:
return os.path.abspath(filename) return os.path.abspath(filename)
@ -113,6 +118,33 @@ class Document:
else: else:
raise errors.SuffixNotApplicableException() raise errors.SuffixNotApplicableException()
@property
def archive_after_conversion(self) -> bool:
return self._archive
@archive_after_conversion.setter
def archive_after_conversion(self, enabled: bool) -> None:
if enabled:
self._archive = True
else:
self._archive = False
def archive(self) -> None:
"""
Moves the original document to a subdirectory. Prevents the user from
mistakenly opening the unsafe (original) document.
"""
archive_dir = self.default_archive_dir
old_file_path = Path(self.input_filename)
new_file_path = archive_dir / old_file_path.name
log.debug(f"Archiving doc {self.id} to {new_file_path}")
Path.mkdir(archive_dir, exist_ok=True)
old_file_path.rename(new_file_path)
@property
def default_archive_dir(self) -> Path:
return Path(self.input_filename).parent / ARCHIVE_SUBDIR
@property @property
def default_output_filename(self) -> str: def default_output_filename(self) -> str:
return f"{os.path.splitext(self.input_filename)[0]}{self.suffix}" return f"{os.path.splitext(self.input_filename)[0]}{self.suffix}"

View file

@ -355,9 +355,8 @@ class SettingsWidget(QtWidgets.QWidget):
save_group_box_layout.setContentsMargins(20, 0, 0, 0) save_group_box_layout.setContentsMargins(20, 0, 0, 0)
save_group_box_layout.addWidget(save_group_box) save_group_box_layout.addWidget(save_group_box)
self.radio_move_untrusted = QtWidgets.QRadioButton( self.radio_move_untrusted = QtWidgets.QRadioButton(
"Move unsafe PDFs to 'unsafe' subdirectory" "Move original documents to 'unsafe' subdirectory"
) )
self.radio_move_untrusted.setChecked(True)
save_group_box_innner_layout.addWidget(self.radio_move_untrusted) save_group_box_innner_layout.addWidget(self.radio_move_untrusted)
self.radio_save_to = QtWidgets.QRadioButton() self.radio_save_to = QtWidgets.QRadioButton()
self.save_label.clicked.connect( self.save_label.clicked.connect(
@ -433,6 +432,11 @@ class SettingsWidget(QtWidgets.QWidget):
else: else:
self.safe_extension.setText(SAFE_EXTENSION) self.safe_extension.setText(SAFE_EXTENSION)
if self.dangerzone.settings.get("archive"):
self.radio_move_untrusted.setChecked(True)
else:
self.radio_save_to.setChecked(True)
if self.dangerzone.settings.get("ocr"): if self.dangerzone.settings.get("ocr"):
self.ocr_checkbox.setCheckState(QtCore.Qt.Checked) self.ocr_checkbox.setCheckState(QtCore.Qt.Checked)
else: else:
@ -524,23 +528,29 @@ class SettingsWidget(QtWidgets.QWidget):
self.save_location.setText(selected_dir) self.save_location.setText(selected_dir)
def start_button_clicked(self) -> None: def start_button_clicked(self) -> None:
if self.save_checkbox.checkState() == QtCore.Qt.Unchecked: for document in self.dangerzone.get_unconverted_documents():
# If not saving, then save it to a temp file instead if self.save_checkbox.isChecked():
for document in self.dangerzone.get_unconverted_documents(): # If we're saving the document, set the suffix that the user chose. Then
# check if we should to store the document in the same directory, and
# move the original document to an 'unsafe' subdirectory, or save the
# document to another directory.
document.suffix = self.safe_extension.text()
if self.radio_move_untrusted.isChecked():
document.archive_after_conversion = True
elif self.radio_save_to.isChecked():
if self.output_dir:
document.set_output_dir(self.output_dir) # type: ignore [unreachable]
else:
# If not saving, then save it to a temp file instead
(_, tmp) = tempfile.mkstemp(suffix=".pdf", prefix="dangerzone_") (_, tmp) = tempfile.mkstemp(suffix=".pdf", prefix="dangerzone_")
document.output_filename = tmp document.output_filename = tmp
else:
for document in self.dangerzone.get_unconverted_documents():
document.suffix = self.safe_extension.text()
if self.output_dir:
document.set_output_dir(self.output_dir) # type: ignore [unreachable]
# Update settings # Update settings
self.dangerzone.settings.set( self.dangerzone.settings.set(
"save", self.save_checkbox.checkState() == QtCore.Qt.Checked "save", self.save_checkbox.checkState() == QtCore.Qt.Checked
) )
self.dangerzone.settings.set("safe_extension", self.safe_extension.text()) self.dangerzone.settings.set("safe_extension", self.safe_extension.text())
self.dangerzone.settings.set("archive", self.radio_move_untrusted.isChecked())
self.dangerzone.settings.set( self.dangerzone.settings.set(
"ocr", self.ocr_checkbox.checkState() == QtCore.Qt.Checked "ocr", self.ocr_checkbox.checkState() == QtCore.Qt.Checked
) )

View file

@ -21,6 +21,7 @@ class Settings:
) )
self.default_settings: Dict[str, Any] = { self.default_settings: Dict[str, Any] = {
"save": True, "save": True,
"archive": True,
"ocr": True, "ocr": True,
"ocr_language": "English", "ocr_language": "English",
"open": True, "open": True,