diff --git a/alembic/versions/a4bf1f58ce69_fix_journalist_association_in_replies.py b/alembic/versions/a4bf1f58ce69_fix_journalist_association_in_replies.py index ff2a2260a..782b2f0ef 100644 --- a/alembic/versions/a4bf1f58ce69_fix_journalist_association_in_replies.py +++ b/alembic/versions/a4bf1f58ce69_fix_journalist_association_in_replies.py @@ -18,7 +18,7 @@ def upgrade(): """ Fix reply association with journalist by updating journalist uuid to journalist id in the - journalist_id column. + journalist_id column for the replies and draftreplies tables. """ conn = op.get_bind() cursor = conn.execute(""" @@ -28,25 +28,47 @@ def upgrade(): """) replies_with_incorrect_associations = cursor.fetchall() - if not replies_with_incorrect_associations: - return - - conn.execute(""" - UPDATE replies - SET journalist_id= - ( - SELECT users.id - FROM users - WHERE journalist_id=users.uuid - ) - WHERE exists - ( - SELECT users.id - FROM users - WHERE journalist_id=users.uuid - ); + if replies_with_incorrect_associations: + conn.execute(""" + UPDATE replies + SET journalist_id= + ( + SELECT users.id + FROM users + WHERE journalist_id=users.uuid + ) + WHERE exists + ( + SELECT users.id + FROM users + WHERE journalist_id=users.uuid + ); + """) + + cursor = conn.execute(""" + SELECT journalist_id + FROM draftreplies, users + WHERE journalist_id=users.uuid; """) + draftreplies_with_incorrect_associations = cursor.fetchall() + if draftreplies_with_incorrect_associations: + conn.execute(""" + UPDATE draftreplies + SET journalist_id= + ( + SELECT users.id + FROM users + WHERE journalist_id=users.uuid + ) + WHERE exists + ( + SELECT users.id + FROM users + WHERE journalist_id=users.uuid + ); + """) + def downgrade(): """ diff --git a/tests/files/test-key.gpg.asc b/tests/files/test-key.gpg.asc index 0f8acc937..a79b1cd32 100644 --- a/tests/files/test-key.gpg.asc +++ b/tests/files/test-key.gpg.asc @@ -20,39 +20,46 @@ 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 -I064z5UlBt8g -=N54R +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 +Ue5DzA== +=ymks -----END PGP PRIVATE KEY BLOCK----- diff --git a/tests/files/test-key.gpg.pub.asc b/tests/files/test-key.gpg.pub.asc index 593ce6936..2be9a324f 100644 --- a/tests/files/test-key.gpg.pub.asc +++ b/tests/files/test-key.gpg.pub.asc @@ -6,26 +6,32 @@ zg/RWEC1cQnAJvRik1SSd7CBaw2B7TcMRPng1ZjFiQX4Fmi1QbPEXifqveWOoibS BTSUf4OCKQSWKIUzScCgHWWImRdXyo2IbUGCQBWrDxH5Pjpnvd0eioWYcdyCJlL0 tDgNYYbsKee23gDV2vQmOhxbduPv4mw1/bDKe+/YLR/BYDLYwQXj4E2tJuYN7uuw OdC8i/EOvzK80YlGofefRhM9wqiz1o4z8hndABEBAAG0K3NlY3VyZWRyb3BjbGll -bnQtdGVzdCA8dGVzdEBzZWN1cmVkcm9wLm9yZz6JAVQEEwEIAD4WIQSy/3+yju2M -q+vF+2xhedl7z6UuXwUCW9l3zgIbAwUJA8JnAAULCQgHAgYVCAkKCwIEFgIDAQIe -AQIXgAAKCRBhedl7z6UuX83JCACEckPXbTiLt6hQM7Uq1u8FMWH3mJGWNj+YBC0D -mqqlzoqH4lgX6D4hJc4+NFykOwkhkcECbdAM3WPA45AVC/KOKJKG4Z0krhiW2nsl -2bUYVsSPG9YnwV/Uzp//Rx90M8t383utR6RGHHxmVeHtgNQQn+KXOH/I0UfcHO/C -HjHLgMzmbKXdJ9DFJLSd5Lq+4dBnkZbvL1/OqZhea1b8L5xuS0dQMkHE61wVgfcJ -frhfP8o9mWoBBxSzRfdF+pgxxtomWJI92o+EAO3sYsrGjqf0OWnoZyK0jXIjI6/6 -Zho+aTDkiNZJgQRnaochlEofjtaZNthuIDFiSTslfZtJweHouQENBFvZd84BCADk -4KNDS/4biyCGIeSM5UO3/1XRpXKi/qZC5rQrrqAafEBQQ/hneGtQ1f0nJndhLybx -9YkNSZxqsMqE90dbRmjyIOnyYrSGOa6AxGEmOPcLT+x6WSbQCQRiX3PDfVtPv7BQ -Dpj9w106DI8sLhHkpVJxsY8OCnR5B6BCZyYsrhXDpNJdjsnwkOztxOPnByVMduU3 -25f6FibnYx0GEr75UJclp73zb1dY41UQNC7MCqnrvt08ahKc/KZibvflsuLR5xnu -wjN5NRDp81hZomJUuRM2a5STdhgHI6a6D2Vhc2DjtB0FYLQQA2DsuDlf6eb7icx4 -4Oq+ZwZkEs8tLtWeOT4PABEBAAGJATwEGAEIACYWIQSy/3+yju2Mq+vF+2xhedl7 -z6UuXwUCW9l3zgIbDAUJA8JnAAAKCRBhedl7z6UuX3fHB/4xFq30ekVnyNkWwWBJ -m2ydurWp/HKIJJpXcAs9V6S6AEtu7Z+8nsEi9LYeppShyqCyM/+iUbvHl0BkbjV+ -WLMKqkERumGKL6q9UEZ+BtaCURS56vugK4DoeptNuz/X0qZ1PVyOwKxwsOjxoF5y -uhC+DTsEwmLdsrUwP9jAL23RmGHjpCIv7wlPCBGF3r3m/9fQnnMDxrIYzyXcxBNR -WQvpYAp0MxawK6qeSrdUbRVhgyBMfb9PXhXTQxSA6c4ykJI0fHbF13wuYg0fZbPX -ec4uAaZZCRWux9RGEQk8BJnn/Jno8GD58AaZaKgt9FdnIcDB2Zq6Y3QcI064z5Ul -Bt8g -=KNtK +bnQtdGVzdCA8dGVzdEBzZWN1cmVkcm9wLm9yZz6JAU4EEwEIADgCGwMFCwkIBwIG +FQgJCgsCBBYCAwECHgECF4AWIQSy/3+yju2Mq+vF+2xhedl7z6UuXwUCX6COmAAK +CRBhedl7z6UuXxYqCACOCqSRIFNl0XwVmI3bSLbcMczmWCnIFcn3aTdFbVMmGwO1 +5Z6V0NQuWwQlaVNZu2o96bo8u7qDcg4uPDcyz90J51zsYRTnoKfTZ7o23dQGTVFI +5IEgzssOeOmrdNJHKVoVu0sTuakRzbDU0yCT4crSCbyMspKtGiPu1HIAAHwS1tO8 +Hgeo0FbwEgZskOXoQpNHT95g8/MadQqGjSiRiwwY0ycC1lVmH0b/9xMxeBX1XC0o +Lmc4b4hbZwU0S1lu2RCJaLF3LOmW7OYbsE+hbIqjEvmROgQqP/Rzbx59xibOpHGu +W+83vKjf3pvmOFjNA5o6qR398BnlZSpAe3NR8izsiQFUBBMBCAA+FiEEsv9/so7t +jKvrxftsYXnZe8+lLl8FAlvZd84CGwMFCQPCZwAFCwkIBwIGFQgJCgsCBBYCAwEC +HgECF4AACgkQYXnZe8+lLl/NyQgAhHJD1204i7eoUDO1KtbvBTFh95iRljY/mAQt +A5qqpc6Kh+JYF+g+ISXOPjRcpDsJIZHBAm3QDN1jwOOQFQvyjiiShuGdJK4Yltp7 +Jdm1GFbEjxvWJ8Ff1M6f/0cfdDPLd/N7rUekRhx8ZlXh7YDUEJ/ilzh/yNFH3Bzv +wh4xy4DM5myl3SfQxSS0neS6vuHQZ5GW7y9fzqmYXmtW/C+cbktHUDJBxOtcFYH3 +CX64Xz/KPZlqAQcUs0X3RfqYMcbaJliSPdqPhADt7GLKxo6n9Dlp6GcitI1yIyOv ++mYaPmkw5IjWSYEEZ2qHIZRKH47WmTbYbiAxYkk7JX2bScHh6LkBDQRb2XfOAQgA +5OCjQ0v+G4sghiHkjOVDt/9V0aVyov6mQua0K66gGnxAUEP4Z3hrUNX9JyZ3YS8m +8fWJDUmcarDKhPdHW0Zo8iDp8mK0hjmugMRhJjj3C0/selkm0AkEYl9zw31bT7+w +UA6Y/cNdOgyPLC4R5KVScbGPDgp0eQegQmcmLK4Vw6TSXY7J8JDs7cTj5wclTHbl +N9uX+hYm52MdBhK++VCXJae9829XWONVEDQuzAqp677dPGoSnPymYm735bLi0ecZ +7sIzeTUQ6fNYWaJiVLkTNmuUk3YYByOmug9lYXNg47QdBWC0EANg7Lg5X+nm+4nM +eODqvmcGZBLPLS7Vnjk+DwARAQABiQE2BBgBCAAgAhsMFiEEsv9/so7tjKvrxfts +YXnZe8+lLl8FAl+gj0MACgkQYXnZe8+lLl+voAf/YgujaIXnhmVq28sRD7NG800w +fell5dT6URrUBlV7+JDqHipg2W7QvNyabws6qsmJ3s5WD9BiVs3E2SB25nMdrm2m +fWRXtVRHtjX0uyZIR6IHB+JKhRMuj49kmZlgSMAQOORs8xS6hf68mkUyN3LJIo/R +WBfZG3uFRjrRLsnh2zp5tQzxxnZ8/jNVstOheAGtR9CmVmTSBq21Z3kUU8AQ1rfL +YhA+o3fMr34547ZfnIAt35M8HlvN4ZbO8Q0kgtN1HWaRn/CMnKzP/rHFJsaQlqFH +l5Stl0kKZ7ykJs31sfxdH6v9ihjsvM8vCVLlAAm2PatBx9OvK4tSePhZUe5DzA== +=op/g -----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/migrations/test_a4bf1f58ce69.py b/tests/migrations/test_a4bf1f58ce69.py index e40ede0e5..84c60d09a 100644 --- a/tests/migrations/test_a4bf1f58ce69.py +++ b/tests/migrations/test_a4bf1f58ce69.py @@ -5,9 +5,9 @@ import subprocess from securedrop_client import db -from securedrop_client.db import Reply, User +from securedrop_client.db import DraftReply, Reply, User -from .utils import add_reply, add_source, add_user +from .utils import add_draft_reply, add_reply, add_source, add_user random.seed("=^..^=..^=..^=") @@ -28,7 +28,8 @@ def __init__(self, homedir): def load_data(self): """ - Load data that has the bug where user.uuid is stored in replies.journalist_id. + Load data that has the bug where user.uuid is stored in replies.journalist_id and + draftreplies.journalist_id. """ for _ in range(self.NUM_SOURCES): add_source(self.session) @@ -57,12 +58,20 @@ def load_data(self): source_id = random.randint(1, self.NUM_SOURCES) add_reply(self.session, journalist.uuid, source_id) + # Add draft replies from randomly-selected journalists to a randomly-selected sources + for _ in range(1, self.NUM_REPLIES): + journalist_id = random.randint(1, self.NUM_USERS) + journalist = self.session.query(User).filter_by(id=journalist_id).one() + source_id = random.randint(1, self.NUM_SOURCES) + add_draft_reply(self.session, journalist.uuid, source_id) + self.session.commit() def check_upgrade(self): """ - Make sure each reply in the replies table has the correct journalist_id stored for the - associated journalist by making sure a User account exists with that journalist id. + Make sure each reply in the replies and draftreplies tables have the correct journalist_id + stored for the associated journalist by making sure a User account exists with that + journalist id. """ replies = self.session.query(Reply).all() assert len(replies) @@ -71,6 +80,13 @@ def check_upgrade(self): # Will fail if User does not exist self.session.query(User).filter_by(id=reply.journalist_id).one() + draftreplies = self.session.query(DraftReply).all() + assert len(draftreplies) + + for draftreply in draftreplies: + # Will fail if User does not exist + self.session.query(User).filter_by(id=draftreply.journalist_id).one() + self.session.close() diff --git a/tests/migrations/utils.py b/tests/migrations/utils.py index 3cabf86fe..650918a36 100644 --- a/tests/migrations/utils.py +++ b/tests/migrations/utils.py @@ -8,7 +8,7 @@ from sqlalchemy import text from sqlalchemy.orm.session import Session -from securedrop_client.db import DownloadError, Source +from securedrop_client.db import DownloadError, ReplySendStatus, Source random.seed("ᕕ( ᐛ )ᕗ") @@ -152,3 +152,48 @@ def add_reply(session: Session, journalist_id: int, source_id: int) -> None: ) """ session.execute(text(sql), params) + + +def add_draft_reply(session: Session, journalist_id: int, source_id: int) -> None: + reply_send_statuses = session.query(ReplySendStatus).all() + reply_send_status_ids = [reply_send_status.id for reply_send_status in reply_send_statuses] + + content = random_chars(1000) + + source = session.query(Source).filter_by(id=source_id).one() + + file_counter = len(source.collection) + 1 + + params = { + "uuid": str(uuid4()), + "journalist_id": journalist_id, + "source_id": source_id, + "file_counter": file_counter, + "content": content, + "send_status_id": random.choice(reply_send_status_ids), + "timestamp": random_datetime(), + } + + sql = """ + INSERT INTO draftreplies + ( + uuid, + journalist_id, + source_id, + file_counter, + content, + send_status_id, + timestamp + ) + VALUES + ( + :uuid, + :journalist_id, + :source_id, + :file_counter, + :content, + :send_status_id, + :timestamp + ) + """ + session.execute(text(sql), params)