]> git.cworth.org Git - turbot-web/blobdiff - html_generator.py
Make the code robust against a puzzle without some fields
[turbot-web] / html_generator.py
index 7d18e0a5738a111e9bd4acda97cccbb88d7d8338..b944391ed2cd15745f57b1c29ac563d889b2893e 100644 (file)
@@ -5,7 +5,7 @@ Created on Thu Jan  6 23:35:23 2022
 @author: Avram Gottschlich
 """
 """
 @author: Avram Gottschlich
 """
 """
-I copied several functions from your code; 
+I copied several functions from your code;
 if it's easier to refer to them rather than copying them that's absolutely fine
 
 This rewrites the html each time it is called
 if it's easier to refer to them rather than copying them that's absolutely fine
 
 This rewrites the html each time it is called
@@ -14,20 +14,26 @@ that would be great
 
 Requires sorttable.js, which should be included
 """
 
 Requires sorttable.js, which should be included
 """
-from turbot.channel import channel_url
+import boto3
 from boto3.dynamodb.conditions import Key
 from boto3.dynamodb.conditions import Key
+import re
 
 website = "https://halibut.cworth.org/"
 #change this if we're using AWS or some other subdomain instead
 
 
 website = "https://halibut.cworth.org/"
 #change this if we're using AWS or some other subdomain instead
 
-def find_hunt_for_hunt_id(turb, hunt_id):
+def channel_url(channel_id):
+    """Given a channel ID, return the URL for that channel."""
+
+    return "https://halibutthatbass.slack.com/archives/{}".format(channel_id)
+
+def find_hunt_for_hunt_id(table, hunt_id):
     """Given a hunt ID find the database item for that hunt
 
     Returns None if hunt ID is not found, otherwise a
     dictionary with all fields from the hunt's row in the table,
     (channel_id, active, hunt_id, name, url, sheet_url, etc.).
     """
     """Given a hunt ID find the database item for that hunt
 
     Returns None if hunt ID is not found, otherwise a
     dictionary with all fields from the hunt's row in the table,
     (channel_id, active, hunt_id, name, url, sheet_url, etc.).
     """
-    response = turb.table.get_item(
+    response = table.get_item(
         Key={
             'hunt_id': hunt_id,
             'SK': 'hunt-{}'.format(hunt_id)
         Key={
             'hunt_id': hunt_id,
             'SK': 'hunt-{}'.format(hunt_id)
@@ -38,10 +44,10 @@ def find_hunt_for_hunt_id(turb, hunt_id):
     else:
         return None
 
     else:
         return None
 
-def hunt_puzzles_for_hunt_id(turb, hunt_id):
+def hunt_puzzles_for_hunt_id(table, hunt_id):
     """Return all puzzles that belong to the given hunt_id"""
 
     """Return all puzzles that belong to the given hunt_id"""
 
-    response = turb.table.query(
+    response = table.query(
         KeyConditionExpression=(
             Key('hunt_id').eq(hunt_id) &
             Key('SK').begins_with('puzzle-')
         KeyConditionExpression=(
             Key('hunt_id').eq(hunt_id) &
             Key('SK').begins_with('puzzle-')
@@ -59,16 +65,18 @@ def link(lin, text):
     #internal links, doesn't open new tab
     return '<a href="{}">{}</a>'.format(lin, text)
 
     #internal links, doesn't open new tab
     return '<a href="{}">{}</a>'.format(lin, text)
 
-def hunt_info(turb, hunt):
+def hunt_info(table, hunt_id):
     """
     """
-    Retrieves list of rounds, puzzles for the given hunt    
+    Retrieves list of rounds, puzzles for the given hunt
     """
     """
+
+    hunt = find_hunt_for_hunt_id(table, hunt_id)
+
     name = hunt["name"]
     name = hunt["name"]
-    hunt_id = hunt["hunt_id"]
     channel_id = hunt["channel_id"]
     channel_id = hunt["channel_id"]
-    
-    puzzles = hunt_puzzles_for_hunt_id(turb, hunt_id)
-    
+
+    puzzles = hunt_puzzles_for_hunt_id(table, hunt_id)
+
     rounds = set()
     for puzzle in puzzles:
         if "rounds" not in puzzle:
     rounds = set()
     for puzzle in puzzles:
         if "rounds" not in puzzle:
@@ -77,7 +85,7 @@ def hunt_info(turb, hunt):
             rounds.add(rnd)
     rounds = list(rounds)
     rounds.sort()
             rounds.add(rnd)
     rounds = list(rounds)
     rounds.sort()
-    
+
     return puzzles, rounds
 
 def round_stat(rnd, puzzles):
     return puzzles, rounds
 
 def round_stat(rnd, puzzles):
@@ -90,7 +98,7 @@ def round_stat(rnd, puzzles):
     meta_solved = 0
     for puzzle in puzzles:
         if "rounds" not in puzzle:
     meta_solved = 0
     for puzzle in puzzles:
         if "rounds" not in puzzle:
-            continue        
+            continue
         if rnd in puzzle["rounds"]:
             if puzzle['type'] == 'meta':
                 metas.append(puzzle)
         if rnd in puzzle["rounds"]:
             if puzzle['type'] == 'meta':
                 metas.append(puzzle)
@@ -107,9 +115,9 @@ def round_stat(rnd, puzzles):
     unsolved_puzzles = sorted(unsolved_puzzles, key = lambda i: i['name'])
     rnd_puzzles = metas + unsolved_puzzles + solved_puzzles
     return puzzle_count, solved_count, rnd_puzzles, meta_solved, len(metas)
     unsolved_puzzles = sorted(unsolved_puzzles, key = lambda i: i['name'])
     rnd_puzzles = metas + unsolved_puzzles + solved_puzzles
     return puzzle_count, solved_count, rnd_puzzles, meta_solved, len(metas)
-            
-   
-    
+
+
+
 def overview(puzzles, rounds):
     #big board, main page. saves as index.html
     start = ['<!DOCTYPE html>\n',
 def overview(puzzles, rounds):
     #big board, main page. saves as index.html
     start = ['<!DOCTYPE html>\n',
@@ -155,7 +163,7 @@ def overview(puzzles, rounds):
         '      <p>Puzzles: {}/{}</p>\n'.format(solved_count, puzzle_count),
         '      <p>Metas: {}/{}</p>\n'.format(meta_solved, metas),
         '    </div>\n']
         '      <p>Puzzles: {}/{}</p>\n'.format(solved_count, puzzle_count),
         '      <p>Metas: {}/{}</p>\n'.format(meta_solved, metas),
         '    </div>\n']
-        
+
         expanding += [
         '  <div id="b{}" class="containerTab {}" style="display:none;">\n'.format(i, status),
         '    <span onclick="this.parentElement.style.display=\'none\'" class="closebtn">x</span>\n',
         expanding += [
         '  <div id="b{}" class="containerTab {}" style="display:none;">\n'.format(i, status),
         '    <span onclick="this.parentElement.style.display=\'none\'" class="closebtn">x</span>\n',
@@ -234,26 +242,26 @@ def round_overview(rnd, puzzles):
         else:
             meta = ''
         slack_url = channel_url(puzzle['channel_id'])
         else:
             meta = ''
         slack_url = channel_url(puzzle['channel_id'])
-        
+
         if puzzle['status'] == 'solved':
             puzzle_list += [ '                    <tr>\n',
              '                        <td>{}</td>\n'.format(elink(slack_url, puzzle['name']+meta)),
         if puzzle['status'] == 'solved':
             puzzle_list += [ '                    <tr>\n',
              '                        <td>{}</td>\n'.format(elink(slack_url, puzzle['name']+meta)),
-             '                        <td>{}</td>\n'.format(elink(puzzle['url'], 'Puzzle')),
+             '                        <td>{}</td>\n'.format(elink(puzzle.get('url',''), 'Puzzle')),
              '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
              '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
              '                        <td>{}</td>\n'.format(puzzle['solution']),
             # '                        <td></td>\n',
              '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
              '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
              '                        <td>{}</td>\n'.format(puzzle['solution']),
             # '                        <td></td>\n',
-             '                        <td>{}</td>\n'.format("".join(puzzle['tags'])),
+             '                        <td>{}</td>\n'.format("".join(puzzle.get('tags',[]))),
              '                    </tr>\n']
         else:
             puzzle_list += [ '                    <tr>\n',
              '                        <td><b>{}</b></td>\n'.format(elink(slack_url, puzzle['name']+meta)),
              '                    </tr>\n']
         else:
             puzzle_list += [ '                    <tr>\n',
              '                        <td><b>{}</b></td>\n'.format(elink(slack_url, puzzle['name']+meta)),
-             '                        <td>{}</td>\n'.format(elink(puzzle['url'], 'Puzzle')),
+             '                        <td>{}</td>\n'.format(elink(puzzle.get('url',''), 'Puzzle')),
              '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
              '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
              '                        <td></td>\n',
             # '                        <td></td>\n',
              '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
              '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
              '                        <td></td>\n',
             # '                        <td></td>\n',
-             '                        <td>{}</td>\n'.format(" ".join(puzzle['tags'])),
+             '                        <td>{}</td>\n'.format(" ".join(puzzle.get('tags',[]))),
              '                    </tr>\n']
     end = ['                </tbody>\n',
     '            </table>\n',
              '                    </tr>\n']
     end = ['                </tbody>\n',
     '            </table>\n',
@@ -277,7 +285,10 @@ def puzzle_overview(puzzle):
     else:
         meta = ''
     slack_url = channel_url(puzzle['channel_id'])
     else:
         meta = ''
     slack_url = channel_url(puzzle['channel_id'])
-    round_url = [link(website + "_".join(rnd.split()) + "_round.html", rnd) for rnd in puzzle['rounds']]
+    if 'rounds' in puzzle:
+        round_url = [link(website + "_".join(rnd.split()) + "_round.html", rnd) for rnd in puzzle['rounds']]
+    else:
+        round_url = ''
     if puzzle['status'] == 'solved':
         solution = puzzle['solution']
         status = 'solved'
     if puzzle['status'] == 'solved':
         solution = puzzle['solution']
         status = 'solved'
@@ -300,7 +311,7 @@ def puzzle_overview(puzzle):
      '        <table class="center">\n',
      '            <tr>\n',
      '                <td>{}</td>\n'.format(elink(slack_url, 'Channel')), #slack channel
      '        <table class="center">\n',
      '            <tr>\n',
      '                <td>{}</td>\n'.format(elink(slack_url, 'Channel')), #slack channel
-     '                <td>{}</td>\n'.format(elink(puzzle['url'], 'Puzzle')),
+     '                <td>{}</td>\n'.format(elink(puzzle.get('url',''), 'Puzzle')),
      '                <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
      '                <td>Additional Resources</td>\n',
      '            </tr>\n',
      '                <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
      '                <td>Additional Resources</td>\n',
      '            </tr>\n',
@@ -308,7 +319,7 @@ def puzzle_overview(puzzle):
      '        <table class="center">\n',
      '            <tr>\n',
      '                <td>Round(s): {}</td>\n'.format(" ".join(round_url)), #round page on our site
      '        <table class="center">\n',
      '            <tr>\n',
      '                <td>Round(s): {}</td>\n'.format(" ".join(round_url)), #round page on our site
-     '                <td>Tags: {}</td>\n'.format(" ".join(puzzle['tags'])), #add tags
+     '                <td>Tags: {}</td>\n'.format(" ".join(puzzle.get('tags',[]))), #add tags
      '            </tr>\n',
      '            <tr>\n',
      '                <td>Answer: {}</td>\n'.format(solution),
      '            </tr>\n',
      '            <tr>\n',
      '                <td>Answer: {}</td>\n'.format(solution),
@@ -319,7 +330,8 @@ def puzzle_overview(puzzle):
      '\n',
      '</body>\n',
      '</html>\n']
      '\n',
      '</body>\n',
      '</html>\n']
-    underscored = "_".join(name.split())
+    # Replace all spaces and slashes in the name with underscores
+    underscored = re.sub(r'[ /]', '_', name)
     file = "{}.html".format(underscored)
     f = open(file, "w")
     for line in html:
     file = "{}.html".format(underscored)
     f = open(file, "w")
     for line in html:
@@ -369,17 +381,20 @@ def puzzle_lists(puzzles, filt):
         else:
             meta = ''
         slack_url = channel_url(puzzle['channel_id'])
         else:
             meta = ''
         slack_url = channel_url(puzzle['channel_id'])
-        round_url = link(website + "_".join(rnd.split()) + "_round.html", puzzle['rounds'][0])
+        if 'rounds' in puzzle:
+            round_url = link(website + "_".join(rnd.split()) + "_round.html", puzzle['rounds'][0])
+        else:
+            round_url = ''
         #assuming one round per puzzle for now
         #assuming one round per puzzle for now
-        
+
         solved_code += ['                    <tr>\n',
          '                        <td>{}</td>\n'.format(elink(slack_url, puzzle['name']+meta)),
         solved_code += ['                    <tr>\n',
          '                        <td>{}</td>\n'.format(elink(slack_url, puzzle['name']+meta)),
-         '                        <td>{}</td>\n'.format(elink(puzzle['url'], 'Puzzle')),
+         '                        <td>{}</td>\n'.format(elink(puzzle.get('url',''), 'Puzzle')),
          '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
          '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
          '                        <td>{}</td>\n'.format(puzzle['solution']),
          '                        <td>{}</td>\n'.format(round_url),
          '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
          '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
          '                        <td>{}</td>\n'.format(puzzle['solution']),
          '                        <td>{}</td>\n'.format(round_url),
-         '                        <td>{}</td>\n'.format("".join(puzzle['tags'])),
+         '                        <td>{}</td>\n'.format("".join(puzzle.get('tags',[]))),
          '                    </tr>\n']
     for puzzle in unsolved_puzzles:
         if puzzle['type'] == 'meta':
          '                    </tr>\n']
     for puzzle in unsolved_puzzles:
         if puzzle['type'] == 'meta':
@@ -387,17 +402,20 @@ def puzzle_lists(puzzles, filt):
         else:
             meta = ''
         slack_url = channel_url(puzzle['channel_id'])
         else:
             meta = ''
         slack_url = channel_url(puzzle['channel_id'])
-        round_url = link(website + "_".join(rnd.split()) + "_round.html", puzzle['rounds'][0])
+        if 'rounds' in puzzle:
+            round_url = link(website + "_".join(rnd.split()) + "_round.html", puzzle['rounds'][0])
+        else:
+            round_url = ''
         #assuming one round per puzzle for now
         #assuming one round per puzzle for now
-        
+
         unsolved_code += ['                    <tr>\n',
          '                        <td>{}</td>\n'.format(elink(slack_url, puzzle['name']+meta)),
         unsolved_code += ['                    <tr>\n',
          '                        <td>{}</td>\n'.format(elink(slack_url, puzzle['name']+meta)),
-         '                        <td>{}</td>\n'.format(elink(puzzle['url'], 'Puzzle')),
+         '                        <td>{}</td>\n'.format(elink(puzzle.get('url',''), 'Puzzle')),
          '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
          '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
          '                        <td></td>\n',
          '                        <td>{}</td>\n'.format(round_url),
          '                        <td>{}</td>\n'.format(elink(puzzle['sheet_url'], 'Sheet')),
          '                        <td>{}</td>\n'.format(link(website + "_".join(puzzle['name'].split()) + '.html', 'Overview')),
          '                        <td></td>\n',
          '                        <td>{}</td>\n'.format(round_url),
-         '                        <td>{}</td>\n'.format("".join(puzzle['tags'])),
+         '                        <td>{}</td>\n'.format("".join(puzzle.get('tags',[]))),
          '                    </tr>\n']
     end = ['                </tbody>\n',
     '            </table>\n',
          '                    </tr>\n']
     end = ['                </tbody>\n',
     '            </table>\n',
@@ -424,10 +442,11 @@ def puzzle_lists(puzzles, filt):
         f.close()
     return None
 
         f.close()
     return None
 
+# Initialize AWS resources to talk to database
+db = boto3.resource('dynamodb')
+table = db.Table("turbot")
+puzzles, rounds = hunt_info(table, "mh2021")
 
 
-
-puzzles, rounds = hunt_info(turb, hunt)
-#I am not sure where these come from
 overview(puzzles, rounds)
 for rnd in rounds:
     round_overview(rnd, puzzles)
 overview(puzzles, rounds)
 for rnd in rounds:
     round_overview(rnd, puzzles)