Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app: fix conversation refresh/syncing #937

Merged
merged 5 commits into from
Mar 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions securedrop_client/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ class Message(Base):
source_id = Column(Integer, ForeignKey('sources.id'), nullable=False)
source = relationship("Source",
backref=backref("messages", order_by=id,
cascade="delete"))
cascade="delete"),
lazy="joined")

def __init__(self, **kwargs: Any) -> None:
if 'file_counter' in kwargs:
Expand Down Expand Up @@ -174,7 +175,8 @@ class File(Base):
source_id = Column(Integer, ForeignKey('sources.id'), nullable=False)
source = relationship("Source",
backref=backref("files", order_by=id,
cascade="delete"))
cascade="delete"),
lazy="joined")

def __init__(self, **kwargs: Any) -> None:
if 'file_counter' in kwargs:
Expand Down Expand Up @@ -221,7 +223,8 @@ class Reply(Base):
source_id = Column(Integer, ForeignKey('sources.id'), nullable=False)
source = relationship("Source",
backref=backref("replies", order_by=id,
cascade="delete"))
cascade="delete"),
lazy="joined")

journalist_id = Column(Integer, ForeignKey('users.id'))
journalist = relationship(
Expand Down Expand Up @@ -291,7 +294,8 @@ class DraftReply(Base):
source_id = Column(Integer, ForeignKey('sources.id'), nullable=False)
source = relationship("Source",
backref=backref("draftreplies", order_by=id,
cascade="delete"))
cascade="delete"),
lazy="joined")
journalist_id = Column(Integer, ForeignKey('users.id'))
journalist = relationship(
"User", backref=backref('draftreplies', order_by=id))
Expand Down
6 changes: 6 additions & 0 deletions securedrop_client/gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ def hide_login(self):
self.login_dialog.accept()
self.login_dialog = None

def refresh_current_source_conversation(self):
"""
Update the current conversation if the source collection has changed.
"""
self.main_view.on_source_changed()

def show_sources(self, sources: List[Source]):
"""
Update the left hand sources list in the UI with the passed in list of
Expand Down
6 changes: 6 additions & 0 deletions securedrop_client/gui/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ def on_source_changed(self):
# Try to get the SourceConversationWrapper from the persistent dict,
# else we create it.
try:
logger.debug('Drawing source conversation for {}'.format(source.uuid))
conversation_wrapper = self.source_conversations[source.uuid]

# Redraw the conversation view such that new messages, replies, files appear.
Expand Down Expand Up @@ -2195,6 +2196,7 @@ def eventFilter(self, obj, event):

def _set_file_state(self):
if self.file.is_decrypted:
logger.debug('Changing file {} state to decrypted/downloaded'.format(self.uuid))
self._set_file_name()
self.download_button.hide()
self.no_file_name.hide()
Expand All @@ -2203,6 +2205,7 @@ def _set_file_state(self):
self.print_button.show()
self.file_name.show()
else:
logger.debug('Changing file {} state to not downloaded'.format(self.uuid))
self.download_button.setText(_('DOWNLOAD'))
# Ensure correct icon depending on mouse hover state.
if self.download_button.underMouse():
Expand Down Expand Up @@ -3002,13 +3005,16 @@ def update_conversation(self, collection: list) -> None:
# by another user (a journalist using the Web UI is able to delete individual
# submissions).
for item_widget in current_conversation.values():
logger.debug('Deleting item: {}'.format(item_widget.uuid))
self.current_messages.pop(item_widget.uuid)
item_widget.deleteLater()
self.conversation_layout.removeWidget(item_widget)

def add_file(self, file: File, index):
"""
Add a file from the source.
"""
logger.debug('Adding file for {}'.format(file.uuid))
conversation_item = FileWidget(
file.uuid,
self.controller,
Expand Down
1 change: 1 addition & 0 deletions securedrop_client/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ def on_sync_success(self) -> None:
self.file_missing.emit(missed_file.source.uuid, missed_file.uuid,
str(missed_file))
self.update_sources()
self.gui.refresh_current_source_conversation()
self.download_new_messages()
self.download_new_replies()
self.sync_events.emit('synced')
Expand Down
14 changes: 14 additions & 0 deletions tests/gui/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,20 @@ def test_hide_login(mocker):
assert w.login_dialog is None


def test_refresh_current_source_conversation(mocker):
"""
Ensure on_source_changed is called on the MainView (which
updates the current conversation) when
refresh_current_source_conversation() is called.
"""
w = Window()
w.main_view = mocker.MagicMock()

w.refresh_current_source_conversation()

w.main_view.on_source_changed.assert_called_once_with()


def test_show_sources(mocker):
"""
Ensure the sources list is passed to the main view to be updated.
Expand Down