From 8db99daace232afd9606650962eeb2b1438d6fa7 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Mon, 3 Aug 2020 01:10:37 +0000 Subject: [PATCH 1/3] Update RecipeFilter interface/implementing classes --- src/main/java/shef/data/ForYou.java | 9 +-- src/main/java/shef/data/RecipeFilter.java | 8 +-- src/main/java/shef/data/Trending.java | 3 +- .../servlets/TestDisplayRecipesServlet.java | 60 ------------------- 4 files changed, 8 insertions(+), 72 deletions(-) delete mode 100644 src/main/java/shef/servlets/TestDisplayRecipesServlet.java diff --git a/src/main/java/shef/data/ForYou.java b/src/main/java/shef/data/ForYou.java index 617871e..0e91284 100644 --- a/src/main/java/shef/data/ForYou.java +++ b/src/main/java/shef/data/ForYou.java @@ -35,6 +35,7 @@ public class ForYou implements RecipeFilter { private DatastoreService datastore; private static final List TEMP_PREFERENCES = new ArrayList<>(Arrays.asList("SPICY", "CHICKEN", "CHOCOLATE")); + private List preferences; private Set filters; public ForYou() { @@ -47,19 +48,15 @@ public ForYou() { * For now, returns recipes that match SPICY, CHICKEN, and CHOCOLATE, or that have more than 50 likes. * This is just a hard-coded example, and will change. */ public PreparedQuery getResults(Query query) { + preferences = getUserPreferences(); filters.add(new FilterPredicate("search-strings", FilterOperator.IN, TEMP_PREFERENCES)); filters.add(new FilterPredicate("likes", FilterOperator.GREATER_THAN_OR_EQUAL, 50)); query.setFilter(new CompositeFilter(CompositeFilterOperator.OR, filters)); return datastore.prepare(query); } - /** Helper method that adds a filter to the composite filter. */ - public Filter addFilter(CompositeFilter filters) { - throw new UnsupportedOperationException(); - } - /** Retrieves additional data from Datastore to be used in the filter. */ - public PreparedQuery getData(Query query) { + public List getUserData() { throw new UnsupportedOperationException(); } } diff --git a/src/main/java/shef/data/RecipeFilter.java b/src/main/java/shef/data/RecipeFilter.java index 4bf5ecf..00a6f7b 100644 --- a/src/main/java/shef/data/RecipeFilter.java +++ b/src/main/java/shef/data/RecipeFilter.java @@ -18,16 +18,14 @@ import com.google.appengine.api.datastore.Query.CompositeFilter; import com.google.appengine.api.datastore.Query.Filter; import com.google.appengine.api.datastore.PreparedQuery; +import java.util.List; public interface RecipeFilter { /** Returns a PreparedQuery of filtered Recipe entities. */ public PreparedQuery getResults(Query query); - /** Helper method that adds a filter to the composite filter. */ - public Filter addFilter(CompositeFilter filters); - - /** Retrieves additional data from Datastore to be used in the filter. */ - public PreparedQuery getData(Query query); + /** Retrieves user data from Datastore to be used in the filter. */ + public List getUserData(); } diff --git a/src/main/java/shef/data/Trending.java b/src/main/java/shef/data/Trending.java index 0592480..03f2c23 100644 --- a/src/main/java/shef/data/Trending.java +++ b/src/main/java/shef/data/Trending.java @@ -23,6 +23,7 @@ import com.google.appengine.api.datastore.Query.FilterPredicate; import com.google.appengine.api.datastore.Query.FilterOperator; import com.google.appengine.api.datastore.PreparedQuery; +import java.util.List; /** * Returns recipes that are currently popular. @@ -49,7 +50,7 @@ public Filter addFilter(CompositeFilter filters) { } /** Retrieves additional data from Datastore to be used in the filter. */ - public PreparedQuery getData(Query query) { + public List getUserData() { throw new UnsupportedOperationException(); } } 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)); - } -} From 92e0dee21dc62e5d39641a83addac75f5a3ac8c6 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Mon, 3 Aug 2020 02:18:00 +0000 Subject: [PATCH 2/3] fix key errors in recipe.html --- src/main/webapp/script.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index b611abd..864463a 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -896,9 +896,10 @@ function recipePageInit() { function getRecipeInfo() { var url = window.location.href; - var key = url.split('?')[1]; + var key = url.split('=')[1]; + console.log(key); - fetch('/new-recipe?' + key).then(response => response.json()).then(recipe => { + fetch('/new-recipe?key=' + key).then(response => response.json()).then(recipe => { document.getElementById('recipe-title').innerHTML = recipe.name; document.getElementById('recipe-description').innerHTML = recipe.description; displayTags(recipe.tags); From a81b498bda1c6898d8d164acee79d2f28c7b8251 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Mon, 3 Aug 2020 02:18:15 +0000 Subject: [PATCH 3/3] implement customized for you algorithm --- src/main/java/shef/data/ForYou.java | 37 ++++++++++++------- src/main/java/shef/data/Trending.java | 6 --- .../shef/servlets/BrowseRecipesServlet.java | 4 ++ .../java/shef/servlets/NewRecipeServlet.java | 2 +- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/main/java/shef/data/ForYou.java b/src/main/java/shef/data/ForYou.java index 0e91284..6eb2090 100644 --- a/src/main/java/shef/data/ForYou.java +++ b/src/main/java/shef/data/ForYou.java @@ -16,31 +16,29 @@ import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceFactory; -import javax.servlet.http.HttpServletRequest; import com.google.appengine.api.datastore.Query; -import com.google.appengine.api.datastore.Query.CompositeFilter; -import com.google.appengine.api.datastore.Query.CompositeFilterOperator; import com.google.appengine.api.datastore.Query.FilterPredicate; import com.google.appengine.api.datastore.Query.FilterOperator; import com.google.appengine.api.datastore.Query.Filter; import com.google.appengine.api.datastore.PreparedQuery; +import com.google.appengine.api.users.UserService; +import com.google.appengine.api.users.UserServiceFactory; +import com.google.appengine.api.datastore.Entity; +import com.google.appengine.api.datastore.Key; +import com.google.appengine.api.datastore.KeyFactory; import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.HashSet; -import java.util.Arrays; /** Defines the For You algorithm, which shows users recipes unique to their preferences. */ public class ForYou implements RecipeFilter { private DatastoreService datastore; - private static final List TEMP_PREFERENCES = new ArrayList<>(Arrays.asList("SPICY", "CHICKEN", "CHOCOLATE")); + private UserService userService; private List preferences; - private Set filters; public ForYou() { datastore = DatastoreServiceFactory.getDatastoreService(); - filters = new HashSet<>(); + userService = UserServiceFactory.getUserService(); } /** @@ -48,15 +46,26 @@ public ForYou() { * For now, returns recipes that match SPICY, CHICKEN, and CHOCOLATE, or that have more than 50 likes. * This is just a hard-coded example, and will change. */ public PreparedQuery getResults(Query query) { - preferences = getUserPreferences(); - filters.add(new FilterPredicate("search-strings", FilterOperator.IN, TEMP_PREFERENCES)); - filters.add(new FilterPredicate("likes", FilterOperator.GREATER_THAN_OR_EQUAL, 50)); - query.setFilter(new CompositeFilter(CompositeFilterOperator.OR, filters)); + preferences = getUserData(); + if (preferences == null) { + // If the user cannot be found, return null. + return null; + } + query.setFilter(new FilterPredicate("search-strings", FilterOperator.IN, preferences)); return datastore.prepare(query); } /** Retrieves additional data from Datastore to be used in the filter. */ public List getUserData() { - throw new UnsupportedOperationException(); + Entity user; + try { + user = datastore.get(KeyFactory.createKey("User", userService.getCurrentUser().getUserId())); + } catch(Exception e) { + // User could not be found. In this case, return null, which will cause the servlet to return trending recipes. + e.printStackTrace(); + return null; + } + List userPreferences = (List) user.getProperty("preferences"); + return userPreferences; } } diff --git a/src/main/java/shef/data/Trending.java b/src/main/java/shef/data/Trending.java index 03f2c23..f45eef2 100644 --- a/src/main/java/shef/data/Trending.java +++ b/src/main/java/shef/data/Trending.java @@ -14,7 +14,6 @@ package shef.data; -import javax.servlet.http.HttpServletRequest; import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.appengine.api.datastore.Query; @@ -44,11 +43,6 @@ public PreparedQuery getResults(Query query) { return datastore.prepare(query); } - /** Helper method that adds a filter to the composite filter. */ - public Filter addFilter(CompositeFilter filters) { - throw new UnsupportedOperationException(); - } - /** Retrieves additional data from Datastore to be used in the filter. */ public List getUserData() { throw new UnsupportedOperationException(); diff --git a/src/main/java/shef/servlets/BrowseRecipesServlet.java b/src/main/java/shef/servlets/BrowseRecipesServlet.java index 4a39527..ce5c713 100644 --- a/src/main/java/shef/servlets/BrowseRecipesServlet.java +++ b/src/main/java/shef/servlets/BrowseRecipesServlet.java @@ -59,6 +59,10 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro Query query = new Query("Recipe"); PreparedQuery recipeEntities = filter.getResults(query); + + // If the filter returns null, an error has occurred with UserService. + // In this case, show trending recipes. + recipeEntities = recipeEntities != null ? recipeEntities : new Trending().getResults(query); List recipes = new LinkedList<>(); for (Entity recipeEntity : recipeEntities.asIterable()) { diff --git a/src/main/java/shef/servlets/NewRecipeServlet.java b/src/main/java/shef/servlets/NewRecipeServlet.java index ee43642..3216339 100644 --- a/src/main/java/shef/servlets/NewRecipeServlet.java +++ b/src/main/java/shef/servlets/NewRecipeServlet.java @@ -94,7 +94,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr recipe.setProperty("likes", likes); datastore.put(recipe); - response.sendRedirect("/recipe.html"); + response.sendRedirect("/recipe.html?key=" + KeyFactory.keyToString(recipe.getKey())); } /**