Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ build
.vscode
.idea
.DS_Store
app/.env
app/.env
.env
4 changes: 3 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,11 @@ dependencies {
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
// https://mvnrepository.com/artifact/io.github.cdimascio/java-dotenv
implementation group: 'io.github.cdimascio', name: 'java-dotenv', version: '5.2.2'

implementation("com.stripe:stripe-java:29.2.0")
// Use JUnit test framework.
testImplementation libs.junit
testImplementation("org.mockito:mockito-core:5.17.0")

testImplementation 'org.springframework.boot:spring-boot-starter-test:3.3.3'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import io.jsonwebtoken.ExpiredJwtException;

import java.io.IOException;

Expand Down Expand Up @@ -41,6 +42,8 @@ protected void doFilterInternal(

if (authHeader == null || !authHeader.startsWith("Bearer ")) {
System.out.println("No Authorization header or invalid format."); // Debug log
System.out.println("➡️ Requête vers : " + request.getRequestURI());
System.out.println("🔐 Authorization header : " + request.getHeader("Authorization"));
filterChain.doFilter(request, response);
return;
}
Expand All @@ -53,7 +56,13 @@ protected void doFilterInternal(
}

System.out.println("Extracted JWT: " + jwt); // Debug log
userEmail = jwtService.extractUserName(jwt);
try {
userEmail = jwtService.extractUserName(jwt);
} catch (ExpiredJwtException e) {
System.err.println("⛔ JWT expiré : " + e.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
System.out.println("Extracted email from JWT: " + userEmail); // Debug log

if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
"/api/v1/auth/logout",
"/api/trips/**",
"/api/waypoints/**",
"/api/v1/news/views/export"
"/api/v1/news/views/export",
"/api/v1/payment/**",
"/api/v1/cart/**"
).authenticated()
.anyRequest().authenticated()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package fr.parisnanterre.greentrip.backend.controller;

import fr.parisnanterre.greentrip.backend.entity.CartItem;
import fr.parisnanterre.greentrip.backend.entity.User;
import fr.parisnanterre.greentrip.backend.service.CartService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/cart")
@RequiredArgsConstructor
public class CartController {

private final CartService cartService;

@GetMapping
public List<CartItem> getCart(@AuthenticationPrincipal User user) {
return cartService.getCart(user);
}

@PostMapping("/{productId}")
public void addToCart(@AuthenticationPrincipal User user, @PathVariable Long productId) {
cartService.addToCart(user, productId);
}

@DeleteMapping("/{productId}")
public void removeFromCart(@AuthenticationPrincipal User user, @PathVariable Long productId) {
cartService.removeFromCart(user, productId);
}

@DeleteMapping("/clear")
public void clearCart(@AuthenticationPrincipal User user) {
cartService.clearCart(user);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package fr.parisnanterre.greentrip.backend.controller;

import fr.parisnanterre.greentrip.backend.entity.Order;
import fr.parisnanterre.greentrip.backend.entity.User;
import fr.parisnanterre.greentrip.backend.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderController {

private final OrderService orderService;

@PostMapping
public void createOrder(@AuthenticationPrincipal User user) {
orderService.createOrderFromCart(user);
}

@GetMapping
public List<Order> getOrders(@AuthenticationPrincipal User user) {
return orderService.getOrders(user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package fr.parisnanterre.greentrip.backend.controller;

import com.stripe.model.PaymentIntent;
import fr.parisnanterre.greentrip.backend.dto.PaymentRequest;
import fr.parisnanterre.greentrip.backend.service.PaymentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/api/v1/payment")
@RequiredArgsConstructor
public class PaymentController {

private final PaymentService paymentService;

@PostMapping
public ResponseEntity<Map<String, String>> pay(
@RequestBody PaymentRequest req,
@AuthenticationPrincipal UserDetails user
) throws Exception {
PaymentIntent intent = paymentService.handlePayment(req, user.getUsername());

return ResponseEntity.ok(Map.of("clientSecret", intent.getClientSecret()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package fr.parisnanterre.greentrip.backend.controller;

import fr.parisnanterre.greentrip.backend.entity.Product;
import fr.parisnanterre.greentrip.backend.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/v1/products")
@RequiredArgsConstructor
public class ProductController {

private final ProductRepository productRepo;

@GetMapping
public List<Product> getAllProducts() {
return productRepo.findAll();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fr.parisnanterre.greentrip.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PaymentRequest {

private Double amount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package fr.parisnanterre.greentrip.backend.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "cart")
public class CartItem {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
private User user;

@ManyToOne
private Product product;

private int quantity;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package fr.parisnanterre.greentrip.backend.entity;

import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;

@Entity
@Table(name = "`order`") // `order` est un mot réservé en SQL
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Order {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(optional = false)
private User user;

@ManyToOne(optional = false)
private Product product;

private int quantity;

private LocalDateTime orderDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package fr.parisnanterre.greentrip.backend.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "payment_history")
public class PaymentHistory {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
private Product product;

@ManyToOne
private User user;

private Double amount;
private String status;
private String paymentIntentId;
private LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package fr.parisnanterre.greentrip.backend.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "product")
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String description;
private Double price;
@Column(nullable = false)
private int stock;
private String imageUrl;

public Product(String name, String description, double price, String imageUrl, int stock) {
this.name = name;
this.description = description;
this.price = price;
this.imageUrl = imageUrl;
this.stock = stock;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package fr.parisnanterre.greentrip.backend.repository;

import fr.parisnanterre.greentrip.backend.entity.CartItem;
import fr.parisnanterre.greentrip.backend.entity.Product;
import fr.parisnanterre.greentrip.backend.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface CartItemRepository extends JpaRepository<CartItem, Long> {

List<CartItem> findByUser(User user);

Optional<CartItem> findByUserAndProduct(User user, Product product);

void deleteByUserAndProduct(User user, Product product);

void deleteAllByUser(User user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fr.parisnanterre.greentrip.backend.repository;

import fr.parisnanterre.greentrip.backend.entity.Order;
import fr.parisnanterre.greentrip.backend.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface OrderRepository extends JpaRepository<Order, Long> {

List<Order> findByUser(User user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package fr.parisnanterre.greentrip.backend.repository;

import fr.parisnanterre.greentrip.backend.entity.PaymentHistory;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PaymentHistoryRepository extends JpaRepository<PaymentHistory, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package fr.parisnanterre.greentrip.backend.repository;

import fr.parisnanterre.greentrip.backend.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {
}
Loading
Loading