Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions puzzles/lacrosse_town_crossword.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import requests
import json
from django.conf import settings
from puzzles.models import Puzzle, LacrosseTownCrossword

# returns URL
def create_lacrosse_town_crossword():
params = {
"type": "new",
}
result = requests.post(
settings.LACROSSE_TOWN_CROSSWORD_DOMAIN + "/api",
data={"params": json.dumps(params)})

result = json.loads(result.text)

if not result["success"]:
raise Exception("crossword api did not return success")
if not result["url"]:
raise Exception("crossword api did not return a URL")

return result["url"]

def add_crossword_for_puzzle(puzzle):
url = create_lacrosse_town_crossword()

LacrosseTownCrossword.objects.create(
puzzle=puzzle,
url=url,
is_deleted=False)
2 changes: 1 addition & 1 deletion puzzles/management/commands/initial_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def handle(self, *args, **options):
testing_taglist.tags = [Tag.objects.get(name='testing')]
testing_taglist.save()

default_locations = ['Cambridge', 'remote']
default_locations = ['Cambridge', 'remote', 'unknown']
Location.objects.all().delete()
for location_name in default_locations:
Location(name=location_name).save()
Expand Down
8 changes: 8 additions & 0 deletions puzzles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ class Location(OrderedModel):
def __unicode__(self):
return self.name

class LacrosseTownCrossword(OrderedModel):
puzzle = models.ForeignKey('Puzzle')
url = models.CharField(max_length=200)
is_deleted = models.BooleanField()

def __unicode__(self):
return self.url

class UserProfile(models.Model):
user = models.OneToOneField(User)

Expand Down
23 changes: 23 additions & 0 deletions puzzles/static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,29 @@ div#answers a#callinanswer:hover {
padding-left: 10px;
}

.puzzle-blurb div#add_crossword {
display: inline-block;
padding-left: 10px;
}

#delete_crossword_form {
padding-left: 200px;
}

.delete_crossword_form_hidden {
display: none;
}

input[type=button].collaboration_link_button_sel {
background-color: #66ffff;
border-color: #66ffff;
box-shadow: inset;
}

input[type=button].collaboration_link_button {
cursor: pointer;
}

span.puzzle-title {
font-weight: bold;
}
Expand Down
42 changes: 40 additions & 2 deletions puzzles/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
from django.db import IntegrityError
from django import forms

from models import Status, Priority, Tag, QueuedAnswer, PuzzleWrongAnswer, Puzzle, TagList, UploadedFile, Location, Config
from models import Status, Priority, Tag, QueuedAnswer, PuzzleWrongAnswer, Puzzle, TagList, UploadedFile, Location, Config, LacrosseTownCrossword
from forms import UploadForm, AnswerForm
from django.contrib.auth.models import User
from django.conf import settings
from lacrosse_town_crossword import add_crossword_for_puzzle

def get_motd():
try:
Expand Down Expand Up @@ -81,6 +82,22 @@ def puzzle_info(request, puzzle_id):
queued_answers = puzzle.queuedanswer_set.order_by('-id')
wrong_answers = puzzle.puzzlewronganswer_set.order_by('-id')
uploaded_files = puzzle.uploadedfile_set.order_by('id')

crosswords = LacrosseTownCrossword.objects.all().filter(puzzle=puzzle, is_deleted=False)
collaboration_links = ([
{"selected": False, "text": "Spreadsheet",
"url": reverse("puzzles.views.puzzle_spreadsheet", args=[puzzle_id]),
"id": ""},
] +
[ {"selected": False, "text": "Crossword Sheet", "url": crossword.url,
"id": str(crossword.id)}
for crossword in crosswords ])
if len(collaboration_links) > 1:
# by default, select the first crossword, if there is at least one
collaboration_links[1]["selected"] = True
else:
collaboration_links[0]["selected"] = True

return render_to_response("puzzles/puzzle-info.html", puzzle_context(request, {
'puzzle': puzzle,
'statuses': statuses,
Expand All @@ -91,7 +108,9 @@ def puzzle_info(request, puzzle_id):
'queued_answers': queued_answers,
'wrong_answers': wrong_answers,
'uploaded_files': uploaded_files,
'refresh': 30
'refresh': 30,
'collaboration_links': collaboration_links,
'hide_collaboration_links': len(collaboration_links) == 1,
}))

@login_required
Expand Down Expand Up @@ -137,6 +156,25 @@ def puzzle_add_solver(request, puzzle_id):
puzzle.save()
return redirect(request.POST['continue'])

@login_required
def puzzle_add_crossword(request, puzzle_id):
puzzle = Puzzle.objects.get(id=puzzle_id)
add_crossword_for_puzzle(puzzle)
return redirect(request.POST['continue'])

@login_required
def puzzle_delete_crossword(request, puzzle_id):
# soft delete: just set the `is_deleted` field to True
crossword_id = int(request.POST['crossword_id'])
crossword = LacrosseTownCrossword.objects.get(id=crossword_id)
if crossword.puzzle.id != int(puzzle_id):
raise Exception(
"puzzle id did not match: crossword_id=%d, puzzle_id=%d, puzzle_id from request=%s" %
(crossword_id, crossword.puzzle.id, puzzle_id))
crossword.is_deleted = True
crossword.save()
return redirect(request.POST['continue'])

def handle_puzzle_upload(puzzle, name, file):
if file.name == '' or file.name[0] == '.' or '/' in file.name:
raise ValueError
Expand Down
2 changes: 2 additions & 0 deletions solving/local_settings_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@
import random
ZULIP_HOSTNAME_BALANCING = lambda: 'https://e%d.%s' % (
random.randint(1, 100), ZULIP_SERVER_HOSTNAME)

LACROSSE_TOWN_CROSSWORD_DOMAIN = 'http://enigmatic-mountain-8851.herokuapp.com'
2 changes: 2 additions & 0 deletions solving/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
url(r'^puzzle/set_priority/(\d+)/$', 'puzzles.views.puzzle_set_priority'),
url(r'^puzzle/remove_solver/(\d+)/$', 'puzzles.views.puzzle_remove_solver'),
url(r'^puzzle/add_solver/(\d+)/$', 'puzzles.views.puzzle_add_solver'),
url(r'^puzzle/add_crossword/(\d+)/$', 'puzzles.views.puzzle_add_crossword'),
url(r'^puzzle/delete_crossword/(\d+)/$', 'puzzles.views.puzzle_delete_crossword'),
url(r'^puzzle/upload/(\d+)/$', 'puzzles.views.puzzle_upload'),
url(r'^puzzle/call_in_answer/(\d+)/$', 'puzzles.views.puzzle_call_in_answer'),

Expand Down
7 changes: 6 additions & 1 deletion templates/puzzles/puzzle-frames.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
<head>
<title>{{ title }}</title>
<link rel="icon" href="{{ STATIC_URL }}img/favicon.ico" />
<script type="text/javascript">
function setCollaborationSrc(src) {
document.getElementById('collaboration_frame').setAttribute('src', src);
}
</script>
</head>
<frameset rows="150px,*" title="{{ title }}">
<frame src="{% url 'puzzles.views.puzzle_info' id %}" />
<frameset cols="*,390px">
<frame src="{% url 'puzzles.views.puzzle_spreadsheet' id %}" />
<frame src="{% url 'puzzles.views.puzzle_spreadsheet' id %}" id="collaboration_frame" />
<frame src="{% url 'puzzles.views.puzzle_chat' id %}" />
</frameset>
</frameset>
Expand Down
61 changes: 61 additions & 0 deletions templates/puzzles/puzzle-info.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
</select>
</div>

<div id="add_crossword">
<form action="{% url 'puzzles.views.puzzle_add_crossword' puzzle.id %}" method="post">{% csrf_token %}
<input type="hidden" name="continue" value="{{ path }}" />
<input type="submit" value="+ Collabortive Crossword Sheet">
</form>
</span>

<div id="puzzlefiles">
<a id="attachfile" href="{% url 'puzzles.views.puzzle_upload' puzzle.id %}">Attach file</a>
{% if uploaded_files %}Attached files:
Expand Down Expand Up @@ -123,5 +130,59 @@
</form>
</span>
</div>

<script type="text/javascript">
function collaborationGoTo(target) {
// Unselect the previously selected button
var currentlySelected = Array.prototype.slice.call(
document.getElementsByClassName("collaboration_link_button_sel"));
for (var i = 0; i < currentlySelected.length; i++) {
currentlySelected[i].setAttribute('class', 'collaboration_link_button')
currentlySelected[i].removeAttribute('disabled');
}

// Select the newly-clicked button
target.setAttribute('class', 'collaboration_link_button_sel');
target.setAttribute('disabled', 'true');

// Set the frame's source
var src = target.getAttribute('data-src');
parent.setCollaborationSrc(src);

// Update the delete button form
var crossword_id = target.getAttribute('data-crossword-id');
var form = document.getElementById('delete_crossword_form');
if (crossword_id == "") {
form.setAttribute('class', 'delete_crossword_form_hidden');
} else {
form.setAttribute('class', '');
}
document.getElementById('crossword_id_input').value = crossword_id;
}

// Makes sure that all the state is correct for the initially
// selected item.
window.addEventListener('load', function() {
collaborationGoTo(document.getElementsByClassName('collaboration_link_button_sel')[0]);
});
</script>
<div id="collaboration_links" style="{% if hide_collaboration_links %}display: none{% endif %}">
{% for collaboration_link in collaboration_links %}
<input type="button"
class="{% if collaboration_link.selected %}collaboration_link_button_sel{%else%}collaboration_link_button{%endif%}"
onClick="collaborationGoTo(event.target)"
value="{{ collaboration_link.text }}"
data-src="{{ collaboration_link.url }}"
data-crossword-id="{{ collaboration_link.id }}">
{% endfor %}
<form id="delete_crossword_form" action="{% url 'puzzles.views.puzzle_delete_crossword' puzzle.id %}"
method="post" class="delete_crossword_form_hidden"
>{% csrf_token %}
<input type="hidden" name="continue" value="{{ path }}">
<input type="hidden" name="crossword_id" value="" id="crossword_id_input">
<input type="submit" value="Delete this crossword sheet">
</form>
</div>

</div>
{% endblock %}