Repository: freedomofpress/securedrop

Issue:
Don't show sources that haven't submitted anything
The latest submissions page lists all of the source codenames, including codenames of sources that haven't submitted any messages or documents. It would be helpful if sources that don't actually have any data were all listed at the bottom instead of in chronological order, or even if they weren't listed at all.

Similarly, it would be nice to be able to "favorite" sources so that they always stuck to the top.

Don't show sources that haven't submitted anything
The latest submissions page lists all of the source codenames, including codenames of sources that haven't submitted any messages or documents. It would be helpful if sources that don't actually have any data were all listed at the bottom instead of in chronological order, or even if they weren't listed at all.

Similarly, it would be nice to be able to "favorite" sources so that they always stuck to the top.



Discussion:
After giving some thought and (briefly) talking with @garrettr, I think it makes sense to do this:

Each source should have an "active" flag that starts out as false and becomes true the first time they submit a message or document. Only "active" sources should show up in the list to journalists. This will prevent total spam sources from cluttering up the interface.

Maybe there's a better word than active to use.

Verified?

Verified could work, but it has a different meaning to journalists. When an anonymous person gives you a document the first thing you do is verify it to learn if it's real or if someone is trolling you.

Maybe all new sources get created with "pending" true, and the first time they submit something "pending" gets changed to false. The source list only shows sources that aren't pending.

After giving some thought and (briefly) talking with @garrettr, I think it makes sense to do this:

Each source should have an "active" flag that starts out as false and becomes true the first time they submit a message or document. Only "active" sources should show up in the list to journalists. This will prevent total spam sources from cluttering up the interface.

Maybe there's a better word than active to use.

Verified?

Verified could work, but it has a different meaning to journalists. When an anonymous person gives you a document the first thing you do is verify it to learn if it's real or if someone is trolling you.

Maybe all new sources get created with "pending" true, and the first time they submit something "pending" gets changed to false. The source list only shows sources that aren't pending.


Resolving patch:
diff --git a/securedrop/db.py b/securedrop/db.py
--- a/securedrop/db.py
+++ b/securedrop/db.py
@@ -41,6 +41,9 @@ class Source(Base):
     journalist_designation = Column(String(255), nullable=False)
     flagged = Column(Boolean, default=False)
     last_updated = Column(DateTime, default=datetime.datetime.now)
+    
+    # sources are "pending" and don't get displayed to journalists until they submit something
+    pending = Column(Boolean, default=True)
 
     def __init__(self, filesystem_id=None, journalist_designation=None):
         self.filesystem_id = filesystem_id
diff --git a/securedrop/journalist.py b/securedrop/journalist.py
--- a/securedrop/journalist.py
+++ b/securedrop/journalist.py
@@ -79,7 +79,7 @@ def get_docs(sid):
 
 @app.route('/')
 def index():
-    sources = Source.query.order_by(Source.last_updated.desc()).all()
+    sources = Source.query.filter_by(pending=False).order_by(Source.last_updated.desc()).all()
     return render_template('index.html', sources=sources)
 
 
diff --git a/securedrop/source.py b/securedrop/source.py
--- a/securedrop/source.py
+++ b/securedrop/source.py
@@ -205,6 +205,7 @@ def submit():
         submission = Submission(g.source, fname)
         db_session.add(submission)
 
+    g.source.pending = False
     g.source.last_updated = datetime.now()
     db_session.commit()
     normalize_timestamps(g.sid)


Test patch:
diff --git a/securedrop/tests/unit_tests.py b/securedrop/tests/unit_tests.py
--- a/securedrop/tests/unit_tests.py
+++ b/securedrop/tests/unit_tests.py
@@ -604,6 +604,10 @@ def test_delete_collection(self):
         # first, add a source
         self.source_app.get('/generate')
         self.source_app.post('/create')
+        self.source_app.post('/submit', data=dict(
+            msg="This is a test.",
+            fh=(StringIO(''), ''),
+        ), follow_redirects=True)
 
         rv = self.journalist_app.get('/')
         # navigate to the collection page
@@ -636,6 +640,10 @@ def test_delete_collections(self):
         for i in range(num_sources):
             self.source_app.get('/generate')
             self.source_app.post('/create')
+            self.source_app.post('/submit', data=dict(
+                msg="This is a test "+str(i)+".",
+                fh=(StringIO(''), ''),
+            ), follow_redirects=True)
             _logout(self.source_app)
 
         rv = self.journalist_app.get('/')