/
whosays_api.py
262 lines (232 loc) · 10.1 KB
/
whosays_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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
"""Hello World API implemented using Google Cloud Endpoints.
Contains declarations of endpoint, endpoint methods,
as well as the ProtoRPC message class and container required
for endpoint method definition.
"""
import endpoints
from protorpc import messages
from protorpc import remote
from google.appengine.api import memcache
from utils import get_by_urlsafe
from models import (
User,
StringMessage,
NewGameDataForm,
GameData,
NewGameForm,
GameForm,
GameForms,
Game,
MakeMoveForm,
ScoreForms,
Rankings,
GameHighScores,
Analysis)
USER_REQUEST = endpoints.ResourceContainer(
user_name=messages.StringField(1),
email=messages.StringField(2))
ADD_DATA = endpoints.ResourceContainer(NewGameDataForm)
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))
MEMCACHE_AVE_PTS_PER_GAME = 'AVE_PTS_PER_GAME'
HIGH_SCORE_REQUEST = endpoints.ResourceContainer(
number_of_results=messages.IntegerField(1))
package = 'WhoSays'
@endpoints.api(name='whosaysendpoints', version='v1')
class WhoSaysApi(remote.Service):
"""WhoSaysAPI v1."""
@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=ADD_DATA,
response_message=StringMessage,
path='adddata',
name='add_data',
http_method='POST')
def add_data(self, request):
"""Add game data. Administrative."""
gData = GameData.new_game_data(sayer_category=request.sayer_category,
sayer=request.sayer,
saying=request.saying,
hints=request.hints)
gData.put()
return StringMessage(
message='Successfully added {}.'.format(request.saying))
@endpoints.method(request_message=NEW_GAME_REQUEST,
response_message=GameForm,
path='game',
name='new_game',
http_method='POST')
def new_game(self, request):
"""Start a 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.sayer_category,
request.num_hints)
except ValueError:
raise endpoints.BadRequestException(
'Number of hints must be between 0 and 5')
return game.to_form("Good luck playing Who Says!")
@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 take a guess!')
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):
"""Make a move and return a game state with message."""
game = get_by_urlsafe(request.urlsafe_game_key, Game)
if game.status != 'NEW':
raise endpoints.ForbiddenException(
'Illegal action: Game is already over.')
if request.guess == game.who_says:
game.do_move()
return game.to_form('You win!')
else:
game.status = 'LOST'
game.put()
return game.to_form('You lost.')
@endpoints.method(response_message=ScoreForms,
path='scores',
name='get_scores',
http_method='GET')
def get_scores(self, request):
"""Return all Game scores."""
qResults = Game.query(Game.status == 'WON')
if not qResults:
raise endpoints.NotFoundException('Scores not found.')
return ScoreForms(scores=[game.to_score_report() for game in qResults])
@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):
"""Return all of an individual User's game scores."""
user = User.query(User.name == request.user_name).get()
if not user:
raise endpoints.NotFoundException(
'A User with that name does not exist!')
qResults = Game.query(Game.user == user.key)
return ScoreForms(scores=[game.to_score_report() for game in qResults])
@endpoints.method(response_message=StringMessage,
path='games/averagepoints',
name='get_average_game_points',
http_method='GET')
def get_average_game_points(self, request):
"""Return average game points."""
avePoints = memcache.get(MEMCACHE_AVE_PTS_PER_GAME)
if not avePoints:
avePoints = 'Average points are not available.'
return StringMessage(message=avePoints)
@endpoints.method(request_message=USER_REQUEST,
response_message=GameForms,
path='games/user/{user_name}',
name='get_user_games',
http_method='GET')
def get_user_games(self, request):
"""Return all of an individual User's games."""
user = User.query(User.name == request.user_name).get()
if not user:
raise endpoints.NotFoundException(
'A User with that name does not exist!')
qResults = Game.query(Game.user == user.key, Game.status == 'NEW')
if not qResults:
raise endpoints.NotFoundException(
'There are no user games in progress.')
return GameForms(games=[game.to_form('Game in progress.')
for game in qResults])
@endpoints.method(request_message=GET_GAME_REQUEST,
response_message=StringMessage,
path='game/cancel/{urlsafe_game_key}',
name='cancel_game',
http_method='PUT')
def cancel_game(self, request):
"""Set the game status to cancelled."""
game = get_by_urlsafe(request.urlsafe_game_key, Game)
if game:
if game.status != 'NEW':
return StringMessage(message='Game already over or cancelled.')
game.status = 'CANCELLED'
game.put()
return StringMessage(message='Game cancelled!')
else:
raise endpoints.NotFoundException('Game not found!')
@endpoints.method(request_message=HIGH_SCORE_REQUEST,
response_message=GameHighScores,
path='games/highscores',
name='get_high_scores',
http_method='GET')
def get_high_scores(self, request):
"""Return game high scores in descending order."""
if request.number_of_results:
highScores = Game.query(Game.status == 'WON').order(
-Game.points).fetch(request.number_of_results)
else:
highScores = Game.query(Game.status == 'WON').order(-Game.points)
if not highScores:
raise endpoints.NotFoundException('Scores not found.')
return GameHighScores(high_scores=[game.to_score_report()
for game in highScores])
@endpoints.method(response_message=Rankings,
path='users/rankings',
name='get_user_rankings',
http_method='GET')
def get_user_rankings(self, request):
"""Return all users' high scores in descending order."""
userRankings = User.query(
User.points_earned > 0).order(-User.points_earned)
if not userRankings:
raise endpoints.NotFoundException('Rankings not found.')
return Rankings(rankings=[user.to_ranking() for user in userRankings])
@endpoints.method(response_message=Analysis,
path='games/analysis',
name='get_game_analysis',
http_method='GET')
def get_game_analysis(self, request):
"""Return history of in-game choices."""
games = Game.query().order(Game.user)
if not games:
raise endpoints.NotFoundException('Games not found.')
return Analysis(analysis=[game.to_game_analysis() for game in games])
@staticmethod
def _cache_average_game_points():
"""Populates memcache with average points won per game."""
games = Game.query(Game.status == 'WON').fetch()
if games:
count = len(games)
total_points = sum([game.points for game in games])
average = float(total_points) / count
memcache.set(MEMCACHE_AVE_PTS_PER_GAME,
'Ave pts won per game is {:.2f}'.format(average))
APPLICATION = endpoints.api_server([WhoSaysApi])