Skip to content

Commit

Permalink
Merge branch 'master' into wsh/standard-guestbook-sans-objectify
Browse files Browse the repository at this point in the history
  • Loading branch information
wsh authored Oct 26, 2016
2 parents dee5c71 + 237e3aa commit 48473a5
Show file tree
Hide file tree
Showing 62 changed files with 2,150 additions and 96 deletions.
2 changes: 1 addition & 1 deletion appengine/cloudsql/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.4</version>
<version>6.0.5</version>
</dependency>
<!-- Parent POM defines ${appengine.sdk.version} (updates frequently). -->
<dependency>
Expand Down
4 changes: 2 additions & 2 deletions appengine/endpoints-frameworks-v2/backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<endpoints.framework.version>2.0.0-beta.7</endpoints.framework.version>
<endpoints.management.version>1.0.0-beta.7</endpoints.management.version>
<endpoints.framework.version>2.0.0-beta.8</endpoints.framework.version>
<endpoints.management.version>1.0.0-beta.10</endpoints.management.version>

<endpoints.project.id>YOUR_PROJECT_ID</endpoints.project.id>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.3</version>
<version>2.8.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.3</version>
<version>2.8.4</version>
</dependency>

<!-- Test Dependencies -->
Expand Down
2 changes: 1 addition & 1 deletion appengine/firebase-tictactoe/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<groupId>com.example.appengine</groupId>
<artifactId>appengine-firebase</artifactId>
<artifactId>appengine-firebase-tictactoe</artifactId>
<parent>
<groupId>com.google.cloud</groupId>
<artifactId>doc-samples</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)
UserService userService = UserServiceFactory.getUserService();
String currentUserId = userService.getCurrentUser().getUserId();

// TODO(you): In practice, first validate that the user has permission to delete the Game
game.deleteChannel(currentUserId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.example.appengine.firetactoe;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.ByteArrayContent;
Expand All @@ -31,6 +32,7 @@

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
Expand All @@ -46,16 +48,18 @@
*/
public class FirebaseChannel {
private static final String FIREBASE_SNIPPET_PATH = "WEB-INF/view/firebase_config.jspf";
static InputStream firebaseConfigStream = null;
private static final Collection FIREBASE_SCOPES = Arrays.asList(
"https://www.googleapis.com/auth/firebase.database",
"https://www.googleapis.com/auth/userinfo.email"
);
private static final String IDENTITY_ENDPOINT =
"https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit";
static final HttpTransport HTTP_TRANSPORT = new UrlFetchTransport();

private String firebaseDbUrl;
private GoogleCredential credential;
// Keep this a package-private member variable, so that it can be mocked for unit tests
HttpTransport httpTransport;

private static FirebaseChannel instance;

Expand All @@ -79,11 +83,17 @@ public static FirebaseChannel getInstance() {
*/
private FirebaseChannel() {
try {
// This variables exist primarily so it can be stubbed out in unit tests.
if (null == firebaseConfigStream) {
firebaseConfigStream = new FileInputStream(FIREBASE_SNIPPET_PATH);
}

String firebaseSnippet = CharStreams.toString(new InputStreamReader(
new FileInputStream(FIREBASE_SNIPPET_PATH), StandardCharsets.UTF_8));
firebaseConfigStream, StandardCharsets.UTF_8));
firebaseDbUrl = parseFirebaseUrl(firebaseSnippet);

credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
httpTransport = UrlFetchTransport.getDefaultInstance();
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand All @@ -109,7 +119,7 @@ private static String parseFirebaseUrl(String firebaseSnippet) {
public void sendFirebaseMessage(String channelKey, Game game)
throws IOException {
// Make requests auth'ed using Application Default Credentials
HttpRequestFactory requestFactory = HTTP_TRANSPORT.createRequestFactory(credential);
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
GenericUrl url = new GenericUrl(
String.format("%s/channels/%s.json", firebaseDbUrl, channelKey));
HttpResponse response = null;
Expand Down Expand Up @@ -163,4 +173,63 @@ public String createFirebaseToken(Game game, String userId) {
AppIdentityService.SigningResult result = appIdentity.signForApp(toSign.getBytes());
return String.format("%s.%s", toSign, base64.encode(result.getSignature()));
}

// The following methods are to illustrate making various calls to Firebase from App Engine
// Standard

public HttpResponse firebasePut(String path, Object object) throws IOException {
// Make requests auth'ed using Application Default Credentials
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);

String json = new Gson().toJson(object);
GenericUrl url = new GenericUrl(path);

return requestFactory.buildPutRequest(
url, new ByteArrayContent("application/json", json.getBytes())).execute();
}

public HttpResponse firebasePatch(String path, Object object) throws IOException {
// Make requests auth'ed using Application Default Credentials
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);

String json = new Gson().toJson(object);
GenericUrl url = new GenericUrl(path);

return requestFactory.buildPatchRequest(
url, new ByteArrayContent("application/json", json.getBytes())).execute();
}

public HttpResponse firebasePost(String path, Object object) throws IOException {
// Make requests auth'ed using Application Default Credentials
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);

String json = new Gson().toJson(object);
GenericUrl url = new GenericUrl(path);

return requestFactory.buildPostRequest(
url, new ByteArrayContent("application/json", json.getBytes())).execute();
}

public HttpResponse firebaseGet(String path) throws IOException {
// Make requests auth'ed using Application Default Credentials
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);

GenericUrl url = new GenericUrl(path);

return requestFactory.buildGetRequest(url).execute();
}

public HttpResponse firebaseDelete(String path) throws IOException {
// Make requests auth'ed using Application Default Credentials
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);

GenericUrl url = new GenericUrl(path);

return requestFactory.buildDeleteRequest(url).execute();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public void setMoveX(boolean moveX) {
this.moveX = moveX;
}

//[START send_updates]
// [START send_updates]
public String getChannelKey(String userId) {
return userId + id;
}
Expand All @@ -130,7 +130,7 @@ public void sendUpdateToClients()
sendUpdateToUser(userX);
sendUpdateToUser(userO);
}
//[END send_updates]
// [END send_updates]

public void checkWin() {
final Pattern[] wins;
Expand All @@ -152,7 +152,6 @@ public void checkWin() {
}
}

//[START make_move]
public boolean makeMove(int position, String userId) {
String currentMovePlayer;
char value;
Expand Down Expand Up @@ -181,5 +180,4 @@ public boolean makeMove(int position, String userId) {

return false;
}
//[END make_move]
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)

int cell = new Integer(request.getParameter("cell"));
if (!game.makeMove(cell, currentUserId)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.sendError(HttpServletResponse.SC_FORBIDDEN);
} else {
ofy.save().entity(game).now();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.example.appengine.firetactoe;

import com.googlecode.objectify.NotFoundException;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

Expand All @@ -32,19 +31,10 @@ public class OpenedServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// TODO(you): In practice, you should validate the user has permission to post to the given Game
String gameId = request.getParameter("gameKey");
Objectify ofy = ObjectifyService.ofy();
try {
Game game = ofy.load().type(Game.class).id(gameId).safe();
if (gameId != null && request.getUserPrincipal() != null) {
game.sendUpdateToClients();
response.setContentType("text/plain");
response.getWriter().println("ok");
} else {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
} catch (NotFoundException e) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
Game game = ofy.load().type(Game.class).id(gameId).safe();
game.sendUpdateToClients();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.example.appengine.firetactoe;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gson.Gson;
import com.googlecode.objectify.Objectify;
Expand Down Expand Up @@ -60,20 +59,18 @@ private String getGameUriWithGameParam(HttpServletRequest request, String gameKe
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final UserService userService = UserServiceFactory.getUserService();
String gameKey = request.getParameter("gameKey");
if (userService.getCurrentUser() == null) {
response.getWriter().println("<p>Please <a href=\"" + userService.createLoginURL(
getGameUriWithGameParam(request, gameKey)) + "\">sign in</a>.</p>");
return;
}

// 1. Create or fetch a Game object from the datastore
Objectify ofy = ObjectifyService.ofy();
Game game = null;
String userId = userService.getCurrentUser().getUserId();
String userId = UserServiceFactory.getUserService().getCurrentUser().getUserId();
if (gameKey != null) {
game = ofy.load().type(Game.class).id(gameKey).safe();
game = ofy.load().type(Game.class).id(gameKey).now();
if (null == game) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (game.getUserO() == null && !userId.equals(game.getUserX())) {
game.setUserO(userId);
}
Expand All @@ -91,6 +88,7 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)

// 3. Inject a secure token into the client, so it can get game updates

// [START pass_token]
// The 'Game' object exposes a method which creates a unique string based on the game's key
// and the user's id.
String token = FirebaseChannel.getInstance().createFirebaseToken(game, userId);
Expand All @@ -102,6 +100,7 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
request.setAttribute("channel_id", game.getChannelKey(userId));
request.setAttribute("initial_message", new Gson().toJson(game));
request.setAttribute("game_link", getGameUriWithGameParam(request, gameKey));
getServletContext().getRequestDispatcher("/WEB-INF/view/index.jsp").forward(request, response);
request.getRequestDispatcher("/WEB-INF/view/index.jsp").forward(request, response);
// [END pass_token]
}
}
39 changes: 20 additions & 19 deletions appengine/firebase-tictactoe/src/main/webapp/WEB-INF/view/index.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<%@ include file="firebase_config.jspf" %>
<link rel="stylesheet" type="text/css" href="static/main.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
Expand All @@ -28,30 +29,30 @@
</script>
</head>
<body>
<div id='display-area' class="waiting">
<div id="display-area" class="waiting">
<h2>Firebase-enabled Tic Tac Toe</h2>
<div id='other-player'>
<div id="other-player">
Waiting for another player to join.<br>
Send them this link to play:<br>
<div id='game-link'><a href='<%= request.getAttribute("game_link") %>'><%= request.getAttribute("game_link") %></a></div>
<div id="game-link"><a href="<%= request.getAttribute("game_link") %>"><%= request.getAttribute("game_link") %></a></div>
</div>
<div id='your-move'>Your move! Click a square to place your piece.</div>
<div id='their-move'>Waiting for other player to move...</div>
<div id='you-won'>You won this game!</div>
<div id='you-lost'>You lost this game.</div>
<div id='board'>
<div class='t l cell' id='0'></div>
<div class='t c cell' id='1'></div>
<div class='t r cell' id='2'></div>
<div class='m l cell' id='3'></div>
<div class='m c cell' id='4'></div>
<div class='m r cell' id='5'></div>
<div class='b l cell' id='6'></div>
<div class='b c cell' id='7'></div>
<div class='b r cell' id='8'></div>
<div id="your-move">Your move! Click a square to place your piece.</div>
<div id="their-move">Waiting for other player to move...</div>
<div id="you-won">You won this game!</div>
<div id="you-lost">You lost this game.</div>
<div id="board">
<div class="t l cell" id="0"></div>
<div class="t c cell" id="1"></div>
<div class="t r cell" id="2"></div>
<div class="m l cell" id="3"></div>
<div class="m c cell" id="4"></div>
<div class="m r cell" id="5"></div>
<div class="b l cell" id="6"></div>
<div class="b c cell" id="7"></div>
<div class="b r cell" id="8"></div>
</div>
<div id='this-game' float='top'>
Quick link to this game: <span id='this-game-link'><a href='<%= request.getAttribute("game_link") %>'><%= request.getAttribute("game_link") %></a></span>
<div id="this-game" float="top">
Quick link to this game: <span id="this-game-link"><a href="<%= request.getAttribute("game_link") %>"><%= request.getAttribute("game_link") %></a></span>
</div>
</div>
</body>
Expand Down
9 changes: 9 additions & 0 deletions appengine/firebase-tictactoe/src/main/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<welcome-file-list>
<welcome-file>index</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>entire-app</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<servlet>
<servlet-name>TicTacToeServlet</servlet-name>
<servlet-class>com.example.appengine.firetactoe.TicTacToeServlet</servlet-class>
Expand Down
Loading

0 comments on commit 48473a5

Please sign in to comment.