this thing has the database

This commit is contained in:
durn
2026-02-26 17:38:13 -07:00
parent e04c62a574
commit 372799f13b
54 changed files with 1496 additions and 0 deletions
@@ -0,0 +1,29 @@
package com.example.database;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "favorites")
public class Favorite {
@EmbeddedId
private FavoriteId id;
@Column(name = "created_at")
private LocalDateTime createdAt;
public Favorite() {}
public Favorite(Integer userId, Integer recipeId) {
this.id = new FavoriteId(userId, recipeId);
this.createdAt = LocalDateTime.now();
}
// Getters and setters
public FavoriteId getId() { return id; }
public void setId(FavoriteId id) { this.id = id; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}
@@ -0,0 +1,42 @@
package com.example.database;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@Embeddable
public class FavoriteId implements Serializable {
private static final long serialVersionUID = 7241804509064720087L;
private Integer userId;
private Integer recipeId;
public FavoriteId() {}
public FavoriteId(Integer userId, Integer recipeId) {
this.userId = userId;
this.recipeId = recipeId;
}
// Getters and setters
public Integer getUserId() { return userId; }
public void setUserId(Integer userId) { this.userId = userId; }
public Integer getRecipeId() { return recipeId; }
public void setRecipeId(Integer recipeId) { this.recipeId = recipeId; }
// equals and hashCode required for composite keys
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FavoriteId)) return false;
FavoriteId that = (FavoriteId) o;
return Objects.equals(userId, that.userId) &&
Objects.equals(recipeId, that.recipeId);
}
@Override
public int hashCode() {
return Objects.hash(userId, recipeId);
}
}
@@ -0,0 +1,13 @@
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
}
@@ -0,0 +1,43 @@
package com.example.database;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "recipe_images") // keep table name the same
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "recipe_id", nullable = false)
private Integer recipeId;
@Column(name = "image_url", nullable = false)
private String imageUrl;
@Column(name = "created_at")
private LocalDateTime createdAt;
public Image() {}
public Image(Integer recipeId, String imageUrl) {
this.recipeId = recipeId;
this.imageUrl = imageUrl;
this.createdAt = LocalDateTime.now();
}
// 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 String getImageUrl() { return imageUrl; }
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}
@@ -0,0 +1,10 @@
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);
}
@@ -0,0 +1,38 @@
package com.example.database;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Column;
@Entity
@Table(name = "ingredients", uniqueConstraints = {
@UniqueConstraint(columnNames = "name")
})
public class Ingredient {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(nullable = false, unique = true)
private String name;
// Default constructor required by JPA
public Ingredient() {}
// Convenience constructor
public Ingredient(String name) {
this.name = name;
}
// Getters and setters
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
@@ -0,0 +1,9 @@
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);
}
@@ -0,0 +1,84 @@
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; }
}
@@ -0,0 +1,57 @@
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; }
}
@@ -0,0 +1,10 @@
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);
}
@@ -0,0 +1,8 @@
package com.example.database;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface RecipeRepo extends CrudRepository<Recipe, Integer> {
}
@@ -0,0 +1,53 @@
package com.example.database;
import jakarta.persistence.*;
@Entity
@Table(name = "recipe_tags")
public class RecipeTag {
@EmbeddedId
private RecipeTagId id;
@ManyToOne
@MapsId("recipeId")
@JoinColumn(name = "recipe_id", nullable = false)
private Recipe recipe;
@ManyToOne
@MapsId("tagId")
@JoinColumn(name = "tag_id", nullable = false)
private Tag tag;
public RecipeTag() {}
public RecipeTag(Recipe recipe, Tag tag) {
this.recipe = recipe;
this.tag = tag;
this.id = new RecipeTagId(recipe.getId(), tag.getId());
}
public RecipeTagId getId() {
return id;
}
public void setId(RecipeTagId id) {
this.id = id;
}
public Recipe getRecipe() {
return recipe;
}
public Tag getTag() {
return tag;
}
public void setRecipe(Recipe recipe) {
this.recipe = recipe;
}
public void setTag(Tag tag) {
this.tag = tag;
}
}
@@ -0,0 +1,56 @@
package com.example.database;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import java.io.Serializable;
import java.util.Objects;
@Embeddable
public class RecipeTagId implements Serializable {
private static final long serialVersionUID = 5272431101708393749L;
@Column(name = "recipe_id")
private Integer recipeId;
@Column(name = "tag_id")
private Integer tagId;
public RecipeTagId() {}
public RecipeTagId(Integer recipeId, Integer tagId) {
this.recipeId = recipeId;
this.tagId = tagId;
}
public Integer getRecipeId() {
return recipeId;
}
public void setRecipeId(Integer recipeId) {
this.recipeId = recipeId;
}
public Integer getTagId() {
return tagId;
}
public void setTagId(Integer tagId) {
this.tagId = tagId;
}
// REQUIRED for composite keys
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RecipeTagId)) return false;
RecipeTagId that = (RecipeTagId) o;
return Objects.equals(recipeId, that.recipeId) &&
Objects.equals(tagId, that.tagId);
}
@Override
public int hashCode() {
return Objects.hash(recipeId, tagId);
}
}
@@ -0,0 +1,11 @@
package com.example.database;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface RecipeTagRepo extends JpaRepository<RecipeTag, RecipeTagId> {
}
@@ -0,0 +1,43 @@
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; }
}
@@ -0,0 +1,11 @@
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
}
@@ -0,0 +1,39 @@
package com.example.database;
import jakarta.persistence.*;
@Entity
@Table(name = "tags")
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(nullable = false, unique = true)
private String name;
// Required by JPA
public Tag() {}
public Tag(String name) {
this.name = name;
}
// Getters and setters
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,12 @@
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);
}
@@ -0,0 +1,61 @@
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; }
}
@@ -0,0 +1,7 @@
package com.example.database;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepo extends JpaRepository<User, Integer> {
User findByUsername(String username);
}
@@ -0,0 +1,13 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RecipeDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RecipeDemoApplication.class, args);
}
}
@@ -0,0 +1,37 @@
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.cors.CorsConfigurationSource;
import java.util.List;
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
// Allow your frontend origin (adjust if different)
config.setAllowedOrigins(List.of("http://localhost:3000",
"http://localhost:5173"));
// Allow common HTTP methods
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
// Allow headers like Authorization (for JWT later)
config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
// Allow cookies if using sessions
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
@@ -0,0 +1,5 @@
package com.example.demo.config;
public class SecurityConfig {
}
@@ -0,0 +1,5 @@
package com.example.demo.controller;
public class AuthController {
}
@@ -0,0 +1,23 @@
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HealthController {
@GetMapping("/api/health")
public Map<String, Object> healthCheck() {
Map<String, Object> response = new HashMap<>();
response.put("status", "UP");
response.put("timestamp", LocalDateTime.now());
response.put("service", "Recipe Backend");
return response;
}
}
@@ -0,0 +1,5 @@
package com.example.demo.controller;
public class RecipeController {
}
@@ -0,0 +1,5 @@
package com.example.demo.dto;
public class AuthResponse {
}
@@ -0,0 +1,5 @@
package com.example.demo.dto;
public class IngredientDto {
}
@@ -0,0 +1,5 @@
package com.example.demo.dto;
public class LoginRequest {
}
@@ -0,0 +1,5 @@
package com.example.demo.dto;
public class RecipeCreateRequest {
}
@@ -0,0 +1,5 @@
package com.example.demo.dto;
public class RecipeResponse {
}
@@ -0,0 +1,5 @@
package com.example.demo.dto;
public class RegisterRequest {
}
@@ -0,0 +1,5 @@
package com.example.demo.dto;
public class StepDto {
}
@@ -0,0 +1,5 @@
package com.example.demo.entity;
public class Recipe {
}
@@ -0,0 +1,5 @@
package com.example.demo.entity;
public class RecipeIngredient {
}
@@ -0,0 +1,5 @@
package com.example.demo.entity;
public class Step {
}
@@ -0,0 +1,5 @@
package com.example.demo.entity;
public class User {
}
@@ -0,0 +1,5 @@
package com.example.demo.exception;
public class BadRequestException {
}
@@ -0,0 +1,5 @@
package com.example.demo.exception;
public class ErrorResponse {
}
@@ -0,0 +1,5 @@
package com.example.demo.exception;
public class GlobalExceptionHandler {
}
@@ -0,0 +1,5 @@
package com.example.demo.exception;
public class NotFoundException {
}
@@ -0,0 +1,5 @@
package com.example.demo.repository;
public class RecipeRepository {
}
@@ -0,0 +1,5 @@
package com.example.demo.repository;
public class UserRepository {
}
@@ -0,0 +1,5 @@
package com.example.demo.service;
public class AuthService {
}
@@ -0,0 +1,5 @@
package com.example.demo.service;
public class RecipeService {
}
@@ -0,0 +1,5 @@
package com.example.demo.service;
public class UserService {
}
@@ -0,0 +1,20 @@
spring.application.name=demo
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=springuser
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.open-in-view=false
#spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
server.port=8080