/
api.py
149 lines (132 loc) · 5.97 KB
/
api.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import logging
import endpoints
from protorpc import remote, messages
from google.appengine.api import memcache
from google.appengine.api import taskqueue
from models import User, Game, Score
from models import StringMessage, NewGameForm, GameForm, MakeMoveForm,\
ScoreForms
from utils import get_by_urlsafe
NEW_GAME_REQUEST = endpoints.ResourceContainer(NewGameForm)
GET_GAME_REQUEST = endpoints.ResourceContainer(
urlsafe_game_key=messages.StringField(1),)
MAKE_MOVE_REQUEST = endpoints.ResourceContainer(
MakeMoveForm,
urlsafe_game_key=messages.StringField(1),)
USER_REQUEST = endpoints.ResourceContainer(user_name=messages.StringField(1),
email=messages.StringField(2))
MEMCACHE_MOVES_REMAINING = 'MOVES_REMAINING'
@endpoints.api(name='guess_a_number', version='v1')
class GuessANumberApi(remote.Service):
"""Game API"""
@endpoints.method(request_message=USER_REQUEST,
response_message=StringMessage,
path='user',
name='create_user',
http_method='POST')
def create_user(self, request):
"""Create a User. Requires a unique username"""
if User.query(User.name == request.user_name).get():
raise endpoints.ConflictException(
'A User with that name already exists!')
user = User(name=request.user_name, email=request.email)
user.put()
return StringMessage(message='User {} created!'.format(
request.user_name))
@endpoints.method(request_message=NEW_GAME_REQUEST,
response_message=GameForm,
path='game',
name='new_game',
http_method='POST')
def new_game(self, request):
"""Creates new game"""
user = User.query(User.name == request.user_name).get()
if not user:
raise endpoints.NotFoundException(
'A User with that name does not exist!')
try:
game = Game.new_game(user.key, request.min,
request.max, request.attempts)
except ValueError:
raise endpoints.BadRequestException('Maximum must be greater '
'than minimum!')
# Use a task queue to update the average attempts remaining.
# This operation is not needed to complete the creation of a new game
# so it is performed out of sequence.
taskqueue.add(url='/tasks/cache_average_attempts')
return game.to_form('Good luck playing Guess a Number!')
@endpoints.method(request_message=GET_GAME_REQUEST,
response_message=GameForm,
path='game/{urlsafe_game_key}',
name='get_game',
http_method='GET')
def get_game(self, request):
"""Return the current game state."""
game = get_by_urlsafe(request.urlsafe_game_key, Game)
if game:
return game.to_form('Time to make a move!')
else:
raise endpoints.NotFoundException('Game not found!')
@endpoints.method(request_message=MAKE_MOVE_REQUEST,
response_message=GameForm,
path='game/{urlsafe_game_key}',
name='make_move',
http_method='PUT')
def make_move(self, request):
"""Makes a move. Returns a game state with message"""
game = get_by_urlsafe(request.urlsafe_game_key, Game)
if game.game_over:
return game.to_form('Game already over!')
game.attempts_remaining -= 1
if request.guess == game.target:
game.end_game(True)
return game.to_form('You win!')
if request.guess < game.target:
msg = 'Too low!'
else:
msg = 'Too high!'
if game.attempts_remaining < 1:
game.end_game(False)
return game.to_form(msg + ' Game over!')
else:
game.put()
return game.to_form(msg)
@endpoints.method(response_message=ScoreForms,
path='scores',
name='get_scores',
http_method='GET')
def get_scores(self, request):
"""Return all scores"""
return ScoreForms(items=[score.to_form() for score in Score.query()])
@endpoints.method(request_message=USER_REQUEST,
response_message=ScoreForms,
path='scores/user/{user_name}',
name='get_user_scores',
http_method='GET')
def get_user_scores(self, request):
"""Returns all of an individual User's scores"""
user = User.query(User.name == request.user_name).get()
if not user:
raise endpoints.NotFoundException(
'A User with that name does not exist!')
scores = Score.query(Score.user == user.key)
return ScoreForms(items=[score.to_form() for score in scores])
@endpoints.method(response_message=StringMessage,
path='games/average_attempts',
name='get_average_attempts_remaining',
http_method='GET')
def get_average_attempts(self, request):
"""Get the cached average moves remaining"""
return StringMessage(message=memcache.get(MEMCACHE_MOVES_REMAINING) or '')
@staticmethod
def _cache_average_attempts():
"""Populates memcache with the average moves remaining of Games"""
games = Game.query(Game.game_over == False).fetch()
if games:
count = len(games)
total_attempts_remaining = sum([game.attempts_remaining
for game in games])
average = float(total_attempts_remaining)/count
memcache.set(MEMCACHE_MOVES_REMAINING,
'The average moves remaining is {:.2f}'.format(average))
api = endpoints.api_server([GuessANumberApi])