# Buggy code
def create_source_and_submissions(num_submissions=2, num_replies=2):
    # Store source in database
    codename = current_app.crypto_util.genrandomid()
    filesystem_id = current_app.crypto_util.hash_codename(codename)
    journalist_designation = current_app.crypto_util.display_id()
    source = Source(filesystem_id, journalist_designation)
    source.pending = False
    db.session.add(source)
    db.session.commit()

    # Generate submissions directory and generate source key
    os.mkdir(current_app.storage.path(source.filesystem_id))
    current_app.crypto_util.genkeypair(source.filesystem_id, codename)

    # Generate some test submissions
    for _ in range(num_submissions):
        source.interaction_count += 1
        fpath = current_app.storage.save_message_submission(
            source.filesystem_id,
            source.interaction_count,
            source.journalist_filename,
            next(submissions),
        )
        source.last_updated = datetime.datetime.utcnow()
        submission = Submission(source, fpath)
        db.session.add(submission)

    # Generate some test replies
    for _ in range(num_replies):
        source.interaction_count += 1
        fname = "{}-{}-reply.gpg".format(
            source.interaction_count, source.journalist_filename
        )
        current_app.crypto_util.encrypt(
            next(replies),
            [
                current_app.crypto_util.getkey(source.filesystem_id),
                config.JOURNALIST_KEY,
            ],
            current_app.storage.path(source.filesystem_id, fname),
        )

        journalist = Journalist.query.first()
        reply = Reply(journalist, source, fname)
        db.session.add(reply)

    db.session.commit()

    print(
        "Test source (codename: '{}', journalist designation '{}') "
        "added with {} submissions and {} replies".format(
            codename, journalist_designation, num_submissions, num_replies
        )
    )


# Traceback (AttributeError)
172.17.0.1 - - [31/Mar/2020 20:57:10] "GET /api/v1/replies HTTP/1.1" 500 -
Traceback (most recent call last):
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/opt/venvs/securedrop-app-code/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/redshiftzero/Documents/Github/securedrop-1.2.0-rc2/securedrop/securedrop/journalist_app/api.py", line 48, in decorated_function
return f(*args, **kwargs)
File "/Users/redshiftzero/Documents/Github/securedrop-1.2.0-rc2/securedrop/securedrop/journalist_app/api.py", line 310, in get_all_replies
{'replies': [reply.to_json() for reply in replies]}), 200
File "/Users/redshiftzero/Documents/Github/securedrop-1.2.0-rc2/securedrop/securedrop/journalist_app/api.py", line 310, in <listcomp>
{'replies': [reply.to_json() for reply in replies]}), 200
File "/Users/redshiftzero/Documents/Github/securedrop-1.2.0-rc2/securedrop/securedrop/models.py", line 289, in to_json
'journalist_username': self.journalist.username,
AttributeError: 'NoneType' object has no attribute 'username'

# Fixed code
def create_source_and_submissions(
    num_submissions=2, num_replies=2, journalist_who_replied=None
):
    # Store source in database
    codename = current_app.crypto_util.genrandomid()
    filesystem_id = current_app.crypto_util.hash_codename(codename)
    journalist_designation = current_app.crypto_util.display_id()
    source = Source(filesystem_id, journalist_designation)
    source.pending = False
    db.session.add(source)
    db.session.commit()

    # Generate submissions directory and generate source key
    os.mkdir(current_app.storage.path(source.filesystem_id))
    current_app.crypto_util.genkeypair(source.filesystem_id, codename)

    # Generate some test submissions
    for _ in range(num_submissions):
        source.interaction_count += 1
        fpath = current_app.storage.save_message_submission(
            source.filesystem_id,
            source.interaction_count,
            source.journalist_filename,
            next(submissions),
        )
        source.last_updated = datetime.datetime.utcnow()
        submission = Submission(source, fpath)
        db.session.add(submission)

    # Generate some test replies
    for _ in range(num_replies):
        source.interaction_count += 1
        fname = "{}-{}-reply.gpg".format(
            source.interaction_count, source.journalist_filename
        )
        current_app.crypto_util.encrypt(
            next(replies),
            [
                current_app.crypto_util.getkey(source.filesystem_id),
                config.JOURNALIST_KEY,
            ],
            current_app.storage.path(source.filesystem_id, fname),
        )

        if not journalist_who_replied:
            journalist = Journalist.query.first()
        else:
            journalist = journalist_who_replied
        reply = Reply(journalist, source, fname)
        db.session.add(reply)

    db.session.commit()

    print(
        "Test source (codename: '{}', journalist designation '{}') "
        "added with {} submissions and {} replies".format(
            codename, journalist_designation, num_submissions, num_replies
        )
    )