Skip to content

Commit

Permalink
Fixes #5176 Adds code+test to return replies without a journalist
Browse files Browse the repository at this point in the history
We can safely return a reply by a journalist who is deleted from
the system. This patch also includes a test case, and dev-data
generation script also now adds a reply and then deletes the
journalist.
  • Loading branch information
kushaldas committed Apr 1, 2020
1 parent 3770689 commit 98935f5
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 9 deletions.
34 changes: 29 additions & 5 deletions securedrop/create-dev-data.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,50 @@ def main(staging=False):
test_otp_secret,
is_admin=False)

journalist_tobe_deleted = add_test_user("clarkkent",
test_password,
test_otp_secret,
is_admin=False,
first_name="Clark",
last_name="Kent")


# Add test sources and submissions
num_sources = int(os.getenv('NUM_SOURCES', 2))
for _ in range(num_sources):
for i in range(num_sources):
if i == 0:
# For the first source, the journalist who replied will be deleted
create_source_and_submissions(journalist_who_replied=journalist_tobe_deleted)
continue
create_source_and_submissions()

# Now let us delete one journalist
db.session.delete(journalist_tobe_deleted)
db.session.commit()


def add_test_user(username, password, otp_secret, is_admin=False):
def add_test_user(username, password, otp_secret, is_admin=False,
first_name="", last_name=""):
try:
user = Journalist(username=username,
password=password,
is_admin=is_admin)
is_admin=is_admin,
first_name=first_name,
last_name=last_name)
user.otp_secret = otp_secret
db.session.add(user)
db.session.commit()
print('Test user successfully added: '
'username={}, password={}, otp_secret={}, is_admin={}'
''.format(username, password, otp_secret, is_admin))
return user
except IntegrityError:
print("Test user already added")
db.session.rollback()


def create_source_and_submissions(num_submissions=2, num_replies=2):
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)
Expand Down Expand Up @@ -109,7 +130,10 @@ def create_source_and_submissions(num_submissions=2, num_replies=2):
config.JOURNALIST_KEY],
current_app.storage.path(source.filesystem_id, fname))

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

Expand Down
17 changes: 13 additions & 4 deletions securedrop/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,15 @@ def __repr__(self):

def to_json(self):
# type: () -> Dict[str, Union[str, int, bool]]
username = ""
first_name = ""
last_name = ""
uuid = ""
if self.journalist:
username = self.journalist.username
first_name = self.journalist.first_name
last_name = self.journalist.last_name
uuid = self.journalist.uuid
json_submission = {
'source_url': url_for('api.single_source',
source_uuid=self.source.uuid),
Expand All @@ -286,10 +295,10 @@ def to_json(self):
reply_uuid=self.uuid),
'filename': self.filename,
'size': self.size,
'journalist_username': self.journalist.username,
'journalist_first_name': self.journalist.first_name,
'journalist_last_name': self.journalist.last_name,
'journalist_uuid': self.journalist.uuid,
'journalist_username': username,
'journalist_first_name': first_name,
'journalist_last_name': last_name,
'journalist_uuid': uuid,
'uuid': self.uuid,
'is_deleted_by_source': self.deleted_by_source,
}
Expand Down
18 changes: 18 additions & 0 deletions securedrop/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,24 @@ def test_files(journalist_app, test_journo):
'replies': source.replies}


@pytest.fixture(scope='function')
def test_files_deleted_journalist(journalist_app, test_journo):
with journalist_app.app_context():
source, codename = utils.db_helper.init_source()
utils.db_helper.submit(source, 2)
test_journo['journalist']
juser, _ = utils.db_helper.init_journalist("f", "l", is_admin=False)
utils.db_helper.reply(juser, source, 1)
utils.db_helper.delete_journalist(juser)
return {'source': source,
'codename': codename,
'filesystem_id': source.filesystem_id,
'uuid': source.uuid,
'submissions': source.submissions,
'replies': source.replies}



@pytest.fixture(scope='function')
def journalist_api_token(journalist_app, test_journo):
with journalist_app.test_client() as app:
Expand Down
27 changes: 27 additions & 0 deletions securedrop/tests/test_journalist_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,33 @@ def test_authorized_user_can_get_single_reply(journalist_app, test_files,
test_files['source'].replies[0].size


def test_reply_of_deleted_journalist(journalist_app,
test_files_deleted_journalist,
journalist_api_token):
with journalist_app.test_client() as app:
reply_uuid = test_files_deleted_journalist['source'].replies[0].uuid
uuid = test_files_deleted_journalist['source'].uuid
response = app.get(url_for('api.single_reply',
source_uuid=uuid,
reply_uuid=reply_uuid),
headers=get_api_headers(journalist_api_token))

assert response.status_code == 200

reply = Reply.query.filter(Reply.uuid == reply_uuid).one()

assert response.json['uuid'] == reply_uuid
assert response.json['journalist_username'] == ""
assert response.json['journalist_uuid'] == ""
assert response.json['journalist_first_name'] == ""
assert response.json['journalist_last_name'] == ""
assert response.json['is_deleted_by_source'] is False
assert response.json['filename'] == \
test_files_deleted_journalist['source'].replies[0].filename
assert response.json['size'] == \
test_files_deleted_journalist['source'].replies[0].size


def test_authorized_user_can_delete_single_submission(journalist_app,
test_submissions,
journalist_api_token):
Expand Down
11 changes: 11 additions & 0 deletions securedrop/tests/utils/db_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ def init_journalist(first_name=None, last_name=None, is_admin=False):
return user, user_pw


def delete_journalist(journalist):
"""Deletes a journalist from the database.
:param models.Journalist journalist: The journalist to delete
:returns: None
"""
db.session.delete(journalist)
db.session.commit()


def reply(journalist, source, num_replies):
"""Generates and submits *num_replies* replies to *source*
from *journalist*. Returns reply objects as a list.
Expand Down

0 comments on commit 98935f5

Please sign in to comment.