From afc5ed33237383303bbf00c3da8eb9949167ed55 Mon Sep 17 00:00:00 2001 From: Ryan Patrick Date: Sat, 1 Aug 2020 01:32:13 +0000 Subject: [PATCH] Adds the following feature. --- src/main/java/shef/data/User.java | 15 +- .../java/shef/servlets/FollowersServlet.java | 92 ++++ .../java/shef/servlets/FollowingServlet.java | 150 +++++++ .../servlets/TestDisplayRecipesServlet.java | 60 --- src/main/java/shef/servlets/UserServlet.java | 17 +- src/main/webapp/profile-page-following.html | 410 ++++++++++++++++++ src/main/webapp/profile-page.html | 328 ++------------ src/main/webapp/quiz.html | 4 +- src/main/webapp/script.js | 75 ++++ 9 files changed, 796 insertions(+), 355 deletions(-) create mode 100644 src/main/java/shef/servlets/FollowersServlet.java create mode 100644 src/main/java/shef/servlets/FollowingServlet.java delete mode 100644 src/main/java/shef/servlets/TestDisplayRecipesServlet.java create mode 100644 src/main/webapp/profile-page-following.html diff --git a/src/main/java/shef/data/User.java b/src/main/java/shef/data/User.java index bf31d4c..2fe03a7 100644 --- a/src/main/java/shef/data/User.java +++ b/src/main/java/shef/data/User.java @@ -28,8 +28,12 @@ public class User { private String bio; private String profilePageUrl; private boolean isCurrentUser; + private boolean isFollowedByCurrentUser; + private long followingCount; + private long followersCount; - public User(String key, String email, String username, String location, String profilePicKey, String bio, boolean isCurrentUser) { + + public User(String key, String email, String username, String location, String profilePicKey, String bio, boolean isCurrentUser, boolean isFollowedByCurrentUser, long followingCount, long followersCount) { this.key = key; this.email = email; this.username = username; @@ -37,5 +41,14 @@ public User(String key, String email, String username, String location, String p this.profilePicKey = profilePicKey; this.bio = bio; this.isCurrentUser = isCurrentUser; + this.isFollowedByCurrentUser = isFollowedByCurrentUser; + this.followingCount = followingCount; + this.followersCount = followersCount; + } + + public User(String key, String username, String profilePicKey) { + this.key = key; + this.username = username; + this.profilePicKey = profilePicKey; } } diff --git a/src/main/java/shef/servlets/FollowersServlet.java b/src/main/java/shef/servlets/FollowersServlet.java new file mode 100644 index 0000000..f00d0a4 --- /dev/null +++ b/src/main/java/shef/servlets/FollowersServlet.java @@ -0,0 +1,92 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shef.servlets; + +import shef.data.User; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.LinkedList; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import com.google.gson.Gson; +import com.google.appengine.api.users.UserService; +import com.google.appengine.api.users.UserServiceFactory; +import com.google.appengine.api.datastore.DatastoreService; +import com.google.appengine.api.datastore.DatastoreServiceFactory; +import com.google.appengine.api.datastore.Entity; +import com.google.appengine.api.datastore.PreparedQuery; +import com.google.appengine.api.datastore.Query; +import com.google.appengine.api.datastore.Key; +import com.google.appengine.api.datastore.KeyFactory; +import com.google.appengine.api.datastore.EntityNotFoundException; + +/** Servlet that retrieves follower information. */ +@WebServlet("/followers") +public class FollowersServlet extends HttpServlet { + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + UserService userService = UserServiceFactory.getUserService(); + DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); + + // Get the key from the query string. + String userKeyString = request.getParameter("key"); + Key userKey; + if(userKeyString == null && userService.isUserLoggedIn()) { + userKey = KeyFactory.createKey("User", userService.getCurrentUser().getUserId()); + } else { + userKey = KeyFactory.stringToKey(userKeyString); + } + + List followers; + try { + Entity userEntity = datastore.get(userKey); + followers = (List) userEntity.getProperty("followers"); + } catch(EntityNotFoundException e) { + // User doesn't exist. + e.printStackTrace(); + return; + } + + + LinkedList followerUsers = new LinkedList(); + + if(followers != null) { + for(String keyString : followers) { + try { + Key key = KeyFactory.stringToKey(keyString); + Entity userEntity = datastore.get(key); + String name = (String) userEntity.getProperty("username"); + String profilePicKey = (String) userEntity.getProperty("profile-pic"); + + User user = new User(keyString, name, profilePicKey); + followerUsers.add(user); + } catch(EntityNotFoundException e) { + e.printStackTrace(); + return; + } + } + } + + // Convert to JSON and send it as the response. + Gson gson = new Gson(); + + response.setContentType("application/json"); + response.getWriter().println(gson.toJson(followerUsers)); + } +} \ No newline at end of file diff --git a/src/main/java/shef/servlets/FollowingServlet.java b/src/main/java/shef/servlets/FollowingServlet.java new file mode 100644 index 0000000..32eae86 --- /dev/null +++ b/src/main/java/shef/servlets/FollowingServlet.java @@ -0,0 +1,150 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shef.servlets; + +import shef.data.User; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.LinkedList; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import com.google.gson.Gson; +import com.google.appengine.api.users.UserService; +import com.google.appengine.api.users.UserServiceFactory; +import com.google.appengine.api.datastore.DatastoreService; +import com.google.appengine.api.datastore.DatastoreServiceFactory; +import com.google.appengine.api.datastore.Entity; +import com.google.appengine.api.datastore.PreparedQuery; +import com.google.appengine.api.datastore.Query; +import com.google.appengine.api.datastore.Key; +import com.google.appengine.api.datastore.KeyFactory; +import com.google.appengine.api.datastore.EntityNotFoundException; + +/** Servlet that updates and retrieves following information. */ +@WebServlet("/following") +public class FollowingServlet extends HttpServlet { + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + UserService userService = UserServiceFactory.getUserService(); + DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); + + // Get the key from the query string. + String userKeyString = request.getParameter("key"); + Key userKey; + if(userKeyString == null && userService.isUserLoggedIn()) { + userKey = KeyFactory.createKey("User", userService.getCurrentUser().getUserId()); + } else { + userKey = KeyFactory.stringToKey(userKeyString); + } + + List following; + try { + Entity userEntity = datastore.get(userKey); + following = (List) userEntity.getProperty("following"); + } catch(EntityNotFoundException e) { + // User doesn't exist. + e.printStackTrace(); + return; + } + + LinkedList usersFollowed = new LinkedList(); + + if(following != null) { + for(String keyString : following) { + try { + Key key = KeyFactory.stringToKey(keyString); + Entity userEntity = datastore.get(key); + String name = (String) userEntity.getProperty("username"); + String profilePicKey = (String) userEntity.getProperty("profile-pic"); + + User user = new User(keyString, name, profilePicKey); + usersFollowed.add(user); + } catch(EntityNotFoundException e) { + e.printStackTrace(); + return; + } + } + } + + // Convert to JSON and send it as the response. + Gson gson = new Gson(); + + response.setContentType("application/json"); + response.getWriter().println(gson.toJson(usersFollowed)); + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + UserService userService = UserServiceFactory.getUserService(); + DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); + + // Retrieve the key of the user to follow. + String userToFollowKeyString = request.getParameter("user"); + Key userToFollowKey = KeyFactory.stringToKey(userToFollowKeyString); + Entity userToFollow; + + // Get the current user's key. + Key currentUserKey = KeyFactory.createKey("User", userService.getCurrentUser().getUserId()); + String currentUserKeyString = KeyFactory.keyToString(currentUserKey); + Entity currentUser; + + boolean unfollow = Boolean.parseBoolean(request.getParameter("unfollow")); + + try { + // Retrieve the current user from Datastore and add to their following list. + currentUser = datastore.get(currentUserKey); + ArrayList following = (ArrayList) currentUser.getProperty("following"); + // Retrieve the user to follow, and add the current user as a follow + userToFollow = datastore.get(userToFollowKey); + ArrayList followers = (ArrayList) userToFollow.getProperty("followers"); + + if(unfollow) { + if(following != null) { + following.remove(userToFollowKeyString); + } + if(followers != null) { + followers.remove(currentUserKeyString); + } + } else { + if(following == null) { + following = new ArrayList(); + } + if(followers == null) { + followers = new ArrayList(); + } + following.add(userToFollowKeyString); + followers.add(currentUserKeyString); + currentUser.setProperty("following", following); + userToFollow.setProperty("followers", followers); + } + + } catch(EntityNotFoundException e) { + /** This means the current user, for whom we're trying to set following for, doesn't exist. + * This should never happen. If it does, multiple things have gone seriously wrong. + */ + e.printStackTrace(); + return; + } + + // Store the user in Datastore. + datastore.put(currentUser); + datastore.put(userToFollow); + response.sendRedirect("/profile-page.html?key=" + userToFollowKeyString); + } +} diff --git a/src/main/java/shef/servlets/TestDisplayRecipesServlet.java b/src/main/java/shef/servlets/TestDisplayRecipesServlet.java deleted file mode 100644 index fcb76b9..0000000 --- a/src/main/java/shef/servlets/TestDisplayRecipesServlet.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package shef.servlets; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import shef.data.TestRecipe; -import com.google.appengine.api.datastore.DatastoreService; -import com.google.appengine.api.datastore.DatastoreServiceFactory; -import com.google.appengine.api.datastore.Entity; -import com.google.appengine.api.datastore.PreparedQuery; -import com.google.appengine.api.datastore.Query; -import com.google.appengine.api.datastore.Query.SortDirection; -import com.google.gson.Gson; -import java.io.IOException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** Servlet responsible for displaying recipes. */ -@WebServlet("/display-recipes") -public class TestDisplayRecipesServlet extends HttpServlet { - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - Query query = new Query("Recipe").addSort("timestamp", SortDirection.DESCENDING); - - DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); - PreparedQuery results = datastore.prepare(query); - - List testRecipes = new LinkedList<>(); - for (Entity entity : results.asIterable()) { - long id = entity.getKey().getId(); - ArrayList searchStrings = (ArrayList) entity.getProperty("search-strings"); - long timestamp = (long) entity.getProperty("timestamp"); - - TestRecipe testRecipe = new TestRecipe(id, searchStrings, timestamp); - testRecipes.add(testRecipe); - } - - Gson gson = new Gson(); - - response.setContentType("application/json;"); - response.getWriter().println(gson.toJson(testRecipes)); - } -} diff --git a/src/main/java/shef/servlets/UserServlet.java b/src/main/java/shef/servlets/UserServlet.java index b40c44d..64bb478 100644 --- a/src/main/java/shef/servlets/UserServlet.java +++ b/src/main/java/shef/servlets/UserServlet.java @@ -66,12 +66,27 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro String location = (String) userEntity.getProperty("location"); String profilePicKey = (String) userEntity.getProperty("profile-pic"); String bio = (String) userEntity.getProperty("bio"); + List following = (List) userEntity.getProperty("following"); + List followers = (List) userEntity.getProperty("followers"); + + long followingCount = 0; + long followersCount = 0; + boolean isFollowedByCurrentUser = false; + + if(following != null) { + followingCount = following.size(); + } + if(followers != null) { + followersCount = followers.size(); + String currentUserKeyString = KeyFactory.createKeyString("User", userService.getCurrentUser().getUserId()); + isFollowedByCurrentUser = followers.contains(currentUserKeyString); + } // Since we chose to store the id as a string in Datastore, it is referred to as "name". String id = (String) userKey.getName(); boolean isCurrentUser = id.equals(userService.getCurrentUser().getUserId()); - User user = new User(keyString, email, username, location, profilePicKey, bio, isCurrentUser); + User user = new User(keyString, email, username, location, profilePicKey, bio, isCurrentUser, isFollowedByCurrentUser, followingCount, followersCount); // Convert to JSON and send it as the response. Gson gson = new Gson(); diff --git a/src/main/webapp/profile-page-following.html b/src/main/webapp/profile-page-following.html new file mode 100644 index 0000000..aa066c9 --- /dev/null +++ b/src/main/webapp/profile-page-following.html @@ -0,0 +1,410 @@ + + + + + + + + + + + + shef + + + + + + + +
+
+
+ ... +
+
+
+
+
+

67

+

Recipes

+
+
+
+
+
+
+
+
+

3.8k

+

Followers

+
+
+
+
+
+
+
+
+

93

+

Following

+
+
+
+
+
+
+
+
+ +

+

+
+

+
+
+ +
+
+ + +
+ + +
+ + +
+ + +
+ +
+
+
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 11 +
  • +
  • + + + + + 70 +
  • +
  • + + + + 1.6k +
  • +
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 18 +
  • +
  • + + + + + 40 +
  • +
  • + + + + 685 +
  • +
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 11 +
  • +
  • + + + + + 45 +
  • +
  • + + + + 1.4k +
  • +
+
+
+
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 12 +
  • +
  • + + + + + 55 +
  • +
  • + + + + 2.3k +
  • +
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 15 +
  • +
  • + + + + + 60 +
  • +
  • + + + + 1.7k +
  • +
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 9 +
  • +
  • + + + + + 30 +
  • +
  • + + + + 927 +
  • +
+
+
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 11 +
  • +
  • + + + + + 70 +
  • +
  • + + + + 1.6k +
  • +
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 18 +
  • +
  • + + + + + 40 +
  • +
  • + + + + 685 +
  • +
+
+
+
+
+ ... +
+ +
    +
  • + + + + + + 11 +
  • +
  • + + + + + 45 +
  • +
  • + + + + 1.4k +
  • +
+
+
+
+
+
+
+ + + + + + diff --git a/src/main/webapp/profile-page.html b/src/main/webapp/profile-page.html index 06b3fc8..80fe8a8 100644 --- a/src/main/webapp/profile-page.html +++ b/src/main/webapp/profile-page.html @@ -33,7 +33,7 @@ shef - +