prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Display number of docs and messages per source in source list
  > At the moment each source in the list displays: source codename, last updated. It would be helpful to also see: total # of messages/docs.
  
  Extracted from #322
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `securedrop/db.py`
  Content:
  ```
  1 import os
  2 import datetime
  3 
  4 from sqlalchemy import create_engine, ForeignKey
  5 from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref
  6 from sqlalchemy.ext.declarative import declarative_base
  7 from sqlalchemy import Column, Integer, String, Boolean, DateTime
  8 from sqlalchemy.orm.exc import NoResultFound
  9 
  10 import config
  11 import crypto_util
  12 import store
  13 
  14 # http://flask.pocoo.org/docs/patterns/sqlalchemy/
  15 
  16 if config.DATABASE_ENGINE == "sqlite":
  17     engine = create_engine(
  18         config.DATABASE_ENGINE + ":///" +
  19         config.DATABASE_FILE
  20     )
  21 else:
  22     engine = create_engine(
  23         config.DATABASE_ENGINE + '://' +
  24         config.DATABASE_USERNAME + ':' +
  25         config.DATABASE_PASSWORD + '@' +
  26         config.DATABASE_HOST + '/' +
  27         config.DATABASE_NAME, echo=False
  28     )
  29 
  30 db_session = scoped_session(sessionmaker(autocommit=False,
  31                                          autoflush=False,
  32                                          bind=engine))
  33 Base = declarative_base()
  34 Base.query = db_session.query_property()
  35 
  36 
  37 class Source(Base):
  38     __tablename__ = 'sources'
  39     id = Column(Integer, primary_key=True)
  40     filesystem_id = Column(String(96), unique=True)
  41     journalist_designation = Column(String(255), nullable=False)
  42     flagged = Column(Boolean, default=False)
  43     last_updated = Column(DateTime, default=datetime.datetime.now)
  44     
  45     # sources are "pending" and don't get displayed to journalists until they submit something
  46     pending = Column(Boolean, default=True)
  47 
  48     # keep track of how many interactions have happened, for filenames
  49     interaction_count = Column(Integer, default=0, nullable=False)
  50 
  51     def __init__(self, filesystem_id=None, journalist_designation=None):
  52         self.filesystem_id = filesystem_id
  53         self.journalist_designation = journalist_designation
  54 
  55     def __repr__(self):
  56         return '<Source %r>' % (self.journalist_designation)
  57 
  58     def journalist_filename(self):
  59         valid_chars = 'abcdefghijklmnopqrstuvwxyz1234567890-_'
  60         return ''.join([c for c in self.journalist_designation.lower().replace(' ', '_') if c in valid_chars])
  61 
  62 class Submission(Base):
  63     __tablename__ = 'submissions'
  64     id = Column(Integer, primary_key=True)
  65     source_id = Column(Integer, ForeignKey('sources.id'))
  66     source = relationship("Source", backref=backref('submissions', order_by=id))
  67     filename = Column(String(255), nullable=False)
  68     size = Column(Integer, nullable=False)
  69 
  70     def __init__(self, source, filename):
  71         self.source_id = source.id
  72         self.filename = filename
  73         self.size = os.stat(store.path(source.filesystem_id, filename)).st_size
  74 
  75     def __repr__(self):
  76         return '<Submission %r>' % (self.filename)
  77 
  78 
  79 # Declare (or import) models before init_db
  80 def init_db():
  81     Base.metadata.create_all(bind=engine)
  82 
  83
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/securedrop/db.py b/securedrop/db.py
  --- a/securedrop/db.py
  +++ b/securedrop/db.py
  @@ -59,6 +59,19 @@
           valid_chars = 'abcdefghijklmnopqrstuvwxyz1234567890-_'
           return ''.join([c for c in self.journalist_designation.lower().replace(' ', '_') if c in valid_chars])
   
  +    def documents_messages_count(self):
  +        try:
  +            return self.docs_msgs_count
  +        except AttributeError:
  +            self.docs_msgs_count = {'messages': 0, 'documents': 0}
  +            for submission in self.submissions:
  +                if submission.filename.endswith('msg.gpg'):
  +                    self.docs_msgs_count['messages'] += 1
  +                elif submission.filename.endswith('doc.zip.gpg'):
  +                    self.docs_msgs_count['documents'] += 1
  +            return self.docs_msgs_count
  +
  +
   class Submission(Base):
       __tablename__ = 'submissions'
       id = Column(Integer, primary_key=True)
  
verification_info: {"golden_diff": "diff --git a/securedrop/db.py b/securedrop/db.py\n--- a/securedrop/db.py\n+++ b/securedrop/db.py\n@@ -59,6 +59,19 @@\n         valid_chars = 'abcdefghijklmnopqrstuvwxyz1234567890-_'\n         return ''.join([c for c in self.journalist_designation.lower().replace(' ', '_') if c in valid_chars])\n \n+    def documents_messages_count(self):\n+        try:\n+            return self.docs_msgs_count\n+        except AttributeError:\n+            self.docs_msgs_count = {'messages': 0, 'documents': 0}\n+            for submission in self.submissions:\n+                if submission.filename.endswith('msg.gpg'):\n+                    self.docs_msgs_count['messages'] += 1\n+                elif submission.filename.endswith('doc.zip.gpg'):\n+                    self.docs_msgs_count['documents'] += 1\n+            return self.docs_msgs_count\n+\n+\n class Submission(Base):\n     __tablename__ = 'submissions'\n     id = Column(Integer, primary_key=True)\n", "issue": "Display number of docs and messages per source in source list\n> At the moment each source in the list displays: source codename, last updated. It would be helpful to also see: total # of messages/docs.\n\nExtracted from #322\n\n", "before_files": [{"content": "import os\nimport datetime\n\nfrom sqlalchemy import create_engine, ForeignKey\nfrom sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy import Column, Integer, String, Boolean, DateTime\nfrom sqlalchemy.orm.exc import NoResultFound\n\nimport config\nimport crypto_util\nimport store\n\n# http://flask.pocoo.org/docs/patterns/sqlalchemy/\n\nif config.DATABASE_ENGINE == \"sqlite\":\n    engine = create_engine(\n        config.DATABASE_ENGINE + \":///\" +\n        config.DATABASE_FILE\n    )\nelse:\n    engine = create_engine(\n        config.DATABASE_ENGINE + '://' +\n        config.DATABASE_USERNAME + ':' +\n        config.DATABASE_PASSWORD + '@' +\n        config.DATABASE_HOST + '/' +\n        config.DATABASE_NAME, echo=False\n    )\n\ndb_session = scoped_session(sessionmaker(autocommit=False,\n                                         autoflush=False,\n                                         bind=engine))\nBase = declarative_base()\nBase.query = db_session.query_property()\n\n\nclass Source(Base):\n    __tablename__ = 'sources'\n    id = Column(Integer, primary_key=True)\n    filesystem_id = Column(String(96), unique=True)\n    journalist_designation = Column(String(255), nullable=False)\n    flagged = Column(Boolean, default=False)\n    last_updated = Column(DateTime, default=datetime.datetime.now)\n    \n    # sources are \"pending\" and don't get displayed to journalists until they submit something\n    pending = Column(Boolean, default=True)\n\n    # keep track of how many interactions have happened, for filenames\n    interaction_count = Column(Integer, default=0, nullable=False)\n\n    def __init__(self, filesystem_id=None, journalist_designation=None):\n        self.filesystem_id = filesystem_id\n        self.journalist_designation = journalist_designation\n\n    def __repr__(self):\n        return '<Source %r>' % (self.journalist_designation)\n\n    def journalist_filename(self):\n        valid_chars = 'abcdefghijklmnopqrstuvwxyz1234567890-_'\n        return ''.join([c for c in self.journalist_designation.lower().replace(' ', '_') if c in valid_chars])\n\nclass Submission(Base):\n    __tablename__ = 'submissions'\n    id = Column(Integer, primary_key=True)\n    source_id = Column(Integer, ForeignKey('sources.id'))\n    source = relationship(\"Source\", backref=backref('submissions', order_by=id))\n    filename = Column(String(255), nullable=False)\n    size = Column(Integer, nullable=False)\n\n    def __init__(self, source, filename):\n        self.source_id = source.id\n        self.filename = filename\n        self.size = os.stat(store.path(source.filesystem_id, filename)).st_size\n\n    def __repr__(self):\n        return '<Submission %r>' % (self.filename)\n\n\n# Declare (or import) models before init_db\ndef init_db():\n    Base.metadata.create_all(bind=engine)\n\n", "path": "securedrop/db.py"}], "after_files": [{"content": "import os\nimport datetime\n\nfrom sqlalchemy import create_engine, ForeignKey\nfrom sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy import Column, Integer, String, Boolean, DateTime\nfrom sqlalchemy.orm.exc import NoResultFound\n\nimport config\nimport crypto_util\nimport store\n\n# http://flask.pocoo.org/docs/patterns/sqlalchemy/\n\nif config.DATABASE_ENGINE == \"sqlite\":\n    engine = create_engine(\n        config.DATABASE_ENGINE + \":///\" +\n        config.DATABASE_FILE\n    )\nelse:\n    engine = create_engine(\n        config.DATABASE_ENGINE + '://' +\n        config.DATABASE_USERNAME + ':' +\n        config.DATABASE_PASSWORD + '@' +\n        config.DATABASE_HOST + '/' +\n        config.DATABASE_NAME, echo=False\n    )\n\ndb_session = scoped_session(sessionmaker(autocommit=False,\n                                         autoflush=False,\n                                         bind=engine))\nBase = declarative_base()\nBase.query = db_session.query_property()\n\n\nclass Source(Base):\n    __tablename__ = 'sources'\n    id = Column(Integer, primary_key=True)\n    filesystem_id = Column(String(96), unique=True)\n    journalist_designation = Column(String(255), nullable=False)\n    flagged = Column(Boolean, default=False)\n    last_updated = Column(DateTime, default=datetime.datetime.now)\n    \n    # sources are \"pending\" and don't get displayed to journalists until they submit something\n    pending = Column(Boolean, default=True)\n\n    # keep track of how many interactions have happened, for filenames\n    interaction_count = Column(Integer, default=0, nullable=False)\n\n    def __init__(self, filesystem_id=None, journalist_designation=None):\n        self.filesystem_id = filesystem_id\n        self.journalist_designation = journalist_designation\n\n    def __repr__(self):\n        return '<Source %r>' % (self.journalist_designation)\n\n    def journalist_filename(self):\n        valid_chars = 'abcdefghijklmnopqrstuvwxyz1234567890-_'\n        return ''.join([c for c in self.journalist_designation.lower().replace(' ', '_') if c in valid_chars])\n\n    def documents_messages_count(self):\n        try:\n            return self.docs_msgs_count\n        except AttributeError:\n            self.docs_msgs_count = {'messages': 0, 'documents': 0}\n            for submission in self.submissions:\n                if submission.filename.endswith('msg.gpg'):\n                    self.docs_msgs_count['messages'] += 1\n                elif submission.filename.endswith('doc.zip.gpg'):\n                    self.docs_msgs_count['documents'] += 1\n            return self.docs_msgs_count\n\n\nclass Submission(Base):\n    __tablename__ = 'submissions'\n    id = Column(Integer, primary_key=True)\n    source_id = Column(Integer, ForeignKey('sources.id'))\n    source = relationship(\"Source\", backref=backref('submissions', order_by=id))\n    filename = Column(String(255), nullable=False)\n    size = Column(Integer, nullable=False)\n\n    def __init__(self, source, filename):\n        self.source_id = source.id\n        self.filename = filename\n        self.size = os.stat(store.path(source.filesystem_id, filename)).st_size\n\n    def __repr__(self):\n        return '<Submission %r>' % (self.filename)\n\n\n# Declare (or import) models before init_db\ndef init_db():\n    Base.metadata.create_all(bind=engine)\n\n", "path": "securedrop/db.py"}]}