Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

data migration for journalist association fix in draftreplies table #1184

Merged
merged 2 commits into from
Nov 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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("""
Expand All @@ -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():
"""
Expand Down
77 changes: 42 additions & 35 deletions tests/files/test-key.gpg.asc
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,46 @@ 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
I064z5UlBt8g
=N54R
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
Ue5DzA==
=ymks
-----END PGP PRIVATE KEY BLOCK-----
50 changes: 28 additions & 22 deletions tests/files/test-key.gpg.pub.asc
Original file line number Diff line number Diff line change
Expand Up @@ -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-----
26 changes: 21 additions & 5 deletions tests/migrations/test_a4bf1f58ce69.py
Original file line number Diff line number Diff line change
Expand Up @@ -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("=^..^=..^=..^=")

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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()


Expand Down
47 changes: 46 additions & 1 deletion tests/migrations/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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("ᕕ( ᐛ )ᕗ")

Expand Down Expand Up @@ -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)