From be6ade58e825010ca95907e81ee2c297f5c22c60 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sun, 25 Jan 2026 20:14:53 -0800 Subject: [PATCH 1/5] added backend for saving breaks on calendar --- .../mvc/calendarBreak/CalendarBreak.java | 80 +++++++ .../CalendarBreakRepository.java | 17 ++ .../calendarBreak/CalendarBreakService.java | 224 ++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreak.java create mode 100644 src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakRepository.java create mode 100644 src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakService.java diff --git a/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreak.java b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreak.java new file mode 100644 index 00000000..d5c3ea5c --- /dev/null +++ b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreak.java @@ -0,0 +1,80 @@ +package com.open.spring.mvc.calendarBreak; + +import java.time.LocalDate; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +/** + * Entity representing a calendar break. + * When a break is created for a date, all events on that date are moved to the next non-break day. + */ +@Entity +@Table(name = "calendar_breaks") +public class CalendarBreak { + // POJO + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private LocalDate date; + private String name; // Break name (e.g., "Spring Break", "Holiday") + private String description; // Break description + + // Default constructor + public CalendarBreak() { + } + + // Constructor with date, name, and description + public CalendarBreak(LocalDate date, String name, String description) { + this.date = date; + this.name = name; + this.description = description; + } + + // Constructor with date and name + public CalendarBreak(LocalDate date, String name) { + this.date = date; + this.name = name; + this.description = ""; + } + + // Constructor with date only + public CalendarBreak(LocalDate date) { + this.date = date; + this.name = "Break"; + this.description = ""; + } + + // Getters and setters + public Long getId() { + return id; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakRepository.java b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakRepository.java new file mode 100644 index 00000000..e9fff8e6 --- /dev/null +++ b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakRepository.java @@ -0,0 +1,17 @@ +package com.open.spring.mvc.calendarBreak; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * Repository for CalendarBreak entities. + * Handles database operations for breaks in the calendar. + */ +public interface CalendarBreakRepository extends JpaRepository { + List findByDate(LocalDate date); + List findAll(); + Optional findById(Long id); +} diff --git a/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakService.java b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakService.java new file mode 100644 index 00000000..7968235f --- /dev/null +++ b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakService.java @@ -0,0 +1,224 @@ +package com.open.spring.mvc.calendarBreak; + +import java.time.LocalDate; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.open.spring.mvc.slack.CalendarEvent; +import com.open.spring.mvc.slack.CalendarEventRepository; + +/** + * Service for managing calendar breaks. + * Handles creation, deletion, and retrieval of breaks. + * When a break is created, all events for that date are moved to the next non-break day. + */ +@Service +public class CalendarBreakService { + + @Autowired + private CalendarBreakRepository calendarBreakRepository; + + @Autowired + private CalendarEventRepository calendarEventRepository; + + private static final int MAX_DAYS_AHEAD = 365; + + /** + * Create a break for a specific date. + * Moves all events from that date to the next non-break day. + * + * @param date The date of the break + * @param name The name of the break + * @param description Description of the break + * @param moveToNextNonBreakDay Whether to move events to next non-break day + * @return The created CalendarBreak entity + */ + @Transactional + public CalendarBreak createBreak(LocalDate date, String name, String description, boolean moveToNextNonBreakDay) { + // Validate inputs + if (name == null || name.trim().isEmpty()) { + name = "Break"; + } + if (description == null) { + description = ""; + } + + // Check if a break already exists for this date + List existingBreaks = calendarBreakRepository.findByDate(date); + if (!existingBreaks.isEmpty()) { + // Break already exists, just return it + return existingBreaks.get(0); + } + + // Move all events from this date if requested + if (moveToNextNonBreakDay) { + List eventsOnDate = calendarEventRepository.findByDate(date); + LocalDate nextNonBreakDay = findNextNonBreakDay(date); + + for (CalendarEvent event : eventsOnDate) { + event.setDate(nextNonBreakDay); + calendarEventRepository.save(event); + } + } + + // Create and save the break + CalendarBreak breakRecord = new CalendarBreak(date, name, description); + return calendarBreakRepository.save(breakRecord); + } + + /** + * Create a break with name and description. + * + * @param date The date of the break + * @param name The name of the break + * @param description Description of the break + * @return The created CalendarBreak entity + */ + public CalendarBreak createBreak(LocalDate date, String name, String description) { + return createBreak(date, name, description, false); + } + + /** + * Create a break with a simple name. + * + * @param date The date of the break + * @param name The name of the break + * @return The created CalendarBreak entity + */ + public CalendarBreak createBreak(LocalDate date, String name) { + return createBreak(date, name, "", false); + } + + /** + * Create a break with default name. + * + * @param date The date of the break + * @return The created CalendarBreak entity + */ + public CalendarBreak createBreak(LocalDate date) { + return createBreak(date, "Break", "", false); + } + + /** + * Find the next non-break day starting from the given date. + * Skips the break day itself and checks subsequent days. + * + * @param date The starting date + * @return The first date that doesn't have a break + */ + public LocalDate findNextNonBreakDay(LocalDate date) { + LocalDate currentDate = date.plusDays(1); // Start from the next day + int daysChecked = 0; + + while (daysChecked < MAX_DAYS_AHEAD) { + if (!isBreakDay(currentDate)) { + return currentDate; + } + currentDate = currentDate.plusDays(1); + daysChecked++; + } + + // Fallback: return a date 365 days from now if no non-break day found + return date.plusDays(MAX_DAYS_AHEAD); + } + + /** + * Update a break's name and description. + * + * @param id The ID of the break to update + * @param name The new name + * @param description The new description + * @return The updated CalendarBreak or null if not found + */ + @Transactional + public CalendarBreak updateBreak(Long id, String name, String description) { + CalendarBreak breakRecord = calendarBreakRepository.findById(id).orElse(null); + if (breakRecord != null) { + if (name != null && !name.trim().isEmpty()) { + breakRecord.setName(name); + } + if (description != null) { + breakRecord.setDescription(description); + } + return calendarBreakRepository.save(breakRecord); + } + return null; + } + + /** + * Delete a break by its ID. + * Does NOT move events back (they stay on their rescheduled dates). + * + * @param id The ID of the break to delete + * @return true if the break was deleted, false if not found + */ + @Transactional + public boolean deleteBreakById(Long id) { + if (calendarBreakRepository.existsById(id)) { + calendarBreakRepository.deleteById(id); + return true; + } + return false; + } + + /** + * Delete a break by date. + * + * @param date The date of the break to delete + * @return true if a break was deleted, false if not found + */ + @Transactional + public boolean deleteBreakByDate(LocalDate date) { + List breaks = calendarBreakRepository.findByDate(date); + if (!breaks.isEmpty()) { + for (CalendarBreak breakRecord : breaks) { + calendarBreakRepository.delete(breakRecord); + } + return true; + } + return false; + } + + /** + * Get all breaks for a specific date. + * + * @param date The date to check + * @return List of breaks for that date + */ + public List getBreaksByDate(LocalDate date) { + return calendarBreakRepository.findByDate(date); + } + + /** + * Get all breaks. + * + * @return List of all breaks + */ + public List getAllBreaks() { + return calendarBreakRepository.findAll(); + } + + /** + * Check if a date is a break day. + * + * @param date The date to check + * @return true if there is a break on this date, false otherwise + */ + public boolean isBreakDay(LocalDate date) { + List breaks = calendarBreakRepository.findByDate(date); + return !breaks.isEmpty(); + } + + /** + * Get a break by ID. + * + * @param id The ID of the break + * @return The CalendarBreak if found, null otherwise + */ + public CalendarBreak getBreakById(Long id) { + return calendarBreakRepository.findById(id).orElse(null); + } +} From 4f80edfc544a228605dc66c6a2131a372c04b261 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sun, 25 Jan 2026 20:15:57 -0800 Subject: [PATCH 2/5] created controller with API endpoints for saving breaks from frontend --- .../CalendarBreakController.java | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakController.java diff --git a/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakController.java b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakController.java new file mode 100644 index 00000000..834c7ff1 --- /dev/null +++ b/src/main/java/com/open/spring/mvc/calendarBreak/CalendarBreakController.java @@ -0,0 +1,225 @@ +package com.open.spring.mvc.calendarBreak; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * Controller for managing calendar breaks. + * Handles creation, deletion, and retrieval of breaks through REST API endpoints. + */ +@RestController +@RequestMapping("/api/calendar/breaks") +public class CalendarBreakController { + + @Autowired + private CalendarBreakService calendarBreakService; + + /** + * Create a new break for a specific date. + * When a break is created, all events for that date are moved to the next non-break day. + * + * @param payload JSON payload containing date, name, description, and moveToNextNonBreakDay + * @return ResponseEntity with the created CalendarBreak or error message + */ + @PostMapping("/create") + public ResponseEntity createBreak(@RequestBody Map payload) { + try { + String dateStr = (String) payload.get("date"); + String name = (String) payload.get("name"); + String description = (String) payload.get("description"); + Boolean moveToNextNonBreakDay = (Boolean) payload.getOrDefault("moveToNextNonBreakDay", true); + + // Validate date + if (dateStr == null || dateStr.isEmpty()) { + return ResponseEntity.badRequest().body(Map.of("error", "Date is required")); + } + + // Validate name + if (name == null || name.trim().isEmpty()) { + return ResponseEntity.badRequest().body(Map.of("error", "Break name is required")); + } + + LocalDate date = LocalDate.parse(dateStr); + + // Handle null description + if (description == null) { + description = ""; + } + + CalendarBreak breakRecord = calendarBreakService.createBreak(date, name, description, moveToNextNonBreakDay); + + return ResponseEntity.ok(Map.of( + "success", true, + "message", "Break created successfully", + "break", breakRecord + )); + } catch (IllegalArgumentException e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Invalid date format. Use YYYY-MM-DD" + )); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "error", "Failed to create break: " + e.getMessage() + )); + } + } + + /** + * Edit a break's name and description. + * + * @param id The ID of the break to edit + * @param payload JSON payload containing name and description + * @return ResponseEntity with the updated break or error message + */ + @PutMapping("/{id}") + public ResponseEntity editBreak(@PathVariable Long id, @RequestBody Map payload) { + try { + String name = (String) payload.get("name"); + String description = (String) payload.get("description"); + + // Validate name if provided + if (name != null && name.trim().isEmpty()) { + return ResponseEntity.badRequest().body(Map.of("error", "Break name cannot be empty")); + } + + CalendarBreak updatedBreak = calendarBreakService.updateBreak(id, name, description); + + if (updatedBreak == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of( + "error", "Break not found with ID: " + id + )); + } + + return ResponseEntity.ok(Map.of( + "success", true, + "message", "Break updated successfully", + "break", updatedBreak + )); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "error", "Failed to update break: " + e.getMessage() + )); + } + } + + /** + * Delete a break by its ID. + * + * @param id The ID of the break to delete + * @return ResponseEntity with success or error message + */ + @DeleteMapping("/{id}") + public ResponseEntity deleteBreak(@PathVariable Long id) { + try { + boolean deleted = calendarBreakService.deleteBreakById(id); + if (deleted) { + return ResponseEntity.ok(Map.of( + "success", true, + "message", "Break deleted successfully" + )); + } else { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of( + "error", "Break not found with ID: " + id + )); + } + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "error", "Failed to delete break: " + e.getMessage() + )); + } + } + + /** + * Get all breaks. + * + * @return ResponseEntity with list of all breaks + */ + @GetMapping("/") + public ResponseEntity getAllBreaks() { + try { + List breaks = calendarBreakService.getAllBreaks(); + return ResponseEntity.ok(breaks); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "error", "Failed to retrieve breaks: " + e.getMessage() + )); + } + } + + /** + * Get breaks for a specific date. + * + * @param date The date to check (format: YYYY-MM-DD) + * @return ResponseEntity with list of breaks for that date + */ + @GetMapping("/by-date") + public ResponseEntity getBreaksByDate( + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) { + try { + List breaks = calendarBreakService.getBreaksByDate(date); + return ResponseEntity.ok(breaks); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "error", "Failed to retrieve breaks: " + e.getMessage() + )); + } + } + + /** + * Check if a date is a break day. + * + * @param date The date to check (format: YYYY-MM-DD) + * @return ResponseEntity with boolean indicating if it's a break day + */ + @GetMapping("/is-break-day") + public ResponseEntity isBreakDay( + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) { + try { + boolean isBreak = calendarBreakService.isBreakDay(date); + return ResponseEntity.ok(Map.of("isBreakDay", isBreak)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "error", "Failed to check break day: " + e.getMessage() + )); + } + } + + /** + * Get a break by its ID. + * + * @param id The ID of the break + * @return ResponseEntity with the break or error message + */ + @GetMapping("/{id}") + public ResponseEntity getBreakById(@PathVariable Long id) { + try { + CalendarBreak breakRecord = calendarBreakService.getBreakById(id); + if (breakRecord != null) { + return ResponseEntity.ok(breakRecord); + } else { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of( + "error", "Break not found with ID: " + id + )); + } + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "error", "Failed to retrieve break: " + e.getMessage() + )); + } + } +} From da99c15d34db234729de83ea8afb7ea2664a7cc1 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sun, 25 Jan 2026 20:17:21 -0800 Subject: [PATCH 3/5] added try/exception for player database as it was causing errors in running springboot --- .../spring/mvc/multiplayer/PlayerInit.java | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java b/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java index 9af6fc57..9fe5955a 100644 --- a/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java +++ b/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java @@ -13,32 +13,36 @@ public class PlayerInit { @Bean CommandLineRunner initGamers(PlayerRepository repository) { return args -> { - - if (repository.count() == 0) { - - int count = 50; - String[] uids = new String[count]; - for (int i = 0; i < count; i++) { - uids[i] = "player" + (i + 1); + try { + if (repository.count() == 0) { + + int count = 50; + String[] uids = new String[count]; + for (int i = 0; i < count; i++) { + uids[i] = "player" + (i + 1); + } + + Random random = new Random(); + + for (String uid : uids) { + Player player = new Player(); + player.setUid(uid); + player.setStatus("offline"); + player.setLevel(random.nextInt(10) + 1); + player.setX(random.nextDouble() * 1000.0); + player.setY(random.nextDouble() * 1000.0); + player.setLastActive(LocalDateTime.now()); + player.setConnectedAt(LocalDateTime.now()); + + repository.save(player); + } + + System.out.println("Gamer database initialized with " + + uids.length + " players"); } - - Random random = new Random(); - - for (String uid : uids) { - Player player = new Player(); - player.setUid(uid); - player.setStatus("offline"); - player.setLevel(random.nextInt(10) + 1); - player.setX(random.nextDouble() * 1000.0); - player.setY(random.nextDouble() * 1000.0); - player.setLastActive(LocalDateTime.now()); - player.setConnectedAt(LocalDateTime.now()); - - repository.save(player); - } - - System.out.println("Gamer database initialized with " - + uids.length + " players"); + } catch (Exception e) { + // Players table may not exist yet - skip initialization + System.out.println("Skipping player initialization: " + e.getMessage()); } }; } From 3782554ed1ddcb1cc3ee043d6b8eba9ad9800321 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sun, 25 Jan 2026 23:58:14 -0800 Subject: [PATCH 4/5] added two files that prevent grades_json from crashing --- bathroom_cleaned.csv | 1 + bathroom_summary.csv | 1 + 2 files changed, 2 insertions(+) create mode 100644 bathroom_cleaned.csv create mode 100644 bathroom_summary.csv diff --git a/bathroom_cleaned.csv b/bathroom_cleaned.csv new file mode 100644 index 00000000..22012484 --- /dev/null +++ b/bathroom_cleaned.csv @@ -0,0 +1 @@ +Name,Duration,Average Duration By Period,Date,Abnormal diff --git a/bathroom_summary.csv b/bathroom_summary.csv new file mode 100644 index 00000000..98b7e6a8 --- /dev/null +++ b/bathroom_summary.csv @@ -0,0 +1 @@ +Name,MeanDuration,MaxDuration,StdDevDuration,TotalVisits,PercentAbnormal,AbnormalPerson From 56f0637b9fc865deb2bbf117d33783162b915130 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Wed, 28 Jan 2026 11:38:02 -0800 Subject: [PATCH 5/5] reverted changes in PlayerInit.java and adding two csv files as Main.java still runs successfully --- bathroom_cleaned.csv | 1 - bathroom_summary.csv | 1 - .../spring/mvc/multiplayer/PlayerInit.java | 54 +++++++++---------- 3 files changed, 25 insertions(+), 31 deletions(-) delete mode 100644 bathroom_cleaned.csv delete mode 100644 bathroom_summary.csv diff --git a/bathroom_cleaned.csv b/bathroom_cleaned.csv deleted file mode 100644 index 22012484..00000000 --- a/bathroom_cleaned.csv +++ /dev/null @@ -1 +0,0 @@ -Name,Duration,Average Duration By Period,Date,Abnormal diff --git a/bathroom_summary.csv b/bathroom_summary.csv deleted file mode 100644 index 98b7e6a8..00000000 --- a/bathroom_summary.csv +++ /dev/null @@ -1 +0,0 @@ -Name,MeanDuration,MaxDuration,StdDevDuration,TotalVisits,PercentAbnormal,AbnormalPerson diff --git a/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java b/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java index 9fe5955a..9af6fc57 100644 --- a/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java +++ b/src/main/java/com/open/spring/mvc/multiplayer/PlayerInit.java @@ -13,36 +13,32 @@ public class PlayerInit { @Bean CommandLineRunner initGamers(PlayerRepository repository) { return args -> { - try { - if (repository.count() == 0) { - - int count = 50; - String[] uids = new String[count]; - for (int i = 0; i < count; i++) { - uids[i] = "player" + (i + 1); - } - - Random random = new Random(); - - for (String uid : uids) { - Player player = new Player(); - player.setUid(uid); - player.setStatus("offline"); - player.setLevel(random.nextInt(10) + 1); - player.setX(random.nextDouble() * 1000.0); - player.setY(random.nextDouble() * 1000.0); - player.setLastActive(LocalDateTime.now()); - player.setConnectedAt(LocalDateTime.now()); - - repository.save(player); - } - - System.out.println("Gamer database initialized with " - + uids.length + " players"); + + if (repository.count() == 0) { + + int count = 50; + String[] uids = new String[count]; + for (int i = 0; i < count; i++) { + uids[i] = "player" + (i + 1); } - } catch (Exception e) { - // Players table may not exist yet - skip initialization - System.out.println("Skipping player initialization: " + e.getMessage()); + + Random random = new Random(); + + for (String uid : uids) { + Player player = new Player(); + player.setUid(uid); + player.setStatus("offline"); + player.setLevel(random.nextInt(10) + 1); + player.setX(random.nextDouble() * 1000.0); + player.setY(random.nextDouble() * 1000.0); + player.setLastActive(LocalDateTime.now()); + player.setConnectedAt(LocalDateTime.now()); + + repository.save(player); + } + + System.out.println("Gamer database initialized with " + + uids.length + " players"); } }; }