Skip to content
This repository was archived by the owner on Jan 5, 2024. It is now read-only.
This repository was archived by the owner on Jan 5, 2024. It is now read-only.

breaking up SDExport #33

@redshiftzero

Description

@redshiftzero

This is related to #15 and contains some thoughts on how we might restructure the code in this repo. Note that these are just opinions, we should discuss before doing a big refactor.

First for reference here's a UML diagram of the existing code as of Nov 26:

securedrop_export_classes

We can notice from the UML diagram that each instance of the SDExport class is only ever going to use a subset of the defined methods, i.e. an USB export wouldn't ever use any print-related methods. It's also quite a large class and is doing a lot of different things so imho this is the best class to break up further. This is perfectly natural: originally this was small - and then we added print - and in the future we'll probably add even more export methods.

Here’s one approach for restructuring: instead of each export involving a single SDExport object, each export would involve two objects:

  • an action object, that contains anything related to the specific export action that has been requested (more on that below)
  • a submission object, that contains any other data/methods which isn’t specifically related to the action, i.e. extract_tarball() seems like it should be on this. This is what we'd define here immediately when we get the export archive.

For the action, we'd create an abstract base class e.g. ExportAction which defines the interface that any export actions should implement. Even an interface as minimal as ExportAction.run I think would be beneficial for organization purposes. With that our main would look something like:

submission.extract_tarball()

try:
    submission.archive_metadata = export.Metadata(submission.tmpdir)
except Exception:
    submission.exit_gracefully(ExportStatus.ERROR_METADATA_PARSING.value)

if not submission.archive_metadata.is_valid():
    submission.exit_gracefully(ExportStatus.ERROR_ARCHIVE_METADATA.value)

if submission.archive_metadata.export_method == "usb-test":
    action = UsbTestAction()  # do we need to pass in submission for these test actions? 
elif submission.archive_metadata.export_method == "disk":
    action = UsbExportAction(submission)
# removing disk-test here as we could collapse into usb-test h/t to @emkll for confirming this
elif submission.archive_metadata.export_method == "printer":
    action = PrintExportAction(submission)
elif submission.archive_metadata.export_method == "printer-test":
    action = PrintTestPageAction()

action.run()

The classes that implement the ExportAction base class could have the following hierarchy:

Screen Shot 2019-11-26 at 6 55 24 PM

They'd keep on their classes anything relevant specifically to that action at hand, e.g. for Print* objects they’ll have the print_all_files() and the setup_printer() methods.

Two other smaller things that would be good to do as part of this is:

  1. Make it clear which methods are for a class's internal use and which developers should be calling outside the class - i.e. let's prefix internal methods with _.
  2. We make some methods of SDExport utility functions: I’m specifically thinking of both safe_check_call and popup_message which we could make module-level functions.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions