Skip to content

Commit

Permalink
Merge pull request #103 from COS301-SE-2023/recipe-book-page
Browse files Browse the repository at this point in the history
Recipe book page
  • Loading branch information
SkulderLock authored Aug 1, 2023
2 parents 2366415 + 69a2ab9 commit fb4ab32
Show file tree
Hide file tree
Showing 37 changed files with 889 additions and 252 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,5 @@ out/
### VS Code ###
.vscode/
angular.json
package-lock.json
package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package fellowship.mealmaestro.controllers;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import fellowship.mealmaestro.models.MealModel;
import fellowship.mealmaestro.services.RecipeBookService;
import jakarta.validation.Valid;

import java.util.List;

@RestController
public class RecipeBookController {

private final RecipeBookService recipeBookService;

public RecipeBookController(RecipeBookService recipeBookService) {
this.recipeBookService = recipeBookService;
}

@PostMapping("/addRecipe")
public ResponseEntity<MealModel> addRecipe(@Valid @RequestBody MealModel request, @RequestHeader("Authorization") String token) {
if (token == null || token.isEmpty()) {
return ResponseEntity.badRequest().build();
}

String authToken = token.substring(7);
return ResponseEntity.ok(recipeBookService.addRecipe(request, authToken));
}

@PostMapping("/removeRecipe")
public ResponseEntity<Void> removeRecipe(@Valid @RequestBody MealModel request, @RequestHeader("Authorization") String token) {
if (token == null || token.isEmpty()) {
return ResponseEntity.badRequest().build();
}

String authToken = token.substring(7);
recipeBookService.removeRecipe(request, authToken);

return ResponseEntity.ok().build();
}

@PostMapping("/getAllRecipes")
public ResponseEntity<List<MealModel>> getAllRecipes(@RequestHeader("Authorization") String token) {
if (token == null || token.isEmpty()) {
return ResponseEntity.badRequest().build();
}

String authToken = token.substring(7);
return ResponseEntity.ok(recipeBookService.getAllRecipes(authToken));
}
}
19 changes: 10 additions & 9 deletions backend/src/main/java/fellowship/mealmaestro/models/MealModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ public class MealModel {
@NotBlank(message = "A Meal Name is required")
private String name;

@NotBlank(message = "An image is required")
private String image;

@NotBlank(message = "A Description is required")
private String description;

@NotBlank(message = "A Url is required")
private String url;

@NotBlank(message = "Ingredients are required")
private String ingredients;

Expand All @@ -28,11 +28,11 @@ public class MealModel {
private String cookingTime;
public MealModel(){};

public MealModel(String name, String instructions,String description, String url, String ingredients, String cookingTime){
public MealModel(String name, String instructions,String description, String image, String ingredients, String cookingTime){
this.name = name;
this.instructions = instructions;
this.description = description;
this.url = url;
this.image = image;
this.ingredients = ingredients;
this.cookingTime = cookingTime;
}
Expand Down Expand Up @@ -61,12 +61,12 @@ public void setdescription(String description){
this.description = description;
}

public String geturl(){
return this.url;
public String getimage(){
return this.image;
}

public void seturl(String url){
this.url = url;
public void setimage(String image){
this.image = image;
}

public String getingredients(){
Expand All @@ -91,5 +91,6 @@ public void copyFromOtherModel(MealModel mealModel){
this.ingredients = mealModel.getingredients();
this.instructions = mealModel.getinstructions();
this.description = mealModel.getdescription();
this.image = mealModel.getimage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package fellowship.mealmaestro.models;

import jakarta.validation.constraints.NotBlank;

public class RecipeModel {
@NotBlank(message = "A title is required")
private String title;

@NotBlank(message = "An image is required")
private String image;

public RecipeModel(String title, String image) {
this.title = title;
this.image = image;
}

public String getTitle() {
return this.title;
}

public String getImage() {
return this.image;
}

public void setTitle(String title) {
this.title = title;
}

public void setImage(String image) {
this.image = image;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ public TransactionCallback<List<MealModel>> getPopularMealsTransaction(String em
"WITH m, rand() as random\n" +
"ORDER BY random\n" +
"RETURN m.name AS name, m.instructions AS instructions, m.description AS description, " +
"m.url AS url, m.ingredients AS ingredients, m.cookingTime AS cookingTime",
"m.image AS image, m.ingredients AS ingredients, m.cookingTime AS cookingTime",
Values.parameters("email", email));

while (result.hasNext()) {
org.neo4j.driver.Record record = result.next();
String name = record.get("name").asString();
String instructions = record.get("instructions").asString();
String description = record.get("description").asString();
String url = record.get("url").asString();
String image = record.get("image").asString();
String ingredients = record.get("ingredients").asString();
String cookingTime = record.get("cookingTime").asString();
randomMeals.add(new MealModel(name, instructions, description, url, ingredients, cookingTime));
randomMeals.add(new MealModel(name, instructions, description, image, ingredients, cookingTime));
}

return randomMeals;
Expand Down Expand Up @@ -101,13 +101,13 @@ public TransactionCallback<List<MealModel>> getSearchedMealsTransaction(String m
List<MealModel> matchingPopularMeals = new ArrayList<>();
// org.neo4j.driver.Result result = transaction.run("MATCH (m:Meal {name: $name})\n" +
// "RETURN m.name AS name, m.instructions AS instructions, m.description AS description, " +
// "m.url AS url, m.ingredients AS ingredients, m.cookingTime AS cookingTime",
// "m.image AS image, m.ingredients AS ingredients, m.cookingTime AS cookingTime",
// Values.parameters("email", email));
org.neo4j.driver.Result result = transaction.run(
"MATCH (m:Meal)\n" +
"WHERE m.name =~ $namePattern OR m.ingredients =~ $namePattern OR m.description =~ $namePattern\n" + // Use regular expression matching
"RETURN m.name AS name, m.instructions AS instructions, m.description AS description, " +
"m.url AS url, m.ingredients AS ingredients, m.cookingTime AS cookingTime",
"m.image AS image, m.ingredients AS ingredients, m.cookingTime AS cookingTime",
Values.parameters("namePattern", "(?i).*" + mealName + ".*") // (?i) for case-insensitive
);

Expand All @@ -116,11 +116,11 @@ public TransactionCallback<List<MealModel>> getSearchedMealsTransaction(String m
String name = record.get("name").asString();
String instructions = record.get("instructions").asString();
String description = record.get("description").asString();
String url = record.get("url").asString();
String image = record.get("image").asString();
String ingredients = record.get("ingredients").asString();
String cookingTime = record.get("cookingTime").asString();
// return new MealModel(name, instructions, description, url, ingredients, cookingTime);
matchingPopularMeals.add(new MealModel(name, instructions, description, url, ingredients, cookingTime));
// return new MealModel(name, instructions, description, image, ingredients, cookingTime);
matchingPopularMeals.add(new MealModel(name, instructions, description, image, ingredients, cookingTime));
}

return matchingPopularMeals;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package fellowship.mealmaestro.repositories;

import org.springframework.stereotype.Repository;

import org.neo4j.driver.Driver;
import org.neo4j.driver.Session;
import org.neo4j.driver.TransactionCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.neo4j.driver.Values;

import java.util.List;
import java.util.ArrayList;

import fellowship.mealmaestro.models.MealModel;

@Repository
public class RecipeBookRepository {

@Autowired
private final Driver driver;

public RecipeBookRepository(Driver driver){
this.driver = driver;
}

//#region Create
public MealModel addRecipe(MealModel recipe, String email){
try (Session session = driver.session()){
return session.executeWrite(addRecipeTransaction(recipe, email));
}
}

public static TransactionCallback<MealModel> addRecipeTransaction(MealModel recipe, String email) {
return transaction -> {
transaction.run("MATCH (user:User {email: $email}), (recipe:Meal {name: $name, description: $desc, image: $image, ingredients: $ing, " +
"instructions: $ins, cookingTime: $ck})" +
"MERGE (user)-[:HAS_RECIPE_BOOK]->(recipeBook:`Recipe Book`) " +
"MERGE (recipeBook)-[:CONTAINS]->(recipe)",
Values.parameters("email", email, "name", recipe.getName(), "desc", recipe.getdescription(), "image", recipe.getimage(),
"ing", recipe.getingredients(), "ins", recipe.getinstructions(), "ck", recipe.getcookingTime()));
return (new MealModel(recipe.getName(), recipe.getinstructions(), recipe.getdescription(), recipe.getimage(), recipe.getingredients(), recipe.getcookingTime()));
};
}
//#endregion

//#region Read
public List<MealModel> getAllRecipes(String user){
try (Session session = driver.session()){
return session.executeRead(getAllRecipesTransaction(user));
}
}

public static TransactionCallback<List<MealModel>> getAllRecipesTransaction(String user) {
return transaction -> {
var result = transaction.run("MATCH (user:User {email: $email})-[:HAS_RECIPE_BOOK]->(book:`Recipe Book`)-[:CONTAINS]->(recipe:Meal) " +
"RETURN recipe.name AS name, recipe.image AS image, recipe.description AS description, recipe.ingredients as ingredients, recipe.instructions as instructions, recipe.cookingTime as cookingTime",
Values.parameters("email", user));

List<MealModel> recipes = new ArrayList<>();
while (result.hasNext()){
var record = result.next();
recipes.add(new MealModel(record.get("name").asString(), record.get("instructions").asString(), record.get("description").asString(), record.get("image").asString(),
record.get("ingredients").asString(), record.get("cookingTime").asString()));
}
return recipes;
};
}
//#endregion

//#region Delete
public void removeRecipe(MealModel recipe, String email){
try (Session session = driver.session()){
session.executeWrite(removeRecipeTransaction(recipe, email));
}
}

public static TransactionCallback<Void> removeRecipeTransaction(MealModel recipe, String email) {
return transaction -> {
transaction.run("MATCH (user:User {email: $email})-[:HAS_RECIPE_BOOK]->(book:`Recipe Book`)-[r:CONTAINS]->(recipe:Meal {name: $name}) " +
"DELETE r",
Values.parameters("email", email, "name", recipe.getName()));
return null;
};
}
//#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,16 @@ public class OpenaiApiService {
private OpenaiPromptBuilder pBuilder = new OpenaiPromptBuilder();

public String fetchMealResponse(String Type) throws JsonMappingException, JsonProcessingException {
String jsonResponse = getJSONResponse(Type);
JsonNode jsonNode = jsonMapper.readTree(jsonResponse);
// String jsonResponse = getJSONResponse(Type);
// JsonNode jsonNode = jsonMapper.readTree(jsonResponse);

String text = jsonNode.get("choices").get(0).get("text").asText();
text = text.replace("\\\"", "\"");
text = text.replace("\n", "");
text = text.replace("/r/n", "\\r\\n");
return text;
// String text = jsonNode.get("choices").get(0).get("text").asText();
// text = text.replace("\\\"", "\"");
// text = text.replace("\n", "");
// text = text.replace("/r/n", "\\r\\n");
// return text;

// return "{\"instructions\":\"1. Preheat oven to 375 degrees/r/n2. Grease a baking dish with butter/r/n3. Beat together the eggs, milk, and a pinch of salt/r/n4. Place the bread slices in the baking dish and pour the egg mixture over them/r/n5. Bake in the preheated oven for 25 minutes/r/n6. Serve warm with your favorite toppings\",\"name\":\"Baked French Toast\",\"description\":\"a delicious breakfast dish of egg-soaked bread\",\"ingredients\":\"6 slices of bread/r/n3 eggs/r/n3/4 cup of milk/r/nSalt/r/nButter\",\"cookingTime\":\"30 minutes\"}";
return "{\"instructions\":\"1. Preheat oven to 375 degrees/r/n2. Grease a baking dish with butter/r/n3. Beat together the eggs, milk, and a pinch of salt/r/n4. Place the bread slices in the baking dish and pour the egg mixture over them/r/n5. Bake in the preheated oven for 25 minutes/r/n6. Serve warm with your favorite toppings\",\"name\":\"Baked French Toast\",\"description\":\"a delicious breakfast dish of egg-soaked bread\",\"ingredients\":\"6 slices of bread/r/n3 eggs/r/n3/4 cup of milk/r/nSalt/r/nButter\",\"cookingTime\":\"30 minutes\"}";
}

public String fetchMealResponse(String Type, String extendedPrompt)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package fellowship.mealmaestro.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

import fellowship.mealmaestro.models.MealModel;
import fellowship.mealmaestro.repositories.RecipeBookRepository;
import fellowship.mealmaestro.services.auth.JwtService;

@Service
public class RecipeBookService {

@Autowired
private JwtService jwtService;

private final RecipeBookRepository recipeBookRepository;

public RecipeBookService(RecipeBookRepository recipeBookRepository) {
this.recipeBookRepository = recipeBookRepository;
}

public MealModel addRecipe(MealModel recipe, String token) {
String email = jwtService.extractUserEmail(token);
return recipeBookRepository.addRecipe(recipe, email);
}

public void removeRecipe(MealModel request, String token) {
String email = jwtService.extractUserEmail(token);
recipeBookRepository.removeRecipe(request, email);
}

public List<MealModel> getAllRecipes(String token) {
String email = jwtService.extractUserEmail(token);

return recipeBookRepository.getAllRecipes(email);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@
{{mealsData.description}}
</ion-card-content>
<ion-avatar>
<img src="{{mealsData.url}}">
<img alt="{{mealsData.url}}">
<img src="{{mealsData.image}}">
<img alt="{{mealsData.image}}">

</ion-avatar>

Expand All @@ -107,8 +107,8 @@
</ion-header>
<ion-avatar class="background">

<img src="{{mealsData.url}}">
<img alt="{{mealsData.url}}">
<img src="{{mealsData.image}}">
<img alt="{{mealsData.image}}">

</ion-avatar>
<ion-content class="ion-padding">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';

import { BrowseMealsComponent } from './browse-meals.component';
import { MealBrowseI } from '../../models/mealBrowse.model';
import { MealI } from '../../models/interfaces';

describe('BrowseMealsComponent', () => {
let component: BrowseMealsComponent;
let fixture: ComponentFixture<BrowseMealsComponent>;
let mockMeal: MealBrowseI;
let mockMeal: MealI;

beforeEach(waitForAsync(() => {
mockMeal = {
name: 'test',
description: 'test',
url: 'test',
image: 'test',
ingredients: 'test',
instructions: 'test',
cookingTime: 'test',
Expand Down
Loading

0 comments on commit fb4ab32

Please sign in to comment.