X-Git-Url: https://git.cworth.org/git?p=turbot-web;a=blobdiff_plain;f=html_generator.py;h=0fef3d421c3f1b9158a7e97932f07b43342b24a6;hp=c16f033552cb80094befa995b04645fa1d612ba6;hb=HEAD;hpb=d443dffc599f0f858068bd22dcf289fcbe4d64f3 diff --git a/html_generator.py b/html_generator.py index c16f033..f187032 100644 --- a/html_generator.py +++ b/html_generator.py @@ -16,10 +16,25 @@ Requires sorttable.js, which should be included """ import boto3 from boto3.dynamodb.conditions import Key +import os import re +import sys -website = "https://halibut.cworth.org/" -#change this if we're using AWS or some other subdomain instead +WEBROOT = "/srv/halibut.cworth.org/www" + + +def hunt_file(hunt, name): + """Return a path file 'name' within the given hunt. + + This will be withing WEBROOT and in a hunt-specific path.""" + + return "{}/{}/{}".format(WEBROOT, hunt['channel_id'], name) + +def internal_link(hunt, name): + """Returns a path for a link on this site.""" + + # Just generate a relative link, (which is just the name itself) + return "{}".format(name) def filename_from_name(name): """Returns a string derived from name, but with all spaces and slashes @@ -91,7 +106,7 @@ def hunt_info(table, hunt_id): rounds = list(rounds) rounds.sort() - return puzzles, rounds + return hunt, puzzles, rounds def round_stat(rnd, puzzles): #Counts puzzles, solved, list of puzzles for a given round @@ -123,15 +138,16 @@ def round_stat(rnd, puzzles): -def overview(puzzles, rounds): +def overview(hunt, puzzles, rounds): #big board, main page. saves as index.html start = ['\n', '\n', '\n', ' \n', ' \n', + ' \n', '\n', - ' \n', + ' \n', ' \n', '\n', ' Hunt Overview\n', - ' \n' + ' \n' '\n', - '
\n' - ' Hunt Overview' - ' All Puzzles\n' - ' Unsolved\n' - ' Solved\n' - '
\n' + '
\n', + ' Hunt Overview', + ' All Puzzles\n', + ' Unsolved\n', + ' Solved\n', + ' Turbot Docs\n' + '
\n', '\n',] columns = ['
\n'] expanding = [] @@ -172,7 +189,7 @@ def overview(puzzles, rounds): expanding += [ ' \n') end = ['\n', '\n'] html = start + expanding + columns + end - file = "index.html" - f = open(file, "w") + file = hunt_file(hunt, "index.html") + f = open(file + ".tmp", "w") for line in html: f.write(line) f.close() + os.rename(file + ".tmp", file) return None -def round_overview(rnd, puzzles): +def round_overview(hunt, rnd, puzzles): #inputs: round name, puzzles #round overview page #saves as (round name)_round.html, in case meta/round share names. @@ -219,13 +237,14 @@ def round_overview(rnd, puzzles): status = 'unsolved' start = ['\n', ' \n', - ' \n', + ' \n', ' Mystery Hunt 2022\n', - ' \n', + ' \n', + ' \n', ' \n', ' \n'.format(status), '

{}

\n'.format(rnd), - '

{}

\n'.format(link(website + "index.html", 'Hunt Overview')), + '

{}

\n'.format(link(internal_link(hunt, "index") + ".html", 'Hunt Overview')), '
\n', ' \n', ' \n', @@ -253,20 +272,20 @@ def round_overview(rnd, puzzles): ' \n'.format(elink(slack_url, puzzle['name']+meta)), ' \n'.format(elink(puzzle.get('url',''), 'Puzzle')), ' \n'.format(elink(puzzle['sheet_url'], 'Sheet')), - ' \n'.format(link(website + filename_from_name(puzzle['name']) + '.html', 'Overview')), - ' \n'.format(puzzle['solution']), + ' \n'.format(link(internal_link(hunt, filename_from_name(puzzle['name'])) + ".html", 'Overview')), + ' \n'.format(", ".join(puzzle['solution']).upper()), # ' \n', - ' \n'.format("".join(puzzle.get('tags',[]))), + ' \n'.format(", ".join(puzzle.get('tags',[]))), ' \n'] else: puzzle_list += [ ' \n', ' \n'.format(elink(slack_url, puzzle['name']+meta)), ' \n'.format(elink(puzzle.get('url',''), 'Puzzle')), ' \n'.format(elink(puzzle['sheet_url'], 'Sheet')), - ' \n'.format(link(website + filename_from_name(puzzle['name']) + '.html', 'Overview')), + ' \n'.format(link(internal_link(hunt, filename_from_name(puzzle['name'])) + ".html", 'Overview')), ' \n', # ' \n', - ' \n'.format(" ".join(puzzle.get('tags',[]))), + ' \n'.format(", ".join(puzzle.get('tags',[]))), ' \n'] end = [' \n', '
{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}
\n', @@ -274,14 +293,15 @@ def round_overview(rnd, puzzles): ' \n', '\n'] html = start + puzzle_list + end - file = "{}_round.html".format(filename_from_name(rnd)) - f = open(file, "w") + file = hunt_file(hunt, "{}_round.html".format(filename_from_name(rnd))) + f = open(file + ".tmp", "w") for line in html: f.write(line) f.close() + os.rename(file + ".tmp", file) return None -def puzzle_overview(puzzle): +def puzzle_overview(hunt, puzzle): #overview page for individual puzzles. saves as (name of puzzle).html, #with underscores rather than spaces name = puzzle['name'] @@ -291,11 +311,11 @@ def puzzle_overview(puzzle): meta = '' slack_url = channel_url(puzzle['channel_id']) if 'rounds' in puzzle: - round_url = [link(website + filename_from_name(rnd) + "_round.html", rnd) for rnd in puzzle['rounds']] + round_url = [link(internal_link(hunt, filename_from_name(rnd)) + "_round.html", rnd) for rnd in puzzle['rounds']] else: round_url = '' if puzzle['status'] == 'solved': - solution = puzzle['solution'] + solution = ", ".join(puzzle['solution']).upper() status = 'solved' else: solution = "" @@ -305,9 +325,10 @@ def puzzle_overview(puzzle): '\n', ' \n', ' \n', - ' \n', + ' \n', + ' \n', ' {}\n'.format(name+meta), - '

{}

'.format(link(website + 'index.html', 'Hunt Overview')), + '

{}

'.format(link(internal_link(hunt, 'index') + ".html", 'Hunt Overview')), '\n', '\n', '\n'.format(status), @@ -324,7 +345,7 @@ def puzzle_overview(puzzle): ' \n', ' \n', ' \n'.format(" ".join(round_url)), #round page on our site - ' \n'.format(" ".join(puzzle.get('tags',[]))), #add tags + ' \n'.format(", ".join(puzzle.get('tags',[]))), #add tags ' \n', ' \n', ' \n'.format(solution), @@ -335,13 +356,15 @@ def puzzle_overview(puzzle): '\n', '\n', '\n'] - file = "{}.html".format(filename_from_name(name)) - f = open(file, "w") + file = hunt_file(hunt, "{}.html".format(filename_from_name(name))) + f = open(file + ".tmp", "w") for line in html: f.write(line) + f.close() + os.rename(file + ".tmp", file) return None -def puzzle_lists(puzzles, filt): +def puzzle_lists(hunt, puzzles, filt): #filt is one of "All", "Solved", "Unsolved" and spits out the appropriate list of puzzles #generates pages for all puzzles, solved puzzles, unsolved puzzles #saves as all/solved/unsolved.html, has a sidebar to link to each other and to the big board @@ -349,19 +372,21 @@ def puzzle_lists(puzzles, filt): unsolved_puzzles = [puzzle for puzzle in puzzles if puzzle['status'] != 'solved'] start = ['\n', ' \n', - ' \n', + ' \n', ' Mystery Hunt 2022\n', - ' \n', + ' \n', + ' \n', ' \n', - '
\n' - ' Hunt Overview' - ' All Puzzles\n' - ' Unsolved\n' - ' Solved\n' - '
\n' + '
\n', + ' Hunt Overview', + ' All Puzzles\n', + ' Unsolved\n', + ' Solved\n', + ' Turbot Docs\n' + '
\n', ' \n', '

{}

\n'.format('{} Puzzles').format(filt), - '

{}

\n'.format(link(website + "index.html", 'Hunt Overview')), + '

{}

\n'.format(link(internal_link(hunt, 'index') + ".html", 'Hunt Overview')), '
\n', '
Round(s): {}Tags: {}Tags: {}
Answer: {}
\n', ' \n', @@ -385,7 +410,7 @@ def puzzle_lists(puzzles, filt): meta = '' slack_url = channel_url(puzzle['channel_id']) if 'rounds' in puzzle: - round_url = link(website + filename_from_name(rnd) + "_round.html", puzzle['rounds'][0]) + round_url = link(internal_link(hunt, filename_from_name(puzzle['rounds'][0])) + "_round.html", puzzle['rounds'][0]) else: round_url = '' #assuming one round per puzzle for now @@ -394,10 +419,10 @@ def puzzle_lists(puzzles, filt): ' \n'.format(elink(slack_url, puzzle['name']+meta)), ' \n'.format(elink(puzzle.get('url',''), 'Puzzle')), ' \n'.format(elink(puzzle['sheet_url'], 'Sheet')), - ' \n'.format(link(website + filename_from_name(puzzle['name']) + '.html', 'Overview')), - ' \n'.format(puzzle['solution']), + ' \n'.format(link(internal_link(hunt, filename_from_name(puzzle['name'])) + ".html", 'Overview')), + ' \n'.format(", ".join(puzzle['solution']).upper()), ' \n'.format(round_url), - ' \n'.format("".join(puzzle.get('tags',[]))), + ' \n'.format(", ".join(puzzle.get('tags',[]))), ' \n'] for puzzle in unsolved_puzzles: if puzzle['type'] == 'meta': @@ -406,7 +431,7 @@ def puzzle_lists(puzzles, filt): meta = '' slack_url = channel_url(puzzle['channel_id']) if 'rounds' in puzzle: - round_url = link(website + filename_from_name(rnd) + "_round.html", puzzle['rounds'][0]) + round_url = link(internal_link(hunt, filename_from_name(puzzle['rounds'][0])) + "_round.html", puzzle['rounds'][0]) else: round_url = '' #assuming one round per puzzle for now @@ -415,10 +440,10 @@ def puzzle_lists(puzzles, filt): ' \n'.format(elink(slack_url, puzzle['name']+meta)), ' \n'.format(elink(puzzle.get('url',''), 'Puzzle')), ' \n'.format(elink(puzzle['sheet_url'], 'Sheet')), - ' \n'.format(link(website + filename_from_name(puzzle['name']) + '.html', 'Overview')), + ' \n'.format(link(internal_link(hunt, filename_from_name(puzzle['name'])) + ".html", 'Overview')), ' \n', ' \n'.format(round_url), - ' \n'.format("".join(puzzle.get('tags',[]))), + ' \n'.format(", ".join(puzzle.get('tags',[]))), ' \n'] end = [' \n', '
{}{}{}{}{}{}{}{}{}{}
{}{}{}{}{}{}{}{}
\n', @@ -426,35 +451,62 @@ def puzzle_lists(puzzles, filt): ' \n', '\n'] if filt == "All": - file1 = 'all.html' - f = open(file1, "w") + file1 = hunt_file(hunt, 'all.html') + f = open(file1 + ".tmp", "w") for line in start + unsolved_code + solved_code + end: f.write(line) f.close() + os.rename(file1 + ".tmp", file1) elif filt == "Solved": - file2 = 'solved.html' - f = open(file2, 'w') + file2 = hunt_file(hunt, 'solved.html') + f = open(file2 + ".tmp", 'w') for line in start + solved_code + end: f.write(line) f.close() + os.rename(file2 + ".tmp", file2) elif filt == "Unsolved": - file3 = 'unsolved.html' - f = open(file3, 'w') + file3 = hunt_file(hunt, 'unsolved.html') + f = open(file3 + ".tmp", 'w') for line in start + unsolved_code + end: f.write(line) f.close() + os.rename(file3 + ".tmp", file3) return None -# Initialize AWS resources to talk to database +def generate_for_hunt_id(table, hunt_id): + hunt, puzzles, rounds = hunt_info(table, hunt_id) + + # Create a directory for the hunt in the WEBROOT + root = hunt_file(hunt, "") + try: + os.mkdir(root) + except FileExistsError: + # We're happy as a clam if the directory already exists + pass + + overview(hunt, puzzles, rounds) + for rnd in rounds: + round_overview(hunt, rnd, puzzles) + for puzzle in puzzles: + puzzle_overview(hunt, puzzle) + puzzle_lists(hunt, puzzles, "All") + puzzle_lists(hunt, puzzles, "Solved") + puzzle_lists(hunt, puzzles, "Unsolved") + + +# Initialize AWS resources to talk to the database db = boto3.resource('dynamodb') table = db.Table("turbot") -puzzles, rounds = hunt_info(table, "mh2021") - -overview(puzzles, rounds) -for rnd in rounds: - round_overview(rnd, puzzles) -for puzzle in puzzles: - puzzle_overview(puzzle) -puzzle_lists(puzzles, "All") -puzzle_lists(puzzles, "Solved") -puzzle_lists(puzzles, "Unsolved") + +def usage(): + print("Usage: {} hunt_id [...]") + print("") + print("Generates pages (under {}) ".format(WEBROOT)) + print("for the specified hunt_id(s).") + +if len(sys.argv) < 2: + usage() + sys.exit(1) + +for hunt_id in sys.argv[1:]: + generate_for_hunt_id(table, hunt_id)