Commit ee3c4813 by interrogator

basic json working

parent 3d48c11b
from django.shortcuts import render from django.shortcuts import render
from django.views import generic
from django.http import HttpResponse, JsonResponse
from wugsy.utils import REQUESTED, PROVIDED, _validator
from wugsy.decide import DecideGame
from rest_framework.decorators import api_view
# Create your views here. class GamePage(generic.TemplateView):
template_name = "game.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
print(self.request.user)
return context
def _generate_game_data(given, user):
"""
From posted data, construct a new language game
"""
decider = DecideGame(given, user)
return decider.to_dict()
@api_view(['GET', 'POST'])
def generate_data(request):
"""
Get data for a new Game
"""
assert request.method == 'POST', 'Can only POST here'
given_data = request.data
user = request.user
out_data = _generate_game_data(given_data, user)
assert _validator(out_data, PROVIDED)
return JsonResponse(out_data)
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class LangConfig(AppConfig):
name = 'lang'
from django.db import models
# Create your models here.
from django.test import TestCase
# Create your tests here.
from django.shortcuts import render
# Create your views here.
// pad numbers smaller than 10
function pad(n) {
return (n < 10) ? ("0" + n) : n;
}
// an abstract game class you can inherit from
function BaseGame() {
this.height = 100;
this.width = 100;
this.cards = {};
}
// game that follows the 00 rules
function Game00(gameData) {
BaseGame.call(this);
this.gameData = gameData;
console.log('Add game logic...')
$('#game-space').html('<h3>Game "' + gameData['game_title'] + '" here?</h3>');
}
Game00.prototype = Object.create(BaseGame.prototype);
// map game numbers to functions
var games = {'00': Game00}
// main method: lookup correct js
function buildGame(gameData) {
var gameType = gameData['game_type'];
var Game = games[pad(gameType)];
Game(gameData);
};
<li {% if active_link == "home" %}class="active"{% endif %}><a href="{% url 'home' %}">Home</a></li> <li {% if active_link == "home" %}class="active"{% endif %}><a href="{% url 'home' %}">Home</a></li>
<li {% if active_link == "about" %}class="active"{% endif %}><a href="{% url 'about' %}">About</a></li> <li {% if active_link == "about" %}class="active"{% endif %}><a href="{% url 'about' %}">About</a></li>
<li {% if active_link == "about" %}class="active"{% endif %}><a href="{% url 'game' %}">Game</a></li>
<!DOCTYPE html>
<html lang="en">
{% load staticfiles %}
{% load thumbnail %}
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{% block description %}{% endblock description %}">
<meta name="author" content="Arun Ravindran">
<link rel="shortcut icon" href="{% static 'site/ico/favicon.ico' %}">
<title>{% block title %}{% include "_brandname.html" %} :: {% endblock %}</title>
<!-- Bootstrap core CSS -->
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet">
<!-- Custom styles for this site -->
{% block styles %}
<script src="{% static 'site/js/jquery-3.2.1.min.js' %}"></script>
<link href="{% static 'site/css/main.css' %}" rel="stylesheet">
{% endblock styles %}
<!-- Custom tags for the head tag -->
{% block extrahead %}{% endblock extrahead %}
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
<body>
{% block navbar %}
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{% url 'home' %}">
{% block navbar-brand %}
<img src="{% static 'site/img/logo.png' %}" alt="logo">
{% include "_brandname.html" %}
{% endblock %}
</a>
</div>
{% block navbar-menu %}
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
{% block navbar-left %}{% endblock %}
</ul>
<ul class="nav navbar-nav navbar-right">
{% block navbar-right %}
{% if user.is_authenticated %}
{% if user.is_staff %}
<li><a href="{% url 'admin:index' %}">Admin</a></li>
{% endif %}
<li class="dropdown">
<a href="#" class="dropdown-toggle profile-menu" data-toggle="dropdown">
<img src="{% thumbnail user.profile.picture|default:'default_profile.png' 30x30 crop %}" alt="" />
{{ user.get_full_name|truncatechars:20 }}
<span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li><a href="{% url 'profiles:show_self' %}">Profile</a></li>
<li><a href="{% url 'accounts:logout' %}">Logout</a></li>
</ul>
</li>
{% endif %}
{% endblock %}
</ul>
</ul>
</div><!--/.nav-collapse -->
{% endblock %}
</div>
{% endblock navbar %}
{% block messages %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}"> <!-- singular -->
<a class="close" data-dismiss="alert">×</a>
{{ message|safe }}
</div>
{% endfor %}
{% endif %}
{% endblock %}
{% block splash %}
{% endblock splash %}
{% block container %}
<div class="container">
<div class="starter-template">
<h1>Game view</h1>
{% if not user.is_authenticated %}
<h2>Game for random user</h2>
{% else %}
<h2>Game for logged in user: {{user.get_full_name}}</h2>
{% endif %}
<form id="get-game" action = "/generate_data" method = "post">{% csrf_token %}
<input type="submit" name="Generate game" value="submit" />
</form>
<div id="json-space">JSON for a game will appear here</div>
<div id="game-space"></div>
</div>
</div><!-- /.container -->
{% endblock container %}
<!-- Site footer -->
{% block footer %}
<!-- Some social button for contact will do -->
<a name="contact"></a>
<div class="container">
<div class="footer">
<div class="row">
<div class="col-lg-6">
<p>&copy; Company {% now 'Y' %}</p>
</div>
<div class="col-lg-6 text-right">
Connect with us on
<a href="#"><i class="fa fa-facebook"></i> Facebook</a> or
<a href="#"><i class="fa fa-twitter"></i> Twitter</a>
</div>
</div>
</div>
</div>
{% endblock %}
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<script src="{% static 'site/js/game.js' %}"></script>
{% block scripts %}
<script>
$('#get-game').submit(function(e){
e.preventDefault();
$.ajax({
url:"/generate_data",
type:'post',
data:$('#get-game').serialize(),
success:function(e){
console.log('Below is validated game JSON, which should be interpretable')
console.log(e);
// now, you can call the code that builds and inserts a game
buildGame(e)
// here, have the json on screen :)
$("#json-space").text(JSON.stringify(e));
}
});
});
</script>
{% endblock scripts %}
</body>
</html>
import random
class DecideGame(object):
"""
Class that generates a game from a request
Right now it just gives dummy data, but can be filled in with methods
that look things up in DB and decide
"""
def __init__(self, request, user):
self.request = request
self.user = user
self._nonce = random.randint(0, 10000)
self._type = self._get_type()
self._title = self._get_title()
self._opponent = self._get_opponent()
self._cards = self._get_cards()
self._concept_space = self._get_concept_space()
self._user_text_entry_field = self._get_user_text_entry_field()
self._user_info = self._get_user_info()
self._extra = self._get_extra()
def _get_type(self):
return 0
def _get_title(self):
return 'Prototype game {} for {}'.format(self._nonce, self.user.name)
def _get_opponent(self):
return dict(id=78,
username='fake-opponent',
score=1234,
picture='img.jpg')
def _get_cards(self):
out = list()
cards_for_games = {0: 25}
for i in range(0, cards_for_games.get(self._type, 16)):
out.append(dict(id=i,
colour='#ffffff',
card_text='dummy {}'.format(i),
reverse=None,
selected=False,
in_theme=True
))
return out
def _get_concept_space(self):
return dict(concept_text='Underlying concept',
colour='#0000ff',
hover_text='hovering')
def _get_user_text_entry_field(self):
return dict(placeholder='placeholder text here')
def _get_user_info(self):
return dict(id=321,
username='developer',
score=1246,
picture='img.jpg')
def _get_extra(self):
return None
def to_dict(self):
return dict(game_type=self._type,
game_title=self._title,
opponent=self._opponent,
cards=self._cards,
concept_space=self._concept_space,
user_text_entry_field=self._user_text_entry_field,
user_info=self._user_info,
extra=self._extra
)
...@@ -15,6 +15,7 @@ BASE_DIR = dirname(dirname(dirname(__file__))) ...@@ -15,6 +15,7 @@ BASE_DIR = dirname(dirname(dirname(__file__)))
STATICFILES_DIRS = [join(BASE_DIR, 'static')] STATICFILES_DIRS = [join(BASE_DIR, 'static')]
MEDIA_ROOT = join(BASE_DIR, 'media') MEDIA_ROOT = join(BASE_DIR, 'media')
MEDIA_URL = "/media/" MEDIA_URL = "/media/"
APPEND_SLASH=False
# Use Django templates using the new Django 1.8 TEMPLATES settings # Use Django templates using the new Django 1.8 TEMPLATES settings
TEMPLATES = [ TEMPLATES = [
......
...@@ -5,10 +5,13 @@ from django.conf.urls.static import static ...@@ -5,10 +5,13 @@ from django.conf.urls.static import static
import profiles.urls import profiles.urls
import accounts.urls import accounts.urls
from . import views from . import views
from game.views import GamePage, generate_data
urlpatterns = [ urlpatterns = [
url(r'^$', views.HomePage.as_view(), name='home'), url(r'^$', views.HomePage.as_view(), name='home'),
url(r'^about/$', views.AboutPage.as_view(), name='about'), url(r'^about/$', views.AboutPage.as_view(), name='about'),
url(r'^game/$', GamePage.as_view(), name='game'),
url(r'^generate_data$', generate_data, name='generate_data'),
url(r'^users/', include(profiles.urls, namespace='profiles')), url(r'^users/', include(profiles.urls, namespace='profiles')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
url(r'^', include(accounts.urls, namespace='accounts')), url(r'^', include(accounts.urls, namespace='accounts')),
......
# validation scheme for frontend request for game data
REQUESTED = dict(
game_type=int,
time_remaining=float,
user_id=int,
opponent_id=int,
concept_space_text=str,
bad_game_selected=bool,
bad_game_feedback=dict(rating=int,
reason=str),
selected_cards=[int],
deleted_cards=[int],
card_order=[int]
)
# validation scheme for backend-generated game
PROVIDED = dict(
game_type=int,
game_title=str,
opponent=dict(id=int,
username=str,
score=int,
picture=str),
cards=[dict(id=int,
colour=str,
card_text=str,
reverse=None,
selected=bool,
in_theme=bool)],
concept_space=dict(concept_text=str,
colour=str,
hover_text=str),
user_text_entry_field=dict(placeholder=str),
user_info=dict(id=int,
username=str,
score=int,
picture=str),
extra=None
)
def _validator(data_to_check, schema):
"""
Check that data_to_check conforms to types in schema
"""
assert isinstance(data_to_check, dict), 'Data must be dict'
for field, expected_type in schema.items():
if expected_type is None:
continue
found = data_to_check.get(field)
msg = '{} {} is not type {}'.format(field, found, expected_type)
if isinstance(expected_type, type):
assert isinstance(found, expected_type), msg
else:
assert isinstance(found, type(expected_type)), msg
if isinstance(expected_type, dict):
#msg = '{} {} {} assertion fail'.format(expected_type, found, field)
assert _validator(found, expected_type), msg
elif isinstance(expected_type, list):
subschema = expected_type[0]
for item in found:
if isinstance(subschema, dict):
assert _validator(item, subschema)
elif isinstance(subschema, type):
assert isinstance(item, subschema)
else:
raise ValueError('List item must be dict or type')
return True
...@@ -4,6 +4,5 @@ from django.views import generic ...@@ -4,6 +4,5 @@ from django.views import generic
class HomePage(generic.TemplateView): class HomePage(generic.TemplateView):
template_name = "home.html" template_name = "home.html"
class AboutPage(generic.TemplateView): class AboutPage(generic.TemplateView):
template_name = "about.html" template_name = "about.html"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment