beidl message

This commit is contained in:
Jonas Weissengruber 2023-12-20 00:41:20 +01:00
parent fc372073f3
commit 85d7162419
28 changed files with 413 additions and 84 deletions

21
http-requests/cart.http Normal file
View file

@ -0,0 +1,21 @@
### add
POST {{url}}/cart/add
Content-Type: application/json
{
"id": 9999999,
"cartEntries": [
{
"id": 2,
"amount": 20
}
]
}
### list
GET {{url}}/user/signin
### checkout
GET {{url}}/user/update
Authorization: Bearer {{token}}

View file

@ -0,0 +1,34 @@
### create
POST {{url}}/category/create
Authorization: Bearer {{token}}
Content-Type: application/json
{
"name": "Erwachsene",
"price": 25.5,
"stock": 100
}
### update
PUT {{url}}/category/update
Authorization: Bearer {{token}}
Content-Type: application/json
{
"id": 1,
"name": "Erwachsene",
"price": 25.5,
"stock": 100
}
### delete
DELETE {{url}}/category/delete/1
Authorization: Bearer {{token}}
### list
GET {{url}}/category/list
Authorization: Bearer {{token}}
### load
GET {{url}}/category/2
Authorization: Bearer {{token}}

53
http-requests/event.http Normal file
View file

@ -0,0 +1,53 @@
### create
POST {{url}}/event/create
# Authorization: Bearer {{token}}
Content-Type: application/json
{
"name": "Maturaball HTL Steyr 2024",
"from": "2023-03-02T20:00:00.000Z",
"to": "2023-03-03T05:00:00.000Z",
"description": "Maturaball der Abteilungen EL, IT, ME, Y",
"ticketCategories": [
{
"name": "Normal",
"price": 25,
"stock": 500
},
{
"name": "Maturanten",
"price": 0,
"stock": 500
},
{
"name": "Prechtl",
"price": 50,
"stock": 1
}
]
}
### update
PUT {{url}}/event/update
Authorization: Bearer {{token}}
Content-Type: application/json
{
"id": 2,
"name": "Maturaball HTL Steyr 2024",
"from": "2024-03-02T20:00:00.000Z",
"to": "2024-03-03T05:00:00.000Z",
"description": "Fluch der HTL"
}
### delete
DELETE {{url}}/event/delete/3
Authorization: Bearer {{token}}
### list future events
GET {{url}}/event/list
Authorization: Bearer {{token}}
### load
GET {{url}}/event/2
Authorization: Bearer {{token}}

View file

@ -1,5 +1,6 @@
{
"dev": {
"url": "http://localhost:8080/api/v1"
"url": "http://localhost:8080/api/v1",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZXRpY2tldCB1c2VyIHRva2VuIiwiZXhwIjoxNzAzMTAwNzQyLCJ1c2VySWQiOjIsImlhdCI6MTcwMzAxNDM0Mn0.D9HBxWy1vIP82XOh_ocjLO9HB0lK_rQGjgD3a7KQrOE"
}
}

View file

@ -10,22 +10,34 @@ Content-Type: application/json
}
### signin
GET {{url}}/user/signin
POST {{url}}/user/signin
Content-Type: application/json
{
"email": "admin@email.com",
"password": "a"
}
### update
PUT {{url}}/user/update
Authorization: Bearer {{token}}
Content-Type: application/json
{
"email": "ratp@htl-steyr.ac.at",
"firstname": "Peter Chef",
"lastname": "Rathgeb"
}
### delete
DELETE {{url}}/user/delete/99
DELETE {{url}}/user/delete/1
Authorization: Bearer {{token}}
### list
GET {{url}}/user/list
Authorization: Bearer {{token}}
### load
GET {{url}}/user/load/1
# eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZXRpY2tldCB1c2VyIHRva2VuIiwiZXhwIjoxNzAzMDU4MjczLCJ1c2VySWQiOjEsImlhdCI6MTcwMjk3MTg3M30.hC1N7hKYSIT-fqmaZ9bv3-YXOxQWdp-Sb5rZi4rARc0
GET {{url}}/user/load/2
Authorization: Bearer {{token}}

View file

@ -25,6 +25,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>

View file

@ -0,0 +1,11 @@
package me.jweissen.aeticket.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AdminOnly {
}

View file

@ -0,0 +1,63 @@
package me.jweissen.aeticket.aspect;
import jakarta.servlet.http.HttpServletRequest;
import me.jweissen.aeticket.model.Role;
import me.jweissen.aeticket.model.User;
import me.jweissen.aeticket.service.AuthService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Aspect
@Component
public class AuthAspect {
private final HttpServletRequest request;
private final AuthService authService;
public AuthAspect(HttpServletRequest request, AuthService authService) {
this.request = request;
this.authService = authService;
}
@Pointcut("@annotation(UserOnly)")
public void userOnly() { }
@Pointcut("@annotation(AdminOnly)")
public void adminOnly() { }
public Optional<User> authenticate() {
String tokenPrefix = "Bearer ";
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith(tokenPrefix)) {
return Optional.empty();
}
String token = authHeader.substring(tokenPrefix.length());
return authService.authenticate(token);
}
@Around("userOnly()")
public Object checkUser(ProceedingJoinPoint pjp) throws Throwable {
Optional<User> user = authenticate();
if (user.isEmpty()) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
return pjp.proceed();
}
@Around("adminOnly()")
public Object checkAdmin(ProceedingJoinPoint pjp) throws Throwable {
Optional<User> user = authenticate();
if (user.isEmpty()) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
} else if (user.get().getRole() != Role.ADMIN) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
return pjp.proceed();
}
}

View file

@ -0,0 +1,11 @@
package me.jweissen.aeticket.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserOnly {
}

View file

@ -1,15 +1,13 @@
package me.jweissen.aeticket.controller;
import me.jweissen.aeticket.dto.request.CartAddRequestDto;
import me.jweissen.aeticket.dto.response.CartEntryResponseDto;
import me.jweissen.aeticket.dto.response.CartEventResponseDto;
import me.jweissen.aeticket.dto.response.CheckoutResponseDto;
import me.jweissen.aeticket.service.AuthService;
import me.jweissen.aeticket.service.CartService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -17,26 +15,29 @@ import java.util.List;
@RequestMapping("/cart")
public class CartController {
private final CartService cartService;
private final AuthService authService;
public CartController(CartService cartService) {
public CartController(CartService cartService, AuthService authService) {
this.cartService = cartService;
this.authService = authService;
}
@PostMapping("/add")
public ResponseEntity<Void> addEntry(CartAddRequestDto dto) {
// TODO
return ResponseEntity.noContent().build();
public ResponseEntity<Void> addEntry(@RequestBody CartAddRequestDto dto) {
if (!cartService.add(dto, authService.getCurrentUser().getCurrentCart())) {
// user gave invalid category id(s)
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
@GetMapping("/list")
public ResponseEntity<List<CartEntryResponseDto>> getCartEntries() {
// TODO
return new ResponseEntity<>(null, HttpStatus.OK);
public ResponseEntity<List<CartEventResponseDto>> getCartEntries() {
return new ResponseEntity<>(cartService.toDto(authService.getCurrentUser().getCurrentCart()), HttpStatus.OK);
}
@GetMapping("/checkout")
public ResponseEntity<CheckoutResponseDto> checkout() {
// TODO
return ResponseEntity.badRequest().build();
return new ResponseEntity<>(cartService.checkout(authService.getCurrentUser().getCurrentCart()), HttpStatus.OK);
}
}

View file

@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/eventcategory")
@RequestMapping("/category")
public class CategoryController {
private final CategoryService categoryService;
@ -26,35 +26,35 @@ public class CategoryController {
public ResponseEntity<Void> create(@RequestBody CategoryRequestDto dto) {
// TODO admin only
categoryService.create(dto);
return new ResponseEntity<>(HttpStatus.CREATED);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@PutMapping("/update")
public ResponseEntity<Void> update(@RequestBody CategoryUpdateRequestDto dto) {
// TODO admin only
System.out.println(dto);
if (!categoryService.update(dto)) {
return ResponseEntity.notFound().build();
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
return new ResponseEntity<>(HttpStatus.CREATED);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@DeleteMapping("/delete/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
// TODO admin only
categoryService.delete(id);
return ResponseEntity.noContent().build();
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
@GetMapping("/{id}")
public ResponseEntity<CategoryResponseDto> getById(@PathVariable Long id) {
return categoryService.getById(id)
.map(categoryResponseDto -> new ResponseEntity<>(categoryResponseDto, HttpStatus.OK))
.orElseGet(() -> ResponseEntity.notFound().build());
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).build());
}
@GetMapping("/list")
public ResponseEntity<List<CategoryResponseDto>> getAll() {
return new ResponseEntity<>(categoryService.getAll(), HttpStatus.OK);
}
}

View file

@ -23,28 +23,28 @@ public class EventController {
public ResponseEntity<Void> create(@RequestBody EventRequestDto event) {
// TODO admin only
eventService.create(event);
return new ResponseEntity<>(HttpStatus.CREATED);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@PutMapping("/update")
public ResponseEntity<Void> update(@RequestBody EventUpdateRequestDto event) {
// TODO admin only
eventService.update(event);
return new ResponseEntity<>(HttpStatus.CREATED);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
@DeleteMapping("/delete/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
// TODO admin only
eventService.delete(id);
return ResponseEntity.noContent().build();
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
@GetMapping("/{id}")
public ResponseEntity<EventResponseDto> getById(@PathVariable Long id) {
return eventService.getById(id)
.map(eventResponseDto -> new ResponseEntity<>(eventResponseDto, HttpStatus.OK))
.orElseGet(() -> ResponseEntity.notFound().build());
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).build());
}
@GetMapping("/list")

View file

@ -1,6 +1,5 @@
package me.jweissen.aeticket.controller;
import me.jweissen.aeticket.aspect.Permissions;
import me.jweissen.aeticket.dto.request.LoginRequestDto;
import me.jweissen.aeticket.dto.request.SignupRequestDto;
import me.jweissen.aeticket.dto.request.UserUpdateRequestDto;
@ -39,30 +38,29 @@ public class UserController {
public ResponseEntity<Void> update(@RequestBody UserUpdateRequestDto user) {
// TODO admin only
if (!userService.update(user)) {
return ResponseEntity.notFound().build();
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
return ResponseEntity.noContent().build();
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
@DeleteMapping("/delete/{id}")
public ResponseEntity<Void> delete(@PathVariable Integer id) {
public ResponseEntity<Void> delete(@PathVariable Long id) {
// TODO admin only
userService.delete(id);
return ResponseEntity.noContent().build();
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
@GetMapping("/list")
@Permissions(user = false)
public ResponseEntity<List<UserResponseDto>> getAll() {
// TODO admin only
return new ResponseEntity<>(userService.getAll(), HttpStatus.OK);
}
@GetMapping("/load/{id}")
public ResponseEntity<UserResponseDto> getById(@PathVariable Integer id) {
public ResponseEntity<UserResponseDto> getById(@PathVariable Long id) {
// TODO admin only
return userService.getById(id)
.map(userResponseDto -> new ResponseEntity<>(userResponseDto, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(null, HttpStatus.NOT_FOUND));
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).build());
}
}

View file

@ -1,4 +1,7 @@
package me.jweissen.aeticket.dto.request;
public record EventUpdateRequestDto(Long id) {
import java.util.Date;
// no ticketCategories to prevent undefined behaviour
public record EventUpdateRequestDto(Long id, String name, Date from, Date to, String description) {
}

View file

@ -1,4 +1,4 @@
package me.jweissen.aeticket.dto.request;
public record UserUpdateRequestDto(Integer id, String firstname, String lastname, String email) {
public record UserUpdateRequestDto(Long id, String firstname, String lastname, String email) {
}

View file

@ -15,6 +15,9 @@ public class Cart {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Boolean checkedOut = false;
@OneToMany(mappedBy = "cart")
@Column(nullable = false)
private List<CartEntry> cartEntries;

View file

@ -1,26 +1,30 @@
package me.jweissen.aeticket.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.*;
@Entity
@Table
@Getter
@Setter
@NoArgsConstructor
@RequiredArgsConstructor
public class CartEntry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne
@NonNull
@JoinColumn(nullable = false)
private Cart cart;
@ManyToOne
@NonNull
@JoinColumn(nullable = false)
private Category category;
@Column(nullable = false)
private int amount;
@NonNull
private Integer amount;
}

View file

@ -13,7 +13,7 @@ import java.util.List;
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@RequiredArgsConstructor
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ -21,7 +21,7 @@ public class Event {
@Column(nullable = false)
@NonNull
private String title;
private String name;
@Column(nullable = false)
@NonNull
@ -35,7 +35,7 @@ public class Event {
@NonNull
private Date end;
@OneToMany(mappedBy = "event")
@OneToMany(mappedBy = "event", cascade = CascadeType.ALL, orphanRemoval = true)
@Column(nullable = false)
private List<Category> categories = new ArrayList<>();

View file

@ -3,6 +3,7 @@ package me.jweissen.aeticket.model;
import jakarta.persistence.*;
import lombok.*;
import java.util.Date;
import java.util.List;
@Entity
@ -35,11 +36,19 @@ public class User {
@Column
private String token;
@Column
private Date tokenValidUntil;
@Column(nullable = false)
@Enumerated(EnumType.ORDINAL)
@NonNull
private Role role;
@OneToOne
@JoinColumn(nullable = false)
@NonNull
private Cart currentCart;
@OneToMany(mappedBy = "user")
private List<Cart> carts;
}

View file

@ -2,6 +2,10 @@ package me.jweissen.aeticket.repository;
import me.jweissen.aeticket.model.Cart;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface CartRepository extends JpaRepository<Cart, Integer> {
@Query("SELECT sum(ce.amount * c.price) FROM CartEntry ce INNER JOIN Category c ON ce.category = c WHERE ce.cart = :cart")
Integer getCheckoutPrice(@Param("cart") Cart cart);
}

View file

@ -2,6 +2,10 @@ package me.jweissen.aeticket.repository;
import me.jweissen.aeticket.model.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface CategoryRepository extends JpaRepository<Category, Long> {
@Query("SELECT c.stock - sum(ce.amount) FROM Category c INNER JOIN CartEntry ce ON c = ce.category WHERE c = :category GROUP BY c")
Integer availableTickets(@Param("category") Category category);
}

View file

@ -3,7 +3,7 @@ package me.jweissen.aeticket.repository;
import me.jweissen.aeticket.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
public interface UserRepository extends JpaRepository<User, Long> {
User findByToken(String token);
User findByEmail(String email);
}

View file

@ -1,29 +1,56 @@
package me.jweissen.aeticket.service;
import lombok.Getter;
import me.jweissen.aeticket.model.Role;
import me.jweissen.aeticket.model.User;
import me.jweissen.aeticket.repository.UserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.Optional;
@Service
public class AuthService {
private final JwtService jwtService;
private final UserRepository userRepository;
private final Long tokenValidForMillis;
@Getter
private User currentUser;
public AuthService(JwtService jwtService, UserRepository userRepository) {
public AuthService(
JwtService jwtService,
UserRepository userRepository,
@Value("${token.validForHours}") Long tokenValidForHours) {
this.tokenValidForMillis = 1000L * 3600 * tokenValidForHours;
this.jwtService = jwtService;
this.userRepository = userRepository;
}
public Optional<Role> getRole(String token) {
User user = userRepository.findByToken(token);
if (user == null) {
public void extendToken(User user) {
user.setTokenValidUntil(new Date(System.currentTimeMillis() + tokenValidForMillis));
userRepository.save(user);
}
public Optional<User> authenticate(String token) {
Optional<Long> userIdOptional = jwtService.getUserId(token);
// token not valid or userId
if (userIdOptional.isEmpty()) {
return Optional.empty();
}
return Optional.of(user.getRole());
Optional<User> userOptional = userRepository.findById(userIdOptional.get());
if (userOptional.isEmpty()) {
// user with id not found
return Optional.empty();
}
User user = userOptional.get();
if (user.getTokenValidUntil().before(new Date())) {
// token expired
return Optional.empty();
}
// success
extendToken(user);
currentUser = user;
return Optional.of(user);
}
}

View file

@ -1,23 +1,36 @@
package me.jweissen.aeticket.service;
import me.jweissen.aeticket.dto.response.CartEntryResponseDto;
import me.jweissen.aeticket.dto.request.CartAddRequestDto;
import me.jweissen.aeticket.dto.request.CartEntryRequestDto;
import me.jweissen.aeticket.dto.response.CartEventResponseDto;
import me.jweissen.aeticket.dto.response.CheckoutResponseDto;
import me.jweissen.aeticket.model.Cart;
import me.jweissen.aeticket.model.CartEntry;
import me.jweissen.aeticket.model.Category;
import me.jweissen.aeticket.model.Event;
import me.jweissen.aeticket.repository.CartEntryRepository;
import me.jweissen.aeticket.repository.CartRepository;
import me.jweissen.aeticket.repository.CategoryRepository;
import me.jweissen.aeticket.repository.UserRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class CartService {
private final CartRepository cartRepository;
private final CartEntryRepository cartEntryRepository;
private final CategoryRepository categoryRepository;
private final UserRepository userRepository;
public CartService(CartRepository cartRepository, CartEntryRepository cartEntryRepository) {
public CartService(CartRepository cartRepository, CartEntryRepository cartEntryRepository,
CategoryRepository categoryRepository,
UserRepository userRepository) {
this.cartRepository = cartRepository;
this.cartEntryRepository = cartEntryRepository;
this.categoryRepository = categoryRepository;
this.userRepository = userRepository;
}
public List<CartEventResponseDto> toDto(Cart cart) {
@ -27,7 +40,7 @@ public class CartService {
return distinctEvents.stream().map(event ->
new CartEventResponseDto(
event.getId(),
event.getTitle(),
event.getName(),
event.getStart(),
event.getEnd(),
event.getDescription(),
@ -35,6 +48,35 @@ public class CartService {
)).toList();
}
//public List<CartEntryResponseDto> getCartByAuthToken() {
public boolean add(CartAddRequestDto dto, Cart cart) {
// posting the eventIds is redundant so, those are ignored
for (CartEntryRequestDto cartEntryDto: dto.cartEntries()) {
Optional<Category> categoryOptional = categoryRepository.findById(cartEntryDto.id());
if (categoryOptional.isEmpty()) {
// category id not found
return false;
}
Category category = categoryOptional.get();
if (cartEntryDto.amount() > categoryRepository.availableTickets(category)) {
// wants to order more tickets than available
return false;
}
cart.getCartEntries().add(new CartEntry(cart, category, cartEntryDto.amount()));
}
cartRepository.save(cart);
return true;
}
public CheckoutResponseDto checkout(Cart cart) {
cart.setCheckedOut(true);
cartRepository.save(cart);
// reset current cart
Cart newCart = new Cart();
newCart = cartRepository.save(newCart);
cart.getUser().setCurrentCart(newCart);
userRepository.save(cart.getUser());
return new CheckoutResponseDto(
CategoryService.centsToEuros(cartRepository.getCheckoutPrice(cart))
);
}
}

View file

@ -27,6 +27,10 @@ public class CategoryService {
);
}
public static List<Category> fromDtos(List<CategoryRequestDto> dtos) {
return dtos.stream().map(CategoryService::fromDto).toList();
}
public static CategoryResponseDto toDto(Category category) {
return new CategoryResponseDto(
category.getId(),
@ -54,6 +58,7 @@ public class CategoryService {
}
public boolean update(CategoryUpdateRequestDto dto) {
System.out.println(dto);
return categoryRepository.findById(dto.id())
.map(category -> {
category.setName(dto.name());

View file

@ -3,7 +3,9 @@ package me.jweissen.aeticket.service;
import me.jweissen.aeticket.dto.request.EventRequestDto;
import me.jweissen.aeticket.dto.request.EventUpdateRequestDto;
import me.jweissen.aeticket.dto.response.EventResponseDto;
import me.jweissen.aeticket.model.Category;
import me.jweissen.aeticket.model.Event;
import me.jweissen.aeticket.repository.CategoryRepository;
import me.jweissen.aeticket.repository.EventRepository;
import org.springframework.stereotype.Service;
@ -13,24 +15,27 @@ import java.util.Optional;
@Service
public class EventService {
private final EventRepository eventRepository;
private final CategoryRepository categoryRepository;
public EventService(EventRepository eventRepository) {
public EventService(EventRepository eventRepository,
CategoryRepository categoryRepository) {
this.eventRepository = eventRepository;
this.categoryRepository = categoryRepository;
}
public static Event fromDto(EventRequestDto dto) {
return Event.builder()
.title(dto.name())
.description(dto.description())
.start(dto.from())
.end(dto.to())
.build();
return new Event(
dto.name(),
dto.description(),
dto.from(),
dto.to()
);
}
public static EventResponseDto toDto(Event event) {
return new EventResponseDto(
event.getId(),
event.getTitle(),
event.getName(),
event.getStart(),
event.getEnd(),
event.getDescription(),
@ -42,14 +47,23 @@ public class EventService {
return events.stream().map(EventService::toDto).toList();
}
public void create(EventRequestDto event) {
eventRepository.save(EventService.fromDto(event));
public void create(EventRequestDto dto) {
Event event = EventService.fromDto(dto);
event = eventRepository.save(event);
Event finalEvent = event;
List<Category> categories = CategoryService.fromDtos(dto.ticketCategories());
categories.forEach(c -> c.setEvent(finalEvent));
categoryRepository.saveAll(categories);
}
public boolean update(EventUpdateRequestDto dto) {
return eventRepository.findById(dto.id())
.map(event -> {
// dto auf object assignen
event.setName(dto.name());
event.setDescription(dto.description());
event.setStart(dto.from());
event.setEnd(dto.to());
eventRepository.save(event);
return true;
})
.orElse(false);

View file

@ -6,6 +6,8 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import me.jweissen.aeticket.model.User;
import me.jweissen.aeticket.repository.UserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@ -17,10 +19,8 @@ public class JwtService {
private final JWTVerifier jwtVerifier;
private final Algorithm algorithm;
private final String userIdClaimKey = "userId";
private final Long tokenValidForMillis;
public JwtService(@Value("${token.secret}") String secret, @Value("${token.validForHours}") Long tokenValidForHours) {
tokenValidForMillis = 1000L * 3600 * tokenValidForHours;
public JwtService(@Value("${token.secret}") String secret) {
algorithm = Algorithm.HMAC256(secret);
jwtVerifier = JWT.require(algorithm).build();
}
@ -29,8 +29,6 @@ public class JwtService {
return JWT.create()
.withSubject("aeticket user token")
.withClaim(userIdClaimKey, userId)
.withIssuedAt(new Date())
.withExpiresAt(new Date(System.currentTimeMillis() + tokenValidForMillis))
.sign(algorithm);
}
@ -42,11 +40,16 @@ public class JwtService {
// token not valid
return Optional.empty();
}
// token expired
if (decodedJWT.getExpiresAt().before(new Date())) {
Claim userIdClaim = decodedJWT.getClaim(userIdClaimKey);
if (userIdClaim.isNull()) {
// userId claim not present
return Optional.empty();
}
Claim claim = decodedJWT.getClaim(userIdClaimKey);
return Optional.of(claim.asLong());
Long userId = userIdClaim.asLong();
if (userId == null) {
// userId claim not a long
return Optional.empty();
}
return Optional.of(userId);
}
}

View file

@ -5,6 +5,7 @@ import me.jweissen.aeticket.dto.request.SignupRequestDto;
import me.jweissen.aeticket.dto.request.UserUpdateRequestDto;
import me.jweissen.aeticket.dto.response.TokenResponseDto;
import me.jweissen.aeticket.dto.response.UserResponseDto;
import me.jweissen.aeticket.model.Cart;
import me.jweissen.aeticket.model.Role;
import me.jweissen.aeticket.model.User;
import me.jweissen.aeticket.repository.UserRepository;
@ -38,7 +39,8 @@ public class UserService {
dto.lastname(),
dto.email(),
dto.password(),
Role.USER
Role.USER,
new Cart()
);
}
@ -62,7 +64,7 @@ public class UserService {
return new TokenResponseDto(generateToken(user));
}
public void delete(Integer id) {
public void delete(Long id) {
userRepository.deleteById(id);
}
@ -87,7 +89,7 @@ public class UserService {
return true;
}
public Optional<UserResponseDto> getById(Integer id) {
public Optional<UserResponseDto> getById(Long id) {
return userRepository.findById(id).map(UserService::toDto);
}
}