Skip to content

Commit

Permalink
move sqlalchemy session management out of gui
Browse files Browse the repository at this point in the history
  • Loading branch information
Allie Crevier committed May 24, 2019
1 parent 41faea7 commit e21084e
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 41 deletions.
2 changes: 1 addition & 1 deletion securedrop_client/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def start_app(args, qt_args) -> None:

session_maker = make_session_maker(args.sdc_home)

gui = Window(session_maker)
gui = Window()

app.setWindowIcon(load_icon(gui.icon))
app.setStyleSheet(load_css('sdclient.css'))
Expand Down
5 changes: 2 additions & 3 deletions securedrop_client/gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from typing import Dict, List, Optional # noqa: F401
from PyQt5.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QDesktopWidget, \
QApplication
from sqlalchemy.orm import scoped_session

from securedrop_client import __version__
from securedrop_client.db import Source
Expand All @@ -44,7 +43,7 @@ class Window(QMainWindow):

icon = 'icon.png'

def __init__(self, session_maker: scoped_session) -> None:
def __init__(self) -> None:
"""
Create the default start state. The window contains a root widget into
which is placed:
Expand All @@ -69,7 +68,7 @@ def __init__(self, session_maker: scoped_session) -> None:
layout.setSpacing(0)
self.main_pane.setLayout(layout)
self.left_pane = LeftPane()
self.main_view = MainView(session_maker, self.main_pane)
self.main_view = MainView(self.main_pane)
layout.addWidget(self.left_pane, 1)
layout.addWidget(self.main_view, 8)

Expand Down
54 changes: 19 additions & 35 deletions securedrop_client/gui/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from PyQt5.QtWidgets import QListWidget, QLabel, QWidget, QListWidgetItem, QHBoxLayout, \
QPushButton, QVBoxLayout, QLineEdit, QScrollArea, QDialog, QAction, QMenu, QMessageBox, \
QToolButton, QSizePolicy, QTextEdit, QStatusBar, QGraphicsDropShadowEffect
from sqlalchemy.orm import scoped_session

from securedrop_client.db import Source, Message, File, Reply
from securedrop_client.storage import source_exists
Expand Down Expand Up @@ -588,9 +587,8 @@ class MainView(QWidget):
}
'''

def __init__(self, session_maker: scoped_session, parent: QObject):
def __init__(self, parent: QObject):
super().__init__(parent)
self.session_maker = session_maker

self.setStyleSheet(self.CSS)

Expand Down Expand Up @@ -633,11 +631,7 @@ def on_source_changed(self):
source = self.source_list.get_current_source()

if source:
conversation_wrapper = SourceConversationWrapper(
self.session_maker,
source,
self.controller,
)
conversation_wrapper = SourceConversationWrapper(source, self.controller)
self.set_conversation(conversation_wrapper)
else:
self.clear_conversation()
Expand Down Expand Up @@ -1282,7 +1276,6 @@ class FileWidget(QWidget):

def __init__(
self,
session_maker: scoped_session,
file_uuid: str,
controller: Controller,
file_ready_signal: pyqtBoundSignal,
Expand All @@ -1291,35 +1284,23 @@ def __init__(
Given some text and a reference to the controller, make something to display a file.
"""
super().__init__()
self.session_maker = session_maker
self.controller = controller
self.file_uuid = file_uuid
self.file_is_downloaded = False # default to `False`, value updated in `update()`
self.file = self.controller.get_file(file_uuid)

self.layout = QHBoxLayout()
self.update()
self.setLayout(self.layout)

file_ready_signal.connect(self._on_file_download, type=Qt.QueuedConnection)
file_ready_signal.connect(self._on_file_downloaded, type=Qt.QueuedConnection)

def update(self) -> None:
icon = QLabel()
icon.setPixmap(load_image('file.png'))

session = self.session_maker()

# we have to query to get the object we want
file_ = session.query(File).filter_by(uuid=self.file_uuid).one()
# and then force a refresh because SQLAlchemy might have a copy of this object
# in this thread already that isn't up to date
session.refresh(file_)

self.file_is_downloaded = file_.is_downloaded

if self.file_is_downloaded:
if self.file.is_downloaded:
description = QLabel("Open")
else:
human_filesize = humanize_filesize(file_.size)
human_filesize = humanize_filesize(self.file.size)
description = QLabel("Download ({})".format(human_filesize))

self.layout.addWidget(icon)
Expand All @@ -1333,8 +1314,12 @@ def clear(self) -> None:
child.widget().deleteLater()

@pyqtSlot(str)
def _on_file_download(self, file_uuid: str) -> None:
if file_uuid == self.file_uuid:
def _on_file_downloaded(self, file_uuid: str) -> None:
if file_uuid == self.file.uuid:
# update state
self.file = self.controller.get_file(self.file.uuid)

# update gui
self.clear() # delete existing icon and label
self.update() # draw modified widget

Expand All @@ -1343,12 +1328,15 @@ def mouseReleaseEvent(self, e):
Handle a completed click via the program logic. The download state
of the file distinguishes which function in the logic layer to call.
"""
if self.file_is_downloaded:
# update state
self.file = self.controller.get_file(self.file.uuid)

if self.file.is_downloaded:
# Open the already downloaded file.
self.controller.on_file_open(self.file_uuid)
self.controller.on_file_open(self.file.uuid)
else:
# Download the file.
self.controller.on_submission_download(File, self.file_uuid)
self.controller.on_submission_download(File, self.file.uuid)


class ConversationView(QWidget):
Expand All @@ -1362,12 +1350,10 @@ class ConversationView(QWidget):

def __init__(
self,
session_maker: scoped_session,
source_db_object: Source,
controller: Controller,
):
super().__init__()
self.session_maker = session_maker
self.source = source_db_object
self.controller = controller

Expand Down Expand Up @@ -1419,7 +1405,6 @@ def add_file(self, source_db_object, submission_db_object):
"""
self.conversation_layout.addWidget(
FileWidget(
self.session_maker,
submission_db_object.uuid,
self.controller,
self.controller.file_ready,
Expand Down Expand Up @@ -1494,7 +1479,6 @@ class SourceConversationWrapper(QWidget):

def __init__(
self,
session_maker: scoped_session,
source: Source,
controller: Controller,
) -> None:
Expand All @@ -1504,7 +1488,7 @@ def __init__(
self.setLayout(layout)

self.conversation_title_bar = SourceProfileShortWidget(source, controller)
self.conversation_view = ConversationView(session_maker, source, controller)
self.conversation_view = ConversationView(source, controller)
self.reply_box = ReplyBoxWidget(source, controller)

layout.addWidget(self.conversation_title_bar, 1)
Expand Down
9 changes: 7 additions & 2 deletions securedrop_client/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,8 @@ def on_file_open(self, file_db_object):
# Once downloaded, submissions are stored in the data directory
# with the same filename as the server, except with the .gz.gpg
# stripped off.
server_filename = file_db_object.filename
fn_no_ext, _ = os.path.splitext(os.path.splitext(server_filename)[0])
file = self.get_file(file_uuid)
fn_no_ext, _ = os.path.splitext(os.path.splitext(file.filename)[0])
submission_filepath = os.path.join(self.data_dir, fn_no_ext)

if self.proxy:
Expand Down Expand Up @@ -641,3 +641,8 @@ def on_reply_success(self, result, current_object: Tuple[str, str]) -> None:
def on_reply_failure(self, result, current_object: Tuple[str, str]) -> None:
source_uuid, reply_uuid = current_object
self.reply_failed.emit(reply_uuid)

def get_file(self, file_uuid: str) -> db.File:
file = storage.get_file(self.session, file_uuid)
self.session.refresh(file)
return file

1 comment on commit e21084e

@sssoleileraaa
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolves #382

Please sign in to comment.