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

Practical fix for securedrop-client#1025 Faster sync for all source #5204

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions securedrop/journalist_app/api.py
Expand Up @@ -14,6 +14,7 @@
LoginThrottledException, InvalidUsernameException,
BadTokenException, WrongPasswordException)
from store import NotEncrypted
import smallapi


TOKEN_EXPIRATION_MINS = 60 * 8
Expand Down Expand Up @@ -135,9 +136,9 @@ def get_token():
@api.route('/sources', methods=['GET'])
@token_required
def get_all_sources():
sources = Source.query.filter_by(pending=False).all()
sources = smallapi.get_all_sources()
return jsonify(
{'sources': [source.to_json() for source in sources]}), 200
{'sources': sources}), 200

@api.route('/sources/<source_uuid>', methods=['GET', 'DELETE'])
@token_required
Expand Down
78 changes: 78 additions & 0 deletions securedrop/smallapi.py
@@ -0,0 +1,78 @@
from flask import url_for, current_app
import datetime
from collections import defaultdict
from db import db
from sqlalchemy import text


def get_all_sources():
sql = text("SELECT filename, source_id FROM submissions")
results = db.engine.execute(sql)

# A dictionary of all source_ids and their submission names in a list as value
submissions = defaultdict(list)
for res in results:
submissions[res["source_id"]].append(res["filename"])

sql = text("SELECT source_id, starred FROM source_stars")
results = db.engine.execute(sql)

stars = {res["source_id"]: res["starred"] for res in results}

sql = text(
"SELECT id, uuid, filesystem_id, journalist_designation, flagged,"
"last_updated, pending, interaction_count FROM sources"
)
sources = db.engine.execute(sql)

# this is the final result list
result = []
for source in sources:
source_id = source["id"]
if source["last_updated"]:
timestamp = source["last_updated"] + "Z"
else:
timestamp = datetime.datetime.utcnow().isoformat() + "Z"

starred = False
if source_id in stars:
starred = bool(stars[source_id])

messages = 0
documents = 0

subs = submissions.get(source_id, [])
for sub in subs:
if sub.endswith("msg.gpg"):
messages += 1
elif sub.endswith("doc.gz.gpg") or sub.endswith("doc.zip.gpg"):
documents += 1

json_source = {
"uuid": source["uuid"],
"url": url_for("api.single_source", source_uuid=source["uuid"]),
"journalist_designation": source["journalist_designation"],
"is_flagged": source["flagged"],
"is_starred": starred,
"last_updated": timestamp,
"interaction_count": source["interaction_count"],
"key": {
"type": "PGP",
"public": current_app.crypto_util.get_pubkey(source["filesystem_id"]),
"fingerprint": current_app.crypto_util.get_fingerprint(
source["filesystem_id"]
),
},
"number_of_documents": documents,
"number_of_messages": messages,
"submissions_url": url_for(
"api.all_source_submissions", source_uuid=source["uuid"]
),
"add_star_url": url_for("api.add_star", source_uuid=source["uuid"]),
"remove_star_url": url_for("api.remove_star", source_uuid=source["uuid"]),
"replies_url": url_for(
"api.all_source_replies", source_uuid=source["uuid"]
),
}
result.append(json_source)
return result