mirror of
https://gitlab.com/etc404/software-engineering-project.git
synced 2026-05-10 20:52:58 +00:00
User Controller working, refactored structure
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface FavoriteRepo extends CrudRepository<Favorite, FavoriteId> {
|
||||
|
||||
List<Favorite> findByIdUserId(Integer userId); // all favorites for a user
|
||||
|
||||
List<Favorite> findByIdRecipeId(Integer recipeId); // all users who favorited a recipe
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface ImageRepo extends CrudRepository<Image, Integer> {
|
||||
List<Image> findByRecipeId(Integer recipeId);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface IngredientRepo extends CrudRepository<Ingredient, Integer> {
|
||||
Ingredient findByName(String name);
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Column;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "recipes")
|
||||
public class Recipe {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
private String title;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
private Integer prepTimeMinutes;
|
||||
private Integer cookTimeMinutes;
|
||||
private Integer servings;
|
||||
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private Integer userId;
|
||||
|
||||
private String status;
|
||||
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// Default constructor required by JPA
|
||||
public Recipe() {}
|
||||
|
||||
// Convenience constructor
|
||||
public Recipe(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes,
|
||||
Integer servings, Integer userId, String status) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.prepTimeMinutes = prepTimeMinutes;
|
||||
this.cookTimeMinutes = cookTimeMinutes;
|
||||
this.servings = servings;
|
||||
this.userId = userId;
|
||||
this.status = status;
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
// Getters and setters for all fields
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public Integer getPrepTimeMinutes() { return prepTimeMinutes; }
|
||||
public void setPrepTimeMinutes(Integer prepTimeMinutes) { this.prepTimeMinutes = prepTimeMinutes; }
|
||||
|
||||
public Integer getCookTimeMinutes() { return cookTimeMinutes; }
|
||||
public void setCookTimeMinutes(Integer cookTimeMinutes) { this.cookTimeMinutes = cookTimeMinutes; }
|
||||
|
||||
public Integer getServings() { return servings; }
|
||||
public void setServings(Integer servings) { this.servings = servings; }
|
||||
|
||||
public Integer getUserId() { return userId; }
|
||||
public void setUserId(Integer userId) { this.userId = userId; }
|
||||
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "recipe_ingredient_junction",
|
||||
uniqueConstraints = {@UniqueConstraint(columnNames = {"recipe_id", "ingredient_id"})})
|
||||
public class RecipeIngredient {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id; // surrogate PK
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "recipe_id", nullable = false)
|
||||
private Recipe recipe;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "ingredient_id", nullable = false)
|
||||
private Ingredient ingredient;
|
||||
|
||||
private BigDecimal quantity;
|
||||
|
||||
private String unit;
|
||||
|
||||
private String notes;
|
||||
|
||||
public RecipeIngredient() {}
|
||||
|
||||
public RecipeIngredient(Recipe recipe, Ingredient ingredient, BigDecimal quantity, String unit, String notes) {
|
||||
this.recipe = recipe;
|
||||
this.ingredient = ingredient;
|
||||
this.quantity = quantity;
|
||||
this.unit = unit;
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public Recipe getRecipe() { return recipe; }
|
||||
public void setRecipe(Recipe recipe) { this.recipe = recipe; }
|
||||
|
||||
public Ingredient getIngredient() { return ingredient; }
|
||||
public void setIngredient(Ingredient ingredient) { this.ingredient = ingredient; }
|
||||
|
||||
public BigDecimal getQuantity() { return quantity; }
|
||||
public void setQuantity(BigDecimal quantity) { this.quantity = quantity; }
|
||||
|
||||
public String getUnit() { return unit; }
|
||||
public void setUnit(String unit) { this.unit = unit; }
|
||||
|
||||
public String getNotes() { return notes; }
|
||||
public void setNotes(String notes) { this.notes = notes; }
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface RecipeIngredientRepo extends CrudRepository<RecipeIngredient, Integer> {
|
||||
// Custom query: find all ingredients for a recipe
|
||||
Iterable<RecipeIngredient> findByRecipe(Recipe recipe);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface RecipeRepo extends CrudRepository<Recipe, Integer> {
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "steps")
|
||||
public class Step {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "recipe_id", nullable = false)
|
||||
private Integer recipeId;
|
||||
|
||||
@Column(name = "step_number", nullable = false)
|
||||
private Integer stepNumber;
|
||||
|
||||
@Column(name = "instruction", nullable = false, columnDefinition = "TEXT")
|
||||
private String instruction;
|
||||
|
||||
// No-arg constructor required by JPA
|
||||
public Step() {}
|
||||
|
||||
public Step(Integer recipeId, Integer stepNumber, String instruction) {
|
||||
this.recipeId = recipeId;
|
||||
this.stepNumber = stepNumber;
|
||||
this.instruction = instruction;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public Integer getRecipeId() { return recipeId; }
|
||||
public void setRecipeId(Integer recipeId) { this.recipeId = recipeId; }
|
||||
|
||||
public Integer getStepNumber() { return stepNumber; }
|
||||
public void setStepNumber(Integer stepNumber) { this.stepNumber = stepNumber; }
|
||||
|
||||
public String getInstruction() { return instruction; }
|
||||
public void setInstruction(String instruction) { this.instruction = instruction; }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface StepRepo extends CrudRepository<Step, Integer> {
|
||||
|
||||
List<Step> findByRecipeIdOrderByStepNumber(Integer recipeId); // fetch steps in order
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface TagRepo extends CrudRepository<Tag, Integer> {
|
||||
|
||||
Optional<Tag> findByName(String name);
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.example.database;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Column;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "users") // matches your MySQL table name
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto-increment id
|
||||
private Integer id;
|
||||
|
||||
@Column(nullable = false, unique = true) // username cannot be null & must be unique
|
||||
private String username;
|
||||
|
||||
private String role;
|
||||
|
||||
@Column(unique = true)
|
||||
private String email;
|
||||
|
||||
private String hashedpassword;
|
||||
|
||||
@Column(name = "created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
// Constructors
|
||||
public User() {} // default constructor required by JPA
|
||||
|
||||
public User(String username, String role, String email, String hashedpassword, LocalDateTime createdAt) {
|
||||
this.username = username;
|
||||
this.role = role;
|
||||
this.email = email;
|
||||
this.hashedpassword = hashedpassword;
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getRole() { return role; }
|
||||
public void setRole(String role) { this.role = role; }
|
||||
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
|
||||
public String getHashedpassword() { return hashedpassword; }
|
||||
public void setHashedpassword(String hashedpassword) { this.hashedpassword = hashedpassword; }
|
||||
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
}
|
||||
@@ -1,50 +1,20 @@
|
||||
package com.example.demo.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
|
||||
http
|
||||
// Uses your CorsConfigurationSource bean from CorsConfig.java
|
||||
.cors(Customizer.withDefaults())
|
||||
|
||||
// For now, disable CSRF so you can POST from a separate frontend easily.
|
||||
// If you later use cookies/sessions, revisit CSRF.
|
||||
.csrf(csrf -> csrf.disable())
|
||||
|
||||
// Auth rules
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
// Allow health check + auth endpoints without login
|
||||
.requestMatchers("/api/health").permitAll()
|
||||
.requestMatchers("/api/auth/**").permitAll()
|
||||
|
||||
// Everything else requires authentication (you can loosen this later)
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
// Temporary: enables basic auth popup in browser tools.
|
||||
// Later you’ll likely switch to JWT or session login.
|
||||
.httpBasic(Customizer.withDefaults());
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
package com.example.demo.config;
|
||||
|
||||
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.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.anyRequest().permitAll()
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,5 @@
|
||||
package com.example.demo.controller;
|
||||
|
||||
import com.example.demo.dto.LoginRequest;
|
||||
import com.example.demo.dto.RegisterRequest;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
public class AuthController {
|
||||
|
||||
// TEMP: Register endpoint (service logic added later)
|
||||
@PostMapping("/register")
|
||||
public ResponseEntity<?> register(@Valid @RequestBody RegisterRequest request) {
|
||||
|
||||
// For now just return what was sent (test validation first)
|
||||
return ResponseEntity.ok("User registered: " + request.getUsername());
|
||||
}
|
||||
|
||||
// TEMP: Login endpoint
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<?> login(@Valid @RequestBody LoginRequest request) {
|
||||
|
||||
return ResponseEntity.ok("Login attempt for: " + request.getUsernameOrEmail());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.example.demo.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.example.demo.entity.User;
|
||||
import com.example.demo.service.UserService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
public class UserController {
|
||||
|
||||
private UserService userService;
|
||||
|
||||
public UserController(UserService userService) {
|
||||
super();
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
//build create user REST API
|
||||
@PostMapping
|
||||
public ResponseEntity<User> saveUser(@RequestBody User user){
|
||||
|
||||
return new ResponseEntity<User>(userService.saveUser(user), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
//build get all users REST API
|
||||
@GetMapping
|
||||
public List<User> getAllUsers(){
|
||||
return userService.getAllUsers();
|
||||
}
|
||||
|
||||
//build get user by id REST API
|
||||
// http://localhost:8080/api/users/(id number goes here)
|
||||
@GetMapping("{id}")
|
||||
public ResponseEntity<User> getUserById(@PathVariable("id") Integer userId){
|
||||
return new ResponseEntity<User>(userService.getUserById(userId), HttpStatus.OK);
|
||||
}
|
||||
|
||||
//build update user REST API
|
||||
// http://localhost:8080/api/users/(id number goes here)
|
||||
@PutMapping("{id}")
|
||||
public ResponseEntity<User> updateUser(@PathVariable("id") Integer userId, @RequestBody User user){
|
||||
return new ResponseEntity<User>(userService.updateUser(user, userId), HttpStatus.OK);
|
||||
}
|
||||
|
||||
//build delete user REST API
|
||||
@DeleteMapping("{id}")
|
||||
public ResponseEntity<String> deleteUser(@PathVariable("id") Integer userId){
|
||||
userService.deleteUser(userId);
|
||||
return new ResponseEntity<String>("User deleted succesfully!", HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +1,5 @@
|
||||
package com.example.demo.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public class LoginRequest {
|
||||
|
||||
@NotBlank(message = "usernameOrEmail is required")
|
||||
private String usernameOrEmail;
|
||||
|
||||
@NotBlank(message = "password is required")
|
||||
private String password;
|
||||
|
||||
public String getUsernameOrEmail() { return usernameOrEmail; }
|
||||
public void setUsernameOrEmail(String usernameOrEmail) { this.usernameOrEmail = usernameOrEmail; }
|
||||
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
}
|
||||
|
||||
@@ -1,53 +1,5 @@
|
||||
package com.example.demo.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.PositiveOrZero;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
public class RecipeCreateRequest {
|
||||
|
||||
@NotBlank(message = "title is required")
|
||||
@Size(max = 100, message = "title must be 100 characters or less")
|
||||
private String title;
|
||||
|
||||
@Size(max = 1000, message = "description must be 1000 characters or less")
|
||||
private String description;
|
||||
|
||||
@PositiveOrZero(message = "prepTimeMinutes must be 0 or greater")
|
||||
private int prepTimeMinutes;
|
||||
|
||||
@PositiveOrZero(message = "cookTimeMinutes must be 0 or greater")
|
||||
private int cookTimeMinutes;
|
||||
|
||||
@PositiveOrZero(message = "servings must be 0 or greater")
|
||||
private int servings;
|
||||
|
||||
@NotNull(message = "ingredients list is required")
|
||||
private List<IngredientDto> ingredients;
|
||||
|
||||
@NotNull(message = "steps list is required")
|
||||
private List<StepDto> steps;
|
||||
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public int getPrepTimeMinutes() { return prepTimeMinutes; }
|
||||
public void setPrepTimeMinutes(int prepTimeMinutes) { this.prepTimeMinutes = prepTimeMinutes; }
|
||||
|
||||
public int getCookTimeMinutes() { return cookTimeMinutes; }
|
||||
public void setCookTimeMinutes(int cookTimeMinutes) { this.cookTimeMinutes = cookTimeMinutes; }
|
||||
|
||||
public int getServings() { return servings; }
|
||||
public void setServings(int servings) { this.servings = servings; }
|
||||
|
||||
public List<IngredientDto> getIngredients() { return ingredients; }
|
||||
public void setIngredients(List<IngredientDto> ingredients) { this.ingredients = ingredients; }
|
||||
|
||||
public List<StepDto> getSteps() { return steps; }
|
||||
public void setSteps(List<StepDto> steps) { this.steps = steps; }
|
||||
}
|
||||
|
||||
@@ -1,29 +1,5 @@
|
||||
package com.example.demo.dto;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
public class RegisterRequest {
|
||||
|
||||
@NotBlank(message = "username is required")
|
||||
@Size(min = 3, max = 30, message = "username must be 3-30 characters")
|
||||
private String username;
|
||||
|
||||
@NotBlank(message = "email is required")
|
||||
@Email(message = "email must be valid")
|
||||
private String email;
|
||||
|
||||
@NotBlank(message = "password is required")
|
||||
@Size(min = 8, max = 100, message = "password must be at least 8 characters")
|
||||
private String password;
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
@@ -1,5 +1,84 @@
|
||||
package com.example.demo.entity;
|
||||
|
||||
public class Recipe {
|
||||
|
||||
}
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Column;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "recipes")
|
||||
public class Recipe {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
private String title;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
private Integer prepTimeMinutes;
|
||||
private Integer cookTimeMinutes;
|
||||
private Integer servings;
|
||||
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private Integer userId;
|
||||
|
||||
private String status;
|
||||
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// Default constructor required by JPA
|
||||
public Recipe() {}
|
||||
|
||||
// Convenience constructor
|
||||
public Recipe(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes,
|
||||
Integer servings, Integer userId, String status) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.prepTimeMinutes = prepTimeMinutes;
|
||||
this.cookTimeMinutes = cookTimeMinutes;
|
||||
this.servings = servings;
|
||||
this.userId = userId;
|
||||
this.status = status;
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
// Getters and setters for all fields
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public Integer getPrepTimeMinutes() { return prepTimeMinutes; }
|
||||
public void setPrepTimeMinutes(Integer prepTimeMinutes) { this.prepTimeMinutes = prepTimeMinutes; }
|
||||
|
||||
public Integer getCookTimeMinutes() { return cookTimeMinutes; }
|
||||
public void setCookTimeMinutes(Integer cookTimeMinutes) { this.cookTimeMinutes = cookTimeMinutes; }
|
||||
|
||||
public Integer getServings() { return servings; }
|
||||
public void setServings(Integer servings) { this.servings = servings; }
|
||||
|
||||
public Integer getUserId() { return userId; }
|
||||
public void setUserId(Integer userId) { this.userId = userId; }
|
||||
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
|
||||
}
|
||||
@@ -1,5 +1,57 @@
|
||||
package com.example.demo.entity;
|
||||
|
||||
public class RecipeIngredient {
|
||||
|
||||
}
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "recipe_ingredient_junction",
|
||||
uniqueConstraints = {@UniqueConstraint(columnNames = {"recipe_id", "ingredient_id"})})
|
||||
public class RecipeIngredient {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id; // surrogate PK
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "recipe_id", nullable = false)
|
||||
private Recipe recipe;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "ingredient_id", nullable = false)
|
||||
private Ingredient ingredient;
|
||||
|
||||
private BigDecimal quantity;
|
||||
|
||||
private String unit;
|
||||
|
||||
private String notes;
|
||||
|
||||
public RecipeIngredient() {}
|
||||
|
||||
public RecipeIngredient(Recipe recipe, Ingredient ingredient, BigDecimal quantity, String unit, String notes) {
|
||||
this.recipe = recipe;
|
||||
this.ingredient = ingredient;
|
||||
this.quantity = quantity;
|
||||
this.unit = unit;
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public Recipe getRecipe() { return recipe; }
|
||||
public void setRecipe(Recipe recipe) { this.recipe = recipe; }
|
||||
|
||||
public Ingredient getIngredient() { return ingredient; }
|
||||
public void setIngredient(Ingredient ingredient) { this.ingredient = ingredient; }
|
||||
|
||||
public BigDecimal getQuantity() { return quantity; }
|
||||
public void setQuantity(BigDecimal quantity) { this.quantity = quantity; }
|
||||
|
||||
public String getUnit() { return unit; }
|
||||
public void setUnit(String unit) { this.unit = unit; }
|
||||
|
||||
public String getNotes() { return notes; }
|
||||
public void setNotes(String notes) { this.notes = notes; }
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
@@ -1,5 +1,43 @@
|
||||
package com.example.demo.entity;
|
||||
|
||||
public class Step {
|
||||
|
||||
}
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "steps")
|
||||
public class Step {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "recipe_id", nullable = false)
|
||||
private Integer recipeId;
|
||||
|
||||
@Column(name = "step_number", nullable = false)
|
||||
private Integer stepNumber;
|
||||
|
||||
@Column(name = "instruction", nullable = false, columnDefinition = "TEXT")
|
||||
private String instruction;
|
||||
|
||||
// No-arg constructor required by JPA
|
||||
public Step() {}
|
||||
|
||||
public Step(Integer recipeId, Integer stepNumber, String instruction) {
|
||||
this.recipeId = recipeId;
|
||||
this.stepNumber = stepNumber;
|
||||
this.instruction = instruction;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public Integer getRecipeId() { return recipeId; }
|
||||
public void setRecipeId(Integer recipeId) { this.recipeId = recipeId; }
|
||||
|
||||
public Integer getStepNumber() { return stepNumber; }
|
||||
public void setStepNumber(Integer stepNumber) { this.stepNumber = stepNumber; }
|
||||
|
||||
public String getInstruction() { return instruction; }
|
||||
public void setInstruction(String instruction) { this.instruction = instruction; }
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@@ -1,5 +1,61 @@
|
||||
package com.example.demo.entity;
|
||||
|
||||
public class User {
|
||||
|
||||
}
|
||||
package com.example.demo.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Column;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
private String username;
|
||||
|
||||
private String role;
|
||||
|
||||
@Column(unique = true)
|
||||
private String email;
|
||||
|
||||
private String hashedpassword;
|
||||
|
||||
@Column(name = "created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
// Constructors
|
||||
public User() {} // default constructor required by JPA
|
||||
|
||||
public User(String username, String role, String email, String hashedpassword, LocalDateTime createdAt) {
|
||||
this.username = username;
|
||||
this.role = role;
|
||||
this.email = email;
|
||||
this.hashedpassword = hashedpassword;
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getRole() { return role; }
|
||||
public void setRole(String role) { this.role = role; }
|
||||
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
|
||||
public String getHashedpassword() { return hashedpassword; }
|
||||
public void setHashedpassword(String hashedpassword) { this.hashedpassword = hashedpassword; }
|
||||
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.example.demo.exception;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BadRequestException extends RuntimeException {
|
||||
public BadRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
public class BadRequestException {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,25 +1,5 @@
|
||||
package com.example.demo.exception;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class ErrorResponse {
|
||||
private LocalDateTime timestamp;
|
||||
private int status;
|
||||
private String error;
|
||||
private String message;
|
||||
private String path;
|
||||
|
||||
public ErrorResponse(LocalDateTime timestamp, int status, String error, String message, String path) {
|
||||
this.timestamp = timestamp;
|
||||
this.status = status;
|
||||
this.error = error;
|
||||
this.message = message;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public LocalDateTime getTimestamp() { return timestamp; }
|
||||
public int getStatus() { return status; }
|
||||
public String getError() { return error; }
|
||||
public String getMessage() { return message; }
|
||||
public String getPath() { return path; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +1,5 @@
|
||||
package com.example.demo.exception;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ResponseEntity<ErrorResponse> handleNotFound(NotFoundException ex, HttpServletRequest request) {
|
||||
return buildError(HttpStatus.NOT_FOUND, ex.getMessage(), request.getRequestURI());
|
||||
}
|
||||
|
||||
@ExceptionHandler(BadRequestException.class)
|
||||
public ResponseEntity<ErrorResponse> handleBadRequest(BadRequestException ex, HttpServletRequest request) {
|
||||
return buildError(HttpStatus.BAD_REQUEST, ex.getMessage(), request.getRequestURI());
|
||||
}
|
||||
|
||||
// Handles @Valid validation failures from DTOs
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex,
|
||||
HttpServletRequest request) {
|
||||
|
||||
String msg = ex.getBindingResult()
|
||||
.getFieldErrors()
|
||||
.stream()
|
||||
.map(err -> err.getField() + ": " + err.getDefaultMessage())
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
return buildError(HttpStatus.BAD_REQUEST, msg, request.getRequestURI());
|
||||
}
|
||||
|
||||
// Fallback for anything you didn't explicitly handle
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ErrorResponse> handleGeneric(Exception ex, HttpServletRequest request) {
|
||||
// In production you'd avoid returning raw exception messages.
|
||||
return buildError(HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error occurred", request.getRequestURI());
|
||||
}
|
||||
|
||||
private ResponseEntity<ErrorResponse> buildError(HttpStatus status, String message, String path) {
|
||||
ErrorResponse body = new ErrorResponse(
|
||||
LocalDateTime.now(),
|
||||
status.value(),
|
||||
status.getReasonPhrase(),
|
||||
message,
|
||||
path
|
||||
);
|
||||
return ResponseEntity.status(status).body(body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
package com.example.demo.exception;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class NotFoundException extends RuntimeException {
|
||||
public NotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus (value = HttpStatus.NOT_FOUND)
|
||||
public class NotFoundException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1l;
|
||||
private String resourceName;
|
||||
private String fieldName;
|
||||
private Object fieldValue;
|
||||
|
||||
public NotFoundException(String resourceName, String fieldName, Object fieldValue) {
|
||||
super(String.format("%s not found with %s : %s", resourceName, fieldName, fieldValue));
|
||||
this.resourceName = resourceName;
|
||||
this.fieldName = fieldName;
|
||||
this.fieldValue = fieldValue;
|
||||
}
|
||||
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
|
||||
public Object getFieldValue() {
|
||||
return fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import com.example.demo.entity.Favorite;
|
||||
import com.example.demo.entity.FavoriteId;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface FavoriteRepo extends JpaRepository<Favorite, FavoriteId> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import com.example.demo.entity.Image;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface ImageRepo extends JpaRepository<Image, Integer> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import com.example.demo.entity.Ingredient;
|
||||
|
||||
|
||||
public interface IngredientRepo extends JpaRepository<Ingredient, Integer> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import com.example.demo.entity.RecipeIngredient;
|
||||
|
||||
public interface RecipeIngredientRepo extends JpaRepository<RecipeIngredient, Integer> {
|
||||
// Custom query: find all ingredients for a recipe
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import com.example.demo.entity.Recipe;
|
||||
|
||||
|
||||
public interface RecipeRepo extends JpaRepository<Recipe, Integer> {
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
public class RecipeRepository {
|
||||
|
||||
}
|
||||
+4
-3
@@ -1,11 +1,12 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.repository;
|
||||
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import com.example.demo.entity.RecipeTag;
|
||||
import com.example.demo.entity.RecipeTagId;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RecipeTagRepo extends JpaRepository<RecipeTag, RecipeTagId> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import com.example.demo.entity.Step;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface StepRepo extends JpaRepository<Step, Integer> {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import com.example.demo.entity.Tag;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface TagRepo extends JpaRepository<Tag, Integer> {
|
||||
|
||||
|
||||
|
||||
}
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
package com.example.database;
|
||||
package com.example.demo.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import com.example.demo.entity.User;
|
||||
|
||||
public interface UserRepo extends JpaRepository<User, Integer> {
|
||||
User findByUsername(String username);
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.example.demo.repository;
|
||||
|
||||
public class UserRepository {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.example.demo.service.Impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.example.demo.entity.User;
|
||||
import com.example.demo.exception.NotFoundException;
|
||||
import com.example.demo.repository.UserRepo;
|
||||
import com.example.demo.service.UserService;
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService{
|
||||
|
||||
private UserRepo userRepository;
|
||||
|
||||
public UserServiceImpl(UserRepo userRepository) {
|
||||
super();
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User saveUser(User user) {
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<User> getAllUsers() {
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUserById(Integer Id) {
|
||||
|
||||
return userRepository.findById(Id).orElseThrow(() ->
|
||||
new NotFoundException("User", "id", Id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public User updateUser(User user, Integer Id) {
|
||||
|
||||
User existingUser = userRepository.findById(Id).orElseThrow(
|
||||
() -> new NotFoundException("User", "id", Id));
|
||||
|
||||
existingUser.setUsername(user.getUsername());
|
||||
existingUser.setEmail(user.getEmail());
|
||||
|
||||
userRepository.save(existingUser);
|
||||
|
||||
return existingUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUser(Integer Id) {
|
||||
userRepository.findById(Id).orElseThrow(
|
||||
() -> new NotFoundException("User", "id", Id));
|
||||
userRepository.deleteById(Id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
package com.example.demo.service;
|
||||
|
||||
public class RecipeService {
|
||||
public interface RecipeService {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
package com.example.demo.service;
|
||||
|
||||
public class UserService {
|
||||
import java.util.List;
|
||||
|
||||
import com.example.demo.entity.User;
|
||||
|
||||
public interface UserService {
|
||||
User saveUser(User user);
|
||||
List<User> getAllUsers();
|
||||
User getUserById(Integer Id);
|
||||
User updateUser(User user, Integer Id);
|
||||
void deleteUser(Integer Id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user