Compare commits
5 Commits
92f854848d
...
main
Author | SHA1 | Date | |
---|---|---|---|
9d9d6d8a60 | |||
be982193e4 | |||
75644d012d | |||
fce585e089 | |||
fdd18bdb6c |
45
pom.xml
45
pom.xml
@ -55,6 +55,51 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Spring Security für Passwort-Hashing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JJWT API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JJWT Implementierung (zur Laufzeit) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JJWT Jackson für JSON-Verarbeitung (zur Laufzeit) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring Boot Validation für Request-Validierung -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Lombok (Optional, aber erleichtert die Code-Generierung) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
77
src/main/java/com/example/hangry/Group.java
Normal file
77
src/main/java/com/example/hangry/Group.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package com.example.hangry;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "`group`")
|
||||||
|
public class Group {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "group_users",
|
||||||
|
joinColumns = @JoinColumn(name = "group_id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "user_id")
|
||||||
|
)
|
||||||
|
private Set<User> members = new HashSet<>();
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "group", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
|
private Set<GroupRecipe> sharedRecipes = new HashSet<>();
|
||||||
|
|
||||||
|
public Group() {}
|
||||||
|
|
||||||
|
public Group(String name, String description) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<User> getMembers() {
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<GroupRecipe> getSharedRecipes() {
|
||||||
|
return sharedRecipes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembers(Set<User> members) {
|
||||||
|
this.members = members;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSharedRecipes(Set<GroupRecipe> sharedRecipes) {
|
||||||
|
this.sharedRecipes = sharedRecipes;
|
||||||
|
}
|
||||||
|
}
|
52
src/main/java/com/example/hangry/GroupRecipe.java
Normal file
52
src/main/java/com/example/hangry/GroupRecipe.java
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package com.example.hangry;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class GroupRecipe {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "group_id", nullable = false)
|
||||||
|
private Group group;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "recipe_id", nullable = false)
|
||||||
|
private Recipe recipe;
|
||||||
|
|
||||||
|
public GroupRecipe() {}
|
||||||
|
|
||||||
|
public GroupRecipe(Group group, Recipe recipe) {
|
||||||
|
this.group = group;
|
||||||
|
this.recipe = recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Group getGroup() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Recipe getRecipe() {
|
||||||
|
return recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroup(Group group) {
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecipe(Recipe recipe) {
|
||||||
|
this.recipe = recipe;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.hangry;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface GroupRecipeRepository extends JpaRepository<GroupRecipe, Long> {
|
||||||
|
}
|
6
src/main/java/com/example/hangry/GroupRepository.java
Normal file
6
src/main/java/com/example/hangry/GroupRepository.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.hangry;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface GroupRepository extends JpaRepository<Group, Long> {
|
||||||
|
}
|
64
src/main/java/com/example/hangry/Like.java
Normal file
64
src/main/java/com/example/hangry/Like.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package com.example.hangry;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "`likes`")
|
||||||
|
public class Like {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id", nullable = false)
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "recipe_id", nullable = false)
|
||||||
|
private Recipe recipe;
|
||||||
|
|
||||||
|
private LocalDateTime createdAt = LocalDateTime.now();
|
||||||
|
|
||||||
|
// Konstruktoren, Getter & Setter#
|
||||||
|
|
||||||
|
public Like(){}
|
||||||
|
public Like( User user, Recipe recipe) {
|
||||||
|
this.user = user;
|
||||||
|
this.recipe = recipe;
|
||||||
|
this.createdAt=LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Recipe getRecipe() {
|
||||||
|
return recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecipe(Recipe recipe) {
|
||||||
|
this.recipe = recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
17
src/main/java/com/example/hangry/LikeRepository.java
Normal file
17
src/main/java/com/example/hangry/LikeRepository.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.example.hangry;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface LikeRepository extends JpaRepository<Like, Long> {
|
||||||
|
boolean existsByUserAndRecipe(User user, Recipe recipe);
|
||||||
|
|
||||||
|
long countByRecipe(Recipe recipe);
|
||||||
|
|
||||||
|
List<Like> findAllByUser(User user);
|
||||||
|
|
||||||
|
void deleteByUserAndRecipe(User user, Recipe recipe);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -76,4 +76,6 @@ public class Recipe {
|
|||||||
public void setRecipeIngredients(List<RecipeIngredient> recipeIngredients) {
|
public void setRecipeIngredients(List<RecipeIngredient> recipeIngredients) {
|
||||||
this.recipeIngredients = recipeIngredients;
|
this.recipeIngredients = recipeIngredients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ public interface RecipeRepository extends JpaRepository<Recipe, Long> {
|
|||||||
Page<Recipe> findByCategoryIgnoreCase(String category, Pageable pageable);
|
Page<Recipe> findByCategoryIgnoreCase(String category, Pageable pageable);
|
||||||
|
|
||||||
// Sucht nach Rezepten, die eine bestimmte Zutat enthalten
|
// Sucht nach Rezepten, die eine bestimmte Zutat enthalten
|
||||||
@Query("SELECT r FROM Recipe r JOIN r.recipeIngredients i WHERE LOWER(i.name) LIKE LOWER(CONCAT('%', :ingredient, '%'))")
|
@Query("SELECT r FROM Recipe r JOIN r.recipeIngredients i WHERE LOWER(i.ingredient.name) LIKE LOWER(CONCAT('%', :ingredient, '%'))")
|
||||||
Page<Recipe> findByIngredient(@Param("ingredient") String ingredient, Pageable pageable);
|
Page<Recipe> findByIngredient(@Param("ingredient") String ingredient, Pageable pageable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.example.hangry.controller;
|
||||||
|
|
||||||
|
import com.example.hangry.User;
|
||||||
|
import com.example.hangry.services.UserService;
|
||||||
|
import com.example.hangry.services.JwtService;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
|
||||||
|
@CrossOrigin (origins = "*")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/auth")
|
||||||
|
public class AuthController {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
private final JwtService jwtService;
|
||||||
|
|
||||||
|
public AuthController(UserService userService, JwtService jwtService) {
|
||||||
|
this.userService = userService;
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/register")
|
||||||
|
public ResponseEntity<?> register(@RequestBody User user) {
|
||||||
|
if (userService.getUserByEmail(user.getEmail()) != null) {
|
||||||
|
return ResponseEntity.badRequest().body("Email bereits vergeben!");
|
||||||
|
}
|
||||||
|
if (userService.getUserByUsername(user.getUsername()) != null) {
|
||||||
|
return ResponseEntity.badRequest().body("Username bereits vergeben!");
|
||||||
|
}
|
||||||
|
User newUser = userService.createUser(user);
|
||||||
|
return ResponseEntity.ok(newUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/login")
|
||||||
|
public ResponseEntity<?> login(@RequestBody User loginRequest) {
|
||||||
|
User user = userService.getUserByEmail(loginRequest.getEmail());
|
||||||
|
if (user != null && userService.checkPassword(loginRequest.getPassword(), user.getPassword())) {
|
||||||
|
String token = jwtService.generateToken(user); // JWT erstellen
|
||||||
|
return ResponseEntity.ok(Collections.singletonMap("token",token)); // Token zurückgeben
|
||||||
|
}
|
||||||
|
return ResponseEntity.status(401).body(Collections.singletonMap("error","Login Fehlgeschlagen!"));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.example.hangry.controller;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.Set;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
import com.example.hangry.services.GroupService;
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/groups")
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class GroupController {
|
||||||
|
|
||||||
|
private final GroupService groupService;
|
||||||
|
|
||||||
|
public GroupController(GroupService groupService) {
|
||||||
|
this.groupService = groupService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neue Gruppe erstellen
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<Group> createGroup(@RequestParam String name, @RequestParam String description) {
|
||||||
|
return ResponseEntity.ok(groupService.createGroup(name, description));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gruppe beitreten
|
||||||
|
@PostMapping("/{groupId}/join/{userId}")
|
||||||
|
public ResponseEntity<String> joinGroup(@PathVariable Long groupId, @PathVariable Long userId) {
|
||||||
|
boolean joined = groupService.joinGroup(userId, groupId);
|
||||||
|
return joined ? ResponseEntity.ok("Gruppe beigetreten") : ResponseEntity.badRequest().body("Bereits Mitglied");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gruppe verlassen
|
||||||
|
@PostMapping("/{groupId}/leave/{userId}")
|
||||||
|
public ResponseEntity<String> leaveGroup(@PathVariable Long groupId, @PathVariable Long userId) {
|
||||||
|
boolean left = groupService.leaveGroup(userId, groupId);
|
||||||
|
return left ? ResponseEntity.ok("Gruppe verlassen") : ResponseEntity.badRequest().body("Nicht in der Gruppe");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mitglieder einer Gruppe abrufen
|
||||||
|
@GetMapping("/{groupId}/members")
|
||||||
|
public ResponseEntity<Set<User>> getGroupMembers(@PathVariable Long groupId) {
|
||||||
|
return ResponseEntity.ok(groupService.getGroupMembers(groupId));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.example.hangry.controller;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.example.hangry.services.GroupRecipeService;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/group-recipes")
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class GroupRecipeController {
|
||||||
|
|
||||||
|
private final GroupRecipeService groupRecipeService;
|
||||||
|
|
||||||
|
public GroupRecipeController(GroupRecipeService groupRecipeService) {
|
||||||
|
this.groupRecipeService = groupRecipeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{groupId}/share/{recipeId}")
|
||||||
|
public ResponseEntity<String> shareRecipe(@PathVariable Long groupId, @PathVariable Long recipeId) {
|
||||||
|
boolean shared = groupRecipeService.shareRecipeWithGroup(groupId, recipeId);
|
||||||
|
return shared ? ResponseEntity.ok("Rezept geteilt") : ResponseEntity.badRequest().body("Fehler beim Teilen");
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{groupId}")
|
||||||
|
public ResponseEntity<Set<Recipe>> getGroupRecipes(@PathVariable Long groupId) {
|
||||||
|
return ResponseEntity.ok(groupRecipeService.getGroupRecipes(groupId));
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package com.example.hangry;
|
package com.example.hangry.controller;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
import com.example.hangry.services.IngredientService;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/ingredients")
|
@RequestMapping("/api/ingredients")
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.example.hangry.controller;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.List;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
import com.example.hangry.services.LikeService;
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/likes")
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class LikeController {
|
||||||
|
|
||||||
|
private final LikeService likeService;
|
||||||
|
|
||||||
|
public LikeController(LikeService likeService) {
|
||||||
|
this.likeService = likeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rezept liken
|
||||||
|
@PostMapping("/{userId}/{recipeId}")
|
||||||
|
public ResponseEntity<String> likeRecipe(@PathVariable Long userId, @PathVariable Long recipeId) {
|
||||||
|
boolean liked = likeService.likeRecipe(userId, recipeId);
|
||||||
|
return liked ? ResponseEntity.ok("Rezept geliked") : ResponseEntity.badRequest().body("Bereits geliked");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rezept entliken
|
||||||
|
@DeleteMapping("/{userId}/{recipeId}")
|
||||||
|
public ResponseEntity<String> unlikeRecipe(@PathVariable Long userId, @PathVariable Long recipeId) {
|
||||||
|
boolean unliked = likeService.unlikeRecipe(userId, recipeId);
|
||||||
|
return unliked ? ResponseEntity.ok("Like entfernt") : ResponseEntity.badRequest().body("Like existiert nicht");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anzahl der Likes für ein Rezept abrufen
|
||||||
|
@GetMapping("/count/{recipeId}")
|
||||||
|
public ResponseEntity<Long> getLikeCount(@PathVariable Long recipeId) {
|
||||||
|
return ResponseEntity.ok(likeService.getLikeCount(recipeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle geliketen Rezepte eines Users abrufen
|
||||||
|
@GetMapping("/user/{userId}")
|
||||||
|
public ResponseEntity<List<Recipe>> getLikedRecipes(@PathVariable Long userId) {
|
||||||
|
return ResponseEntity.ok(likeService.getLikedRecipes(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.hangry;
|
package com.example.hangry.controller;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@ -7,6 +7,8 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import com.example.hangry.*;
|
||||||
|
import com.example.hangry.services.RecipeService;
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/recipes")
|
@RequestMapping("/api/recipes")
|
||||||
@CrossOrigin(origins = "*") // Erlaubt CORS für alle Domains, kann angepasst werden
|
@CrossOrigin(origins = "*") // Erlaubt CORS für alle Domains, kann angepasst werden
|
@ -1,8 +1,9 @@
|
|||||||
package com.example.hangry;
|
package com.example.hangry.controller;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
import com.example.hangry.*;
|
||||||
|
import com.example.hangry.services.UserService;
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/users")
|
@RequestMapping("/users")
|
||||||
public class UserController {
|
public class UserController {
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.example.hangry.security;
|
||||||
|
|
||||||
|
import com.example.hangry.User;
|
||||||
|
import com.example.hangry.UserRepository;
|
||||||
|
import com.example.hangry.services.JwtService;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
|
||||||
|
private final JwtService jwtService;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
public JwtAuthenticationFilter(JwtService jwtService, UserRepository userRepository) {
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
String authHeader = request.getHeader("Authorization");
|
||||||
|
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||||||
|
String token = authHeader.substring(7);
|
||||||
|
String email = jwtService.extractEmail(token);
|
||||||
|
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||||
|
User user = userRepository.findByEmail(email);
|
||||||
|
if (user != null && jwtService.validateToken(token, user)) {
|
||||||
|
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.example.hangry.security;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity // Aktiviert Spring Security
|
||||||
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
|
||||||
|
http
|
||||||
|
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
|
||||||
|
.csrf(AbstractHttpConfigurer::disable) // Neue Syntax für CSRF-Disable
|
||||||
|
.authorizeHttpRequests(auth -> auth
|
||||||
|
.requestMatchers("/api/auth/register", "/api/auth/login").permitAll() // Registrierung & Login erlauben
|
||||||
|
.anyRequest().authenticated() // Alles andere erfordert Authentifizierung
|
||||||
|
)
|
||||||
|
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // JWT: Keine Session
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.example.hangry.services;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
@Service
|
||||||
|
public class GroupRecipeService {
|
||||||
|
|
||||||
|
private final GroupRepository groupRepository;
|
||||||
|
private final RecipeRepository recipeRepository;
|
||||||
|
private final GroupRecipeRepository groupRecipeRepository;
|
||||||
|
|
||||||
|
public GroupRecipeService(GroupRepository groupRepository, RecipeRepository recipeRepository, GroupRecipeRepository groupRecipeRepository) {
|
||||||
|
this.groupRepository = groupRepository;
|
||||||
|
this.recipeRepository = recipeRepository;
|
||||||
|
this.groupRecipeRepository = groupRecipeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rezept mit Gruppe teilen
|
||||||
|
public boolean shareRecipeWithGroup(Long groupId, Long recipeId) {
|
||||||
|
Group group = groupRepository.findById(groupId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Gruppe nicht gefunden"));
|
||||||
|
Recipe recipe = recipeRepository.findById(recipeId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Rezept nicht gefunden"));
|
||||||
|
|
||||||
|
GroupRecipe groupRecipe = new GroupRecipe(group, recipe);
|
||||||
|
groupRecipeRepository.save(groupRecipe);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle Rezepte einer Gruppe abrufen
|
||||||
|
public Set<Recipe> getGroupRecipes(Long groupId) {
|
||||||
|
Group group = groupRepository.findById(groupId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Gruppe nicht gefunden"));
|
||||||
|
return group.getSharedRecipes().stream().map(GroupRecipe::getRecipe).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
}
|
59
src/main/java/com/example/hangry/services/GroupService.java
Normal file
59
src/main/java/com/example/hangry/services/GroupService.java
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package com.example.hangry.services;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import java.util.Set;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
@Service
|
||||||
|
public class GroupService {
|
||||||
|
|
||||||
|
private final GroupRepository groupRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
public GroupService(GroupRepository groupRepository, UserRepository userRepository) {
|
||||||
|
this.groupRepository = groupRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gruppe erstellen
|
||||||
|
public Group createGroup(String name, String description) {
|
||||||
|
Group group = new Group(name, description);
|
||||||
|
return groupRepository.save(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gruppe beitreten
|
||||||
|
public boolean joinGroup(Long userId, Long groupId) {
|
||||||
|
User user = userRepository.findById(userId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("User nicht gefunden"));
|
||||||
|
Group group = groupRepository.findById(groupId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Gruppe nicht gefunden"));
|
||||||
|
|
||||||
|
if (!group.getMembers().contains(user)) {
|
||||||
|
group.getMembers().add(user);
|
||||||
|
groupRepository.save(group);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gruppe verlassen
|
||||||
|
public boolean leaveGroup(Long userId, Long groupId) {
|
||||||
|
User user = userRepository.findById(userId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("User nicht gefunden"));
|
||||||
|
Group group = groupRepository.findById(groupId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Gruppe nicht gefunden"));
|
||||||
|
|
||||||
|
if (group.getMembers().contains(user)) {
|
||||||
|
group.getMembers().remove(user);
|
||||||
|
groupRepository.save(group);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle Mitglieder einer Gruppe abrufen
|
||||||
|
public Set<User> getGroupMembers(Long groupId) {
|
||||||
|
Group group = groupRepository.findById(groupId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Gruppe nicht gefunden"));
|
||||||
|
return group.getMembers();
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package com.example.hangry;
|
package com.example.hangry.services;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import com.example.hangry.*;
|
||||||
@Service
|
@Service
|
||||||
public class IngredientService {
|
public class IngredientService {
|
||||||
|
|
53
src/main/java/com/example/hangry/services/JwtService.java
Normal file
53
src/main/java/com/example/hangry/services/JwtService.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package com.example.hangry.services;
|
||||||
|
|
||||||
|
import com.example.hangry.User;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import org.springframework.cglib.core.internal.Function;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.security.Key;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class JwtService {
|
||||||
|
|
||||||
|
private static final String SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256).toString();
|
||||||
|
private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 24; // 24 Stunden
|
||||||
|
|
||||||
|
public String generateToken(User user) {
|
||||||
|
return Jwts.builder()
|
||||||
|
.setSubject(user.getEmail())
|
||||||
|
.setIssuedAt(new Date())
|
||||||
|
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
|
||||||
|
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
|
||||||
|
final Claims claims = extractAllClaims(token);
|
||||||
|
return claimsResolver.apply(claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Claims extractAllClaims(String token) {
|
||||||
|
return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Key getSigningKey() {
|
||||||
|
return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
|
||||||
|
}
|
||||||
|
public String extractEmail(String token) {
|
||||||
|
return extractClaim(token, Claims::getSubject); // Subject = E-Mail
|
||||||
|
}
|
||||||
|
public boolean validateToken(String token, User user) {
|
||||||
|
final String email = extractEmail(token);
|
||||||
|
return email.equals(user.getEmail()) && !isTokenExpired(token);
|
||||||
|
}
|
||||||
|
private boolean isTokenExpired(String token) {
|
||||||
|
return extractClaim(token, Claims::getExpiration).before(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
67
src/main/java/com/example/hangry/services/LikeService.java
Normal file
67
src/main/java/com/example/hangry/services/LikeService.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package com.example.hangry.services;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import java.util.List;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LikeService {
|
||||||
|
|
||||||
|
private final LikeRepository likeRepository;
|
||||||
|
private final RecipeRepository recipeRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
public LikeService(LikeRepository likeRepository, RecipeRepository recipeRepository, UserRepository userRepository) {
|
||||||
|
this.likeRepository = likeRepository;
|
||||||
|
this.recipeRepository = recipeRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rezept liken
|
||||||
|
public boolean likeRecipe(Long userId, Long recipeId) {
|
||||||
|
User user = userRepository.findById(userId).orElseThrow();
|
||||||
|
Recipe recipe = recipeRepository.findById(recipeId).orElseThrow();
|
||||||
|
|
||||||
|
if (likeRepository.existsByUserAndRecipe(user, recipe)) {
|
||||||
|
return false; // Bereits geliked
|
||||||
|
}
|
||||||
|
|
||||||
|
Like like = new Like();
|
||||||
|
like.setUser(user);
|
||||||
|
like.setRecipe(recipe);
|
||||||
|
likeRepository.save(like);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rezept entliken
|
||||||
|
@Transactional
|
||||||
|
public boolean unlikeRecipe(Long userId, Long recipeId) {
|
||||||
|
User user = userRepository.findById(userId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("User nicht gefunden"));
|
||||||
|
Recipe recipe = recipeRepository.findById(recipeId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Rezept nicht gefunden"));
|
||||||
|
|
||||||
|
// Prüfen, ob das Like existiert
|
||||||
|
if (!likeRepository.existsByUserAndRecipe(user, recipe)) {
|
||||||
|
return false; // Like existiert nicht
|
||||||
|
}
|
||||||
|
|
||||||
|
likeRepository.deleteByUserAndRecipe(user, recipe);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Anzahl der Likes für ein Rezept abrufen
|
||||||
|
public long getLikeCount(Long recipeId) {
|
||||||
|
Recipe recipe = recipeRepository.findById(recipeId).orElseThrow();
|
||||||
|
return likeRepository.countByRecipe(recipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle geliketen Rezepte eines Users abrufen
|
||||||
|
public List<Recipe> getLikedRecipes(Long userId) {
|
||||||
|
User user = userRepository.findById(userId).orElseThrow();
|
||||||
|
List<Like> likes = likeRepository.findAllByUser(user);
|
||||||
|
return likes.stream().map(Like::getRecipe).toList();
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
package com.example.hangry;
|
package com.example.hangry.services;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import com.example.hangry.*;
|
||||||
@Service
|
@Service
|
||||||
public class RecipeService {
|
public class RecipeService {
|
||||||
|
|
@ -1,19 +1,25 @@
|
|||||||
package com.example.hangry;
|
package com.example.hangry.services;
|
||||||
|
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.example.hangry.*;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserService {
|
public class UserService {
|
||||||
|
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
// Dependency Injection (Spring kümmert sich darum)
|
// Dependency Injection (Spring kümmert sich darum)
|
||||||
public UserService(UserRepository userRepository) {
|
public UserService(UserRepository userRepository) {
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
|
this.passwordEncoder = new BCryptPasswordEncoder(); // Initialisierung von BCrypt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Einen neuen Benutzer erstellen
|
// Neuen Benutzer erstellen (mit Passwort-Hashing)
|
||||||
public User createUser(User user) {
|
public User createUser(User user) {
|
||||||
|
user.setPassword(passwordEncoder.encode(user.getPassword())); // Passwort hashen
|
||||||
return userRepository.save(user);
|
return userRepository.save(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,4 +32,9 @@ public class UserService {
|
|||||||
public User getUserByEmail(String email) {
|
public User getUserByEmail(String email) {
|
||||||
return userRepository.findByEmail(email);
|
return userRepository.findByEmail(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Passwort überprüfen
|
||||||
|
public boolean checkPassword(String rawPassword, String hashedPassword) {
|
||||||
|
return passwordEncoder.matches(rawPassword, hashedPassword);
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,6 +4,11 @@ spring.datasource.username=root
|
|||||||
spring.datasource.password=
|
spring.datasource.password=
|
||||||
|
|
||||||
# Hibernate Einstellungen
|
# Hibernate Einstellungen
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
|
||||||
spring.jpa.show-sql=true
|
spring.jpa.show-sql=true
|
||||||
|
spring.jpa.properties.hibernate.format_sql=true
|
||||||
|
spring.jpa.properties.hibernate.use_sql_comments=true
|
||||||
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
|
||||||
|
|
||||||
|
server.port=8080
|
||||||
|
server.address=0.0.0.0
|
Reference in New Issue
Block a user