input_block, section_block, text_block, multi_select_block
)
from turbot.hunt import find_hunt_for_hunt_id
+from turbot.puzzle import find_puzzle_for_url
import turbot.rot
import turbot.sheets
import turbot.slack
TableName='turbot',
KeySchema=[
{'AttributeName': 'hunt_id', 'KeyType': 'HASH'},
- {'AttributeName': 'SK', 'KeyType': 'RANGE'},
+ {'AttributeName': 'SK', 'KeyType': 'RANGE'}
],
AttributeDefinitions=[
{'AttributeName': 'hunt_id', 'AttributeType': 'S'},
{'AttributeName': 'SK', 'AttributeType': 'S'},
{'AttributeName': 'channel_id', 'AttributeType': 'S'},
{'AttributeName': 'is_hunt', 'AttributeType': 'S'},
+ {'AttributeName': 'url', 'AttributeType': 'S'}
],
ProvisionedThroughput={
'ReadCapacityUnits': 5,
'WriteCapacityUnits': 5
}
}
+ ],
+ LocalSecondaryIndexes = [
+ {
+ 'IndexName': 'url_index',
+ 'KeySchema': [
+ {'AttributeName': 'hunt_id', 'KeyType': 'HASH'},
+ {'AttributeName': 'url', 'KeyType': 'RANGE'},
+ ],
+ 'Projection': {
+ 'ProjectionType': 'ALL'
+ }
+ }
]
)
return submission_error(
This is the modal view presented to the user by the puzzle function
above."""
+ # First, read all the various data from the request
meta = json.loads(metadata)
hunt_id = meta['hunt_id']
rounds = []
new_rounds = state['new_rounds']['new_rounds']['value']
+ # Before doing anything, reject this puzzle if a puzzle already
+ # exists with the same URL.
+ if url:
+ existing = find_puzzle_for_url(turb, hunt_id, url)
+ if existing:
+ return submission_error(
+ "url",
+ "Error: A puzzle with this URL already exists.")
+
# Create a Slack-channel-safe puzzle_id
puzzle_id = re.sub(r'[^a-zA-Z0-9_]', '', name).lower()
--- /dev/null
+from boto3.dynamodb.conditions import Key
+
+def find_puzzle_for_url(turb, hunt_id, url):
+ """Given a hunt_id and URL, return the puzzle with that URL
+
+ Returns None if no puzzle with the given URL exists in the database,
+ otherwise a dictionary with all fields from the puzzle's row in
+ the database.
+ """
+
+ response = turb.table.query(
+ IndexName='url_index',
+ KeyConditionExpression=(
+ Key('hunt_id').eq(hunt_id) &
+ Key('url').eq(url)
+ )
+ )
+
+ if response['Count'] == 0:
+ return None
+
+ return response['Items'][0]