Skip to content
This repository was archived by the owner on Jul 24, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/main/java/shef/data/Recipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Iterator;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EmbeddedEntity;
import com.google.appengine.api.datastore.KeyFactory;

/** Stores a recipe's data. */
public class Recipe {
Expand All @@ -38,6 +39,7 @@ public class Recipe {
private List<Step> steps;
private Set<SpinOff> spinOffs;
private long timestamp;
private boolean hasLiveStream;

/**
* Copy constructor called when creating spin-offs.
Expand Down Expand Up @@ -65,11 +67,14 @@ public Recipe(String name, String description, Set<String> tags, Set<String> ing

/** Creates a Recipe from a Datastore entity. */
public Recipe(Entity recipeEntity) {
this.key = KeyFactory.keyToString(recipeEntity.getKey());
this.name = (String) recipeEntity.getProperty("name");
this.user = (String) recipeEntity.getProperty("user");
this.description = (String) recipeEntity.getProperty("description");
this.tags = getTagsFromEntity((Collection<EmbeddedEntity>) recipeEntity.getProperty("tags"));
this.ingredients = getIngredientsFromEntity((Collection<EmbeddedEntity>) recipeEntity.getProperty("ingredients"));
this.steps = getStepsFromEntity((Collection<EmbeddedEntity>) recipeEntity.getProperty("steps"));
this.hasLiveStream = (boolean) recipeEntity.getProperty("has-live-stream");
this.timestamp = (long) recipeEntity.getProperty("timestamp");
}

Expand Down
25 changes: 1 addition & 24 deletions src/main/java/shef/servlets/DisplayRecipesServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,35 +53,12 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro

List<Recipe> recipes = new ArrayList<>();
for (Entity entity : results.asIterable()) {
recipes.add(entityToRecipe(entity));
recipes.add(new Recipe(entity));
}

Gson gson = new Gson();

response.setContentType("application/json;");
response.getWriter().println(gson.toJson(recipes));
}

/** Converts a Datastore entity into a Recipe. */
public Recipe entityToRecipe(Entity recipeEntity) {
String key = KeyFactory.keyToString(recipeEntity.getKey());
String user = (String) recipeEntity.getProperty("user");
String name = (String) recipeEntity.getProperty("name");
String description = (String) recipeEntity.getProperty("description");
LinkedHashSet<String> tags = new LinkedHashSet<>((LinkedList<String>) (LinkedList<?>) getDataAsList(recipeEntity.getProperty("tags"), "tag"));
LinkedHashSet<String> ingredients = new LinkedHashSet<>((LinkedList<String>) (LinkedList<?>) getDataAsList(recipeEntity.getProperty("ingredients"), "ingredient"));
LinkedList<Step> steps = (LinkedList<Step>) (LinkedList<?>) getDataAsList(recipeEntity.getProperty("steps"), "step");
long timestamp = (long) recipeEntity.getProperty("timestamp");
return new Recipe(key, name, user, description, tags, ingredients, steps, timestamp);
}

/** Gets a list of Recipe parameters from a Datastore property. */
public Collection<Object> getDataAsList(Object propertiesObject, String field) {
Collection<EmbeddedEntity> properties = (Collection<EmbeddedEntity>) propertiesObject;
Collection<Object> dataAsList = new LinkedList<>();
for (EmbeddedEntity property : properties) {
dataAsList.add(property.getProperty(field));
}
return dataAsList;
}
}
26 changes: 26 additions & 0 deletions src/main/java/shef/servlets/NewLiveStreamServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
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.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
Expand Down Expand Up @@ -53,6 +60,25 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(liveStreamEntity);

/* Get the recipe that the user wishes to associate the live stream
with. If the recipe already has an associated live stream, throw an error.
Else, set the recipe's hasLiveStream field to true. hasLiveStream is used
to determine whether and how the recipe shows on the recipe and live stream feeds. */
Query query = new Query("Recipe");
Key recipeKey = KeyFactory.stringToKey(request.getParameter("recipe-key"));
Filter recipeKeyFilter = new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.EQUAL, recipeKey);
query.setFilter(recipeKeyFilter);
PreparedQuery results = datastore.prepare(query);
for (Entity entity : results.asIterable()) {
boolean hasLiveStream = (boolean) entity.getProperty("has-live-stream");
if (hasLiveStream) {
System.err.println("This event already has a live stream associated with it. Each recipe can only be associated with one live stream.");
} else {
entity.setProperty("has-live-stream", true);
datastore.put(entity);
}
}

response.sendRedirect("/create-live-stream.html");
}
}
22 changes: 20 additions & 2 deletions src/main/java/shef/servlets/NewRecipeServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gson.Gson;
import java.util.Collection;
import java.util.List;
Expand All @@ -40,13 +42,15 @@
public class NewRecipeServlet extends HttpServlet {

private DatastoreService datastore;
private UserService userService;
private final String TAG = "tag";
private final String INGREDIENT = "ingredient";
private final String STEP = "step";

@Override
public void init() {
datastore = DatastoreServiceFactory.getDatastoreService();
userService = UserServiceFactory.getUserService();
}

/** When a spin-off is created, this GET request gets the original recipe's data. */
Expand Down Expand Up @@ -75,7 +79,12 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr
Collection<EmbeddedEntity> tags = getParameters(request, TAG, searchStrings);
Collection<EmbeddedEntity> ingredients = getParameters(request, INGREDIENT, searchStrings);
Collection<EmbeddedEntity> steps = getParameters(request, STEP, null);
int likes = Integer.parseInt(request.getParameter("likes"));
int likes;
try {
likes = Integer.parseInt(request.getParameter("likes"));
} catch (NumberFormatException e) {
likes = 0;
}
long timestamp = System.currentTimeMillis();

Entity recipe = new Entity("Recipe");
Expand All @@ -85,6 +94,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr
recipe.setProperty("ingredients", ingredients);
recipe.setProperty("steps", steps);
recipe.setProperty("search-strings", new ArrayList<String>(searchStrings));
recipe.setProperty("has-live-stream", false); // A newly created recipe does not have an associated live stream.
recipe.setProperty("timestamp", timestamp);
// Temporary if statement, can be removed once user service is fully integrated with recipe creation.
// Without this if statement for the time being, the servlet crashes.
Expand All @@ -95,9 +105,17 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr
recipe.setProperty("user", userKeyString);
}
recipe.setProperty("likes", likes);

// Add property for the key string of the current user.
if (userService != null && userService.getCurrentUser() != null) {
String id = userService.getCurrentUser().getUserId();
Key userKey = KeyFactory.createKey("User", id);
String userKeyString = KeyFactory.keyToString(userKey);
recipe.setProperty("user", userKeyString);
}
datastore.put(recipe);

response.sendRedirect("/edit-recipe.html");
response.sendRedirect("/recipe.html");
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/main/webapp/browse-recipes.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ <h1 class="display-4">Browse Recipes</h1>
<button onclick="getRecipes('foryou')">For You</button>
<button onclick="getRecipes('trending')">Trending</button>
</div>
<div id="results"></div>
<div id="recipe-grid"></div>
</div>
</body>
</html>
88 changes: 44 additions & 44 deletions src/main/webapp/create-recipe-blank.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@
</head>

<body class="page-container" onload="protectPage(); navBarSetup();">
<template>
<span>
<svg class="bi bi-plus-circle bootstrap-icon" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 3.5a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5H4a.5.5 0 0 1 0-1h3.5V4a.5.5 0 0 1 .5-.5z"/>
<path fill-rule="evenodd" d="M7.5 8a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1H8.5V12a.5.5 0 0 1-1 0V8z"/>
<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
</svg>
</span>
</template>

<template>
<span>
<svg class="bootstrap-icon" viewBox="0 0 16 16" class="bi bi-dash-circle" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path fill-rule="evenodd" d="M3.5 8a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1H4a.5.5 0 0 1-.5-.5z"/>
</svg>
</span>
</template>

<!--Nav bar-->
<div id="nav-placeholder"></div>
<script>
Expand All @@ -53,68 +72,49 @@ <h1 class="display-4">So you want to create a recipe?</h1>
<div class="med-sep">
<div class="row">
<div class="col-sm-6 col-md-6 col-lg-6 text-left">
<form>
<form action="/new-recipe" method="POST">
<h2>Basic Info</h2>
<div class="form-group small-sep">
<label for="dishNameInput">1. What’s your dish called? *</label>
<input type="text" class="form-control" id="dishNameInput" placeholder="Name of your dish...">
<input type="text" name="name" class="form-control" id="dishNameInput" placeholder="Name of your dish...">
</div>
<div class="form-group small-sep">
<label for="categoriesInput">2. What categories does it fit into? *</label>
<input type="text" class="form-control" id="categoriesInput" placeholder="Start typing for suggestions...">
<label for="timeInput">2. How long does it take to make, in minutes? *</label>
<input type="number" name="time" class="form-control" id="timeInput" placeholder="...">
</div>
<div class="form-group small-sep">
<label for="timeInput">3. How long does it take to make, in minutes? *</label>
<input type="number" class="form-control" id="timeInput" placeholder="...">
</div>
<label for="servingsInput">3. How many servings does it make? *</label>
<input type="number" name="servings" class="form-control" id="servingsInput" placeholder="...">
</div>
<div class="form-group small-sep">
<label for="servingsInput">4. How many servings does it make? *</label>
<input type="number" class="form-control" id="servingsInput" placeholder="...">
<label>4. What tags apply to this recipe?</label>
<div id="Tags">
<parameter-input name="Tag" index="0" id="Tag0"></parameter-input>
</div>
</div>
<div class="med-sep">
<h2>Ingredients</h2>
<div class="form-group small-sep">
<input type="text" class="form-control" id="ingredientInput" placeholder="Enter an ingredient (with quantity)...">
</div>
<div class="small-sep">
<svg class="bi bi-plus-circle bootstrap-icon" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 3.5a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5H4a.5.5 0 0 1 0-1h3.5V4a.5.5 0 0 1 .5-.5z"/>
<path fill-rule="evenodd" d="M7.5 8a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1H8.5V12a.5.5 0 0 1-1 0V8z"/>
<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
</svg>
<h2>Description</h2>
<div class="form-group">
<label for="descriptionTextArea">Give your recipe some more context.</label>
<textarea class="form-control" name="description" id="descriptionTextArea" placeholder="Tell us about your recipe..."></textarea>
</div>
</div>
<div class="med-sep">
<h2>Equipment</h2>
<div class="form-group small-sep">
<input type="text" class="form-control" id="ingredientInput" placeholder="Start typing for suggestions...">
</div>
<div class="small-sep">
<svg class="bi bi-plus-circle bootstrap-icon" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 3.5a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5H4a.5.5 0 0 1 0-1h3.5V4a.5.5 0 0 1 .5-.5z"/>
<path fill-rule="evenodd" d="M7.5 8a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1H8.5V12a.5.5 0 0 1-1 0V8z"/>
<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
</svg>
<h2>Ingredients</h2>
<div class="form-group small-sep" id="Ingredients">
<parameter-input name="Ingredient" index="0" id="Ingredient0"></parameter-input>
</div>
</div>
<div class="med-sep">
<h2>Steps</h2>
<div class="form-group small-sep">
<input type="text" class="form-control" id="ingredientInput" placeholder="Enter a step...">
</div>
<div class="small-sep">
<svg class="bi bi-plus-circle bootstrap-icon" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 3.5a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5H4a.5.5 0 0 1 0-1h3.5V4a.5.5 0 0 1 .5-.5z"/>
<path fill-rule="evenodd" d="M7.5 8a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1H8.5V12a.5.5 0 0 1-1 0V8z"/>
<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
</svg>
<h2>Equipment</h2>
<div class="form-group small-sep" id="Equipments">
<parameter-input name="Equipment" index="0" id="Equipment0"></parameter-input>
</div>
</div>
<div class="med-sep">
<h2>Description</h2>
<div class="form-group">
<label for="descriptionTextArea">Give your recipe some more context.</label>
<textarea class="form-control" id="descriptionTextArea" placeholder="Tell us about your recipe..."></textarea>
<h2>Steps</h2>
<div class="form-group small-sep" id="Steps">
<parameter-input name="Step" index="0" id="Step0"></parameter-input>
</div>
</div>
<div class="med-sep">
Expand Down Expand Up @@ -157,7 +157,7 @@ <h2>Sharing</h2>
</div>
</div>
</div>

<!-- Optional JavaScript -->
<!-- First Popper.js, then Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
Expand Down
6 changes: 6 additions & 0 deletions src/main/webapp/css/style.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading