url = puzzle.get('url', None)
sheet_url = puzzle.get('sheet_url', None)
state = puzzle.get('state', None)
+ tags = puzzle.get('tags', [])
status_emoji = ''
solution_str = ''
state_str = ''
if state:
- state_str = "\n{}".format(state)
+ state_str = " State: {}".format(state)
+
+ tags_str = ''
+ if tags:
+ tags_str = " Tags: "+" ".join(["`{}`".format(tag) for tag in tags])
+
+ extra_str = ''
+ if state_str or tags_str:
+ extra_str = "\n{}{}".format(tags_str, state_str)
rounds_str = ''
if include_rounds and 'rounds' in puzzle:
channel_url(channel_id), name,
solution_str,
', '.join(links), rounds_str,
- state_str
+ extra_str
)
# Combining hunt ID and puzzle ID together here is safe because
"""Returns True if this puzzle matches the given string (regexp)
A match will be considered on any of puzzle title, round title,
- puzzle URL, puzzle state, or solution string. The string can
- include regular expression syntax. Matching is case insensitive.
+ puzzle URL, puzzle state, puzzle type, tags, or solution
+ string. The string can include regular expression syntax. Matching
+ is case insensitive.
"""
p = re.compile('.*'+pattern+'.*', re.IGNORECASE)
if p.match(puzzle['state']):
return True
+ if 'type' in puzzle:
+ if p.match(puzzle['type']):
+ return True
+
if 'solution' in puzzle:
for solution in puzzle['solution']:
if p.match(solution):
return True
+ if 'tags' in puzzle:
+ for tag in puzzle['tags']:
+ if p.match(tag):
+ return True
+
return False
def puzzle_matches_all(puzzle, patterns):
"""Returns True if this puzzle matches all of the given list of patterns
A match will be considered on any of puzzle title, round title,
- puzzle URL, puzzle state, or solution string. All patterns must
- match the puzzle somewhere, (that is, there is an implicit logical
- AND between patterns). Patterns can include regular expression
- syntax. Matching is case insensitive.
+ puzzle URL, puzzle state, puzzle types, tags, or solution
+ string. All patterns must match the puzzle somewhere, (that is,
+ there is an implicit logical AND between patterns). Patterns can
+ include regular expression syntax. Matching is case insensitive.
+
"""
for pattern in patterns:
if len(links):
topic += "({})".format(', '.join(links))
+ tags = puzzle.get('tags', [])
+ if tags:
+ topic += " {}".format(" ".join(["`{}`".format(t) for t in tags]))
+
state = puzzle.get('state', None)
if state:
topic += " {}".format(state)
def puzzle_channel_name(puzzle):
"""Compute the channel name for a puzzle"""
+ round = ''
+ if 'rounds' in puzzle:
+ round = '-' + puzzle_id_from_name(puzzle['rounds'][0])
+
+ meta = ''
+ if puzzle.get('type', 'plain') == 'meta':
+ meta = '-m'
+
# Note: We don't use puzzle['puzzle_id'] here because we're keeping
# that as a persistent identifier in the database. Instead we
# create a new ID-like identifier from the current name.
- channel_name = "{}-{}".format(
+ channel_name = "{}{}{}-{}".format(
puzzle['hunt_id'],
+ round,
+ meta,
puzzle_id_from_name(puzzle['name'])
)
old_sheet_name = puzzle_sheet_name(old_puzzle)
if sheet_name != old_sheet_name:
- turbot.sheets.renameSheet(turb, puzzle['sheet_url'], sheet_name)
+ turbot.sheets.rename_spreadsheet(turb, puzzle['sheet_url'], sheet_name)
# Compute the Slack channel name and set it if it has changed
channel_name = puzzle_channel_name(puzzle)
channel=channel_id,
name=channel_name
)
+
+# A copy deep enough to work for puzzle_update_channel_and_sheet above
+def puzzle_copy(old_puzzle):
+ new_puzzle = old_puzzle.copy()
+
+ if 'tags' in old_puzzle:
+ new_puzzle['tags'] = old_puzzle['tags'].copy()
+
+ return new_puzzle