Skip to content
This repository was archived by the owner on Dec 8, 2022. It is now read-only.
Prev Previous commit
Next Next commit
update question import code
  • Loading branch information
usrbinsam committed Mar 17, 2021
commit b4fb824a94b6f3a708a36d25ed1c08c86cc5e58c
113 changes: 75 additions & 38 deletions CodeChallenge/cli/questions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from ..manage import add_question, del_question
from ..models import Question, db

bp = Blueprint("questioncl", __name__, cli_group="q")
bp = Blueprint("question_cli", __name__, cli_group="q")


@bp.cli.command("add")
Expand Down Expand Up @@ -44,11 +44,24 @@ def q_ls(tablefmt):
table = []

for q in Question.query.all(): # type: Question
table.append((q.id, q.title, q.answer, q.rank, f"{len(q.asset)} length blob", q.asset_ext))

click.echo(tabulate(table,
("id", "title", "answer", "rank", "asset", "asset_ext"),
tablefmt=tablefmt))
table.append(
(
q.id,
q.title,
q.answer,
q.rank,
f"{len(q.asset)} length blob",
q.asset_ext,
)
)

click.echo(
tabulate(
table,
("id", "title", "answer", "rank", "asset", "asset_ext"),
tablefmt=tablefmt,
)
)

if not table:
click.echo("no questions in table")
Expand Down Expand Up @@ -87,8 +100,10 @@ def q_replace(title, answer, rank, asset, hint1, hint2):
print(f"old question id was: {oldq.id}")
return
else:
print(f"warning: there was no question for rank {rank} but I added "
"that question anyway")
print(
f"warning: there was no question for rank {rank} but I added "
"that question anyway"
)

add_question(title, answer, rank, asset)

Expand All @@ -97,8 +112,11 @@ def q_replace(title, answer, rank, asset, hint1, hint2):
def q_sync():
"""Sync with a public Google Sheets Spreadsheet"""

click.confirm("Are you sure you want to sync with the current database? "
f"({db.engine.url.username}@{db.engine.url.host}/{db.engine.url.database})", abort=True)
click.confirm(
"Are you sure you want to sync with the current database? "
f"({db.engine.url.username}@{db.engine.url.host}/{db.engine.url.database})",
abort=True,
)

key = current_app.config.get("GOOGLE_API_KEY")
file_id = current_app.config.get("SHEET_ID")
Expand All @@ -111,7 +129,9 @@ def q_sync():
click.secho("missing SHEET_ID in config.py", fg="red")
return

r = requests.get(f'https://www.googleapis.com/drive/v3/files/{file_id}/export?mimeType=text%2Fcsv&key={key}')
r = requests.get(
f"https://www.googleapis.com/drive/v3/files/{file_id}/export?mimeType=text%2Fcsv&key={key}"
)

if not r.ok:
click.secho(f"sheet download failed (status code {r.status_code})", fg="red")
Expand All @@ -124,18 +144,25 @@ def q_sync():

with click.progressbar(rows, label="synchronizing with CSV data ...") as bar:
for i, row in enumerate(bar):
if not all((row["rank"], row["title"],
row["answer"], row["asset"])):
errors.append(f"invalid row {i} (missing rank/title/answer/asset)")
if not all(
(
row["#"],
row["Question"],
row["Answer Type"],
row["Answer Input"],
row["Answer"],
)
):
errors.append(f"invalid row {i} (required column missing) {row!r}")
continue

try:
rank = int(row["rank"])
rank = int(row["#"])
except ValueError:
errors.append(f"invalid integer value for 'rank' column on row {i}")
errors.append(f"invalid integer value for '#' column on row {i}")
continue

if not row["asset"].startswith("http"):
if "asset" in row and row["asset"].startswith("http"):
errors.append(f"invalid asset URL on row {i}")

q = Question.query.filter_by(rank=rank).first()
Expand All @@ -145,27 +172,37 @@ def q_sync():
q.rank = rank
db.session.add(q)

q.title = row["title"]
q.answer = row["answer"]
q.hint1 = row["hint1"]
q.hint2 = row["hint2"]

b = BytesIO()
r2 = requests.get(row["asset"], stream=True)
if not r2.ok:
errors.append(f"failed to download asset for row {i+1}: {row['asset']}")
continue

for chunk in r2.iter_content(1024):
b.write(chunk)

q.asset = b.getvalue()
content_type = r2.headers.get("content-type")
if "/" in content_type:
q.asset_ext = "." + content_type.split("/")[1]
else:
errors.append(f"unknown content type for asset on rank {rank}. 'asset_ext' column will need to be set "
f"manually in table. (Content-Type: {r2.headers['content-type']!r})")
assert row["Answer Type"] in ("strcmp", "regex")
assert row["Answer Input"] in ("input", "textarea")

q.title = row["Question"]
q.answer = row["Answer"]
q.hint1 = row["Hint 1"]
q.hint2 = row["Hint 2"]
q.match_type = 1 if row["Answer Type"] == "strcmp" else 2
q.input_type = 1 if row["Answer Input"] == "input" else 2

if "asset" in row:
b = BytesIO()
r2 = requests.get(row["asset"], stream=True)
if not r2.ok:
errors.append(
f"failed to download asset for row {i}: {row['asset']}"
)
continue

for chunk in r2.iter_content(1024):
b.write(chunk)

q.asset = b.getvalue()
content_type = r2.headers.get("content-type")
if "/" in content_type:
q.asset_ext = "." + content_type.split("/")[1]
else:
errors.append(
f"unknown content type for asset on rank {rank}. 'asset_ext' column will need to be set "
f"manually in table. (Content-Type: {r2.headers['content-type']!r})"
)

for message in errors:
click.secho(message, fg="red")
Expand Down