Compare commits
2 Commits
e20be63e5e
...
0ee56e4e52
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ee56e4e52 | |||
| 4df0b36f45 |
@@ -2,8 +2,10 @@ package de.zendric.app.xpensely_server;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableScheduling
|
||||||
public class XpenselyServerApplication {
|
public class XpenselyServerApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package de.zendric.app.xpensely_server.controller;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -41,6 +42,14 @@ public class AppUserController {
|
|||||||
return ResponseEntity.status(HttpStatus.CREATED).body(appUser);
|
return ResponseEntity.status(HttpStatus.CREATED).body(appUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/createUser")
|
||||||
|
public ResponseEntity<?> createUsername(@RequestBody AppUser user, Authentication authentication) {
|
||||||
|
String googleUserId = authentication.getName();
|
||||||
|
// Validate and store the username with googleUserId
|
||||||
|
|
||||||
|
return ResponseEntity.ok("Username created successfully");
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping
|
@DeleteMapping
|
||||||
public String deleteUser(@RequestParam Long id) {
|
public String deleteUser(@RequestParam Long id) {
|
||||||
AppUser user = userService.deleteUserById(id);
|
AppUser user = userService.deleteUserById(id);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.zendric.app.xpensely_server.controller;
|
package de.zendric.app.xpensely_server.controller;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -16,19 +17,24 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import de.zendric.app.xpensely_server.model.AppUser;
|
||||||
import de.zendric.app.xpensely_server.model.Expense;
|
import de.zendric.app.xpensely_server.model.Expense;
|
||||||
import de.zendric.app.xpensely_server.model.ExpenseList;
|
import de.zendric.app.xpensely_server.model.ExpenseList;
|
||||||
|
import de.zendric.app.xpensely_server.model.InviteRequest;
|
||||||
import de.zendric.app.xpensely_server.services.ExpenseListService;
|
import de.zendric.app.xpensely_server.services.ExpenseListService;
|
||||||
|
import de.zendric.app.xpensely_server.services.UserService;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/expenselist")
|
@RequestMapping("/api/expenselist")
|
||||||
class ExpenseListController {
|
class ExpenseListController {
|
||||||
|
|
||||||
private ExpenseListService expenseListService;
|
private ExpenseListService expenseListService;
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExpenseListController(ExpenseListService expenseListService) {
|
public ExpenseListController(ExpenseListService expenseListService, UserService userService) {
|
||||||
this.expenseListService = expenseListService;
|
this.expenseListService = expenseListService;
|
||||||
|
this.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/all")
|
@GetMapping("/all")
|
||||||
@@ -129,4 +135,36 @@ class ExpenseListController {
|
|||||||
return new ResponseEntity<>(null, HttpStatus.EXPECTATION_FAILED);
|
return new ResponseEntity<>(null, HttpStatus.EXPECTATION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{listId}/invite")
|
||||||
|
public ResponseEntity<String> generateInvite(@PathVariable Long listId) {
|
||||||
|
String inviteCode = expenseListService.generateInviteCode(listId);
|
||||||
|
return ResponseEntity.ok(inviteCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/accept-invite")
|
||||||
|
public ResponseEntity<?> acceptInvite(@RequestBody InviteRequest inviteRequest) {
|
||||||
|
ExpenseList list = expenseListService.findByInviteCode(inviteRequest.getInviteCode());
|
||||||
|
|
||||||
|
if (list == null || list.getInviteCodeExpiration() == null ||
|
||||||
|
list.getInviteCodeExpiration().isBefore(LocalDateTime.now())) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Invalid or expired invite code");
|
||||||
|
}
|
||||||
|
if (list.getSharedWith() != null) {
|
||||||
|
return ResponseEntity.status(HttpStatus.IM_USED).body("List has already been shared");
|
||||||
|
}
|
||||||
|
AppUser user = null;
|
||||||
|
try {
|
||||||
|
user = userService.getUser(inviteRequest.getUserId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("User not found");
|
||||||
|
}
|
||||||
|
if (user != null) {
|
||||||
|
list.setSharedWith(user);
|
||||||
|
expenseListService.save(list);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("User not found");
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok("User added to the list");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package de.zendric.app.xpensely_server.model;
|
package de.zendric.app.xpensely_server.model;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
@@ -9,7 +11,6 @@ import jakarta.persistence.Entity;
|
|||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.GenerationType;
|
import jakarta.persistence.GenerationType;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.ManyToMany;
|
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -29,11 +30,15 @@ public class ExpenseList {
|
|||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
private String inviteCode;
|
||||||
|
@JsonIgnore
|
||||||
|
private LocalDateTime inviteCodeExpiration;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
private AppUser owner;
|
private AppUser owner;
|
||||||
|
|
||||||
@ManyToMany
|
@ManyToOne
|
||||||
private List<AppUser> sharedWith;
|
private AppUser sharedWith;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "expenseList", cascade = CascadeType.ALL, orphanRemoval = true)
|
@OneToMany(mappedBy = "expenseList", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
@JsonManagedReference
|
@JsonManagedReference
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.zendric.app.xpensely_server.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class InviteRequest {
|
||||||
|
private String inviteCode;
|
||||||
|
private Long userId;
|
||||||
|
}
|
||||||
@@ -10,4 +10,6 @@ import de.zendric.app.xpensely_server.model.ExpenseList;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface ExpenseListRepository extends JpaRepository<ExpenseList, Long> {
|
public interface ExpenseListRepository extends JpaRepository<ExpenseList, Long> {
|
||||||
List<ExpenseList> findByOwnerId(Long ownerId);
|
List<ExpenseList> findByOwnerId(Long ownerId);
|
||||||
|
|
||||||
|
ExpenseList findByInviteCode(String inviteCode);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package de.zendric.app.xpensely_server.services;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import de.zendric.app.xpensely_server.model.ExpenseList;
|
||||||
|
import de.zendric.app.xpensely_server.repo.ExpenseListRepository;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
|
||||||
|
public class CleanupService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ExpenseListRepository expenseListRepository;
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 0 0 * * ?") // Runs daily at midnight
|
||||||
|
public void cleanupExpiredInvites() {
|
||||||
|
List<ExpenseList> expiredLists = expenseListRepository.findAll().stream()
|
||||||
|
.filter(list -> list.getInviteCodeExpiration() != null &&
|
||||||
|
list.getInviteCodeExpiration().isBefore(LocalDateTime.now()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
for (ExpenseList list : expiredLists) {
|
||||||
|
list.setInviteCode(null);
|
||||||
|
list.setInviteCodeExpiration(null);
|
||||||
|
expenseListRepository.save(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package de.zendric.app.xpensely_server.services;
|
package de.zendric.app.xpensely_server.services;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -64,18 +66,16 @@ public class ExpenseListService {
|
|||||||
List<ExpenseList> allLists = repository.findAll();
|
List<ExpenseList> allLists = repository.findAll();
|
||||||
List<ExpenseList> userSpecificList = new ArrayList<>();
|
List<ExpenseList> userSpecificList = new ArrayList<>();
|
||||||
for (ExpenseList expenseList : allLists) {
|
for (ExpenseList expenseList : allLists) {
|
||||||
List<AppUser> sharedWith = expenseList.getSharedWith();
|
AppUser sharedWith = expenseList.getSharedWith();
|
||||||
|
|
||||||
if (expenseList.getOwner().getId().equals(id)) {
|
if (expenseList.getOwner().getId().equals(id)) {
|
||||||
userSpecificList.add(expenseList);
|
userSpecificList.add(expenseList);
|
||||||
} else {
|
} else {
|
||||||
for (AppUser user : sharedWith) {
|
if (sharedWith != null && sharedWith.getId().equals(id)) {
|
||||||
if (user.getId().equals(id)) {
|
|
||||||
userSpecificList.add(expenseList);
|
userSpecificList.add(expenseList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return userSpecificList;
|
return userSpecificList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,19 +83,18 @@ public class ExpenseListService {
|
|||||||
List<ExpenseList> allLists = repository.findAll();
|
List<ExpenseList> allLists = repository.findAll();
|
||||||
List<ExpenseList> userSpecificList = new ArrayList<>();
|
List<ExpenseList> userSpecificList = new ArrayList<>();
|
||||||
for (ExpenseList expenseList : allLists) {
|
for (ExpenseList expenseList : allLists) {
|
||||||
List<AppUser> sharedWith = expenseList.getSharedWith();
|
AppUser sharedWith = expenseList.getSharedWith();
|
||||||
|
|
||||||
if (expenseList.getOwner().getUsername().equals(username)) {
|
if (expenseList.getOwner().getUsername().equals(username)) {
|
||||||
userSpecificList.add(expenseList);
|
userSpecificList.add(expenseList);
|
||||||
} else {
|
} else {
|
||||||
for (AppUser user : sharedWith) {
|
if (sharedWith != null && sharedWith.getUsername().equals(username)) {
|
||||||
if (user.getUsername().equals(username)) {
|
|
||||||
userSpecificList.add(expenseList);
|
userSpecificList.add(expenseList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return userSpecificList;
|
return userSpecificList;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Expense addExpenseToList(Long expenseListId, Expense expense) {
|
public Expense addExpenseToList(Long expenseListId, Expense expense) {
|
||||||
@@ -134,4 +133,22 @@ public class ExpenseListService {
|
|||||||
}
|
}
|
||||||
repository.save(expenseList);
|
repository.save(expenseList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String generateInviteCode(Long listId) {
|
||||||
|
ExpenseList list = repository.findById(listId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("List not found"));
|
||||||
|
|
||||||
|
String inviteCode = UUID.randomUUID().toString().substring(0, 6).toUpperCase();
|
||||||
|
LocalDateTime expirationTime = LocalDateTime.now().plusWeeks(1);
|
||||||
|
|
||||||
|
list.setInviteCode(inviteCode);
|
||||||
|
list.setInviteCodeExpiration(expirationTime);
|
||||||
|
repository.save(list);
|
||||||
|
|
||||||
|
return inviteCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpenseList findByInviteCode(String inviteCode) {
|
||||||
|
return repository.findByInviteCode(inviteCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -48,4 +48,5 @@ public class UserService {
|
|||||||
} else
|
} else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user