From 9bb6db769386db54b28af0fd94bdb53b0cd6dc0e Mon Sep 17 00:00:00 2001 From: Hymmel Date: Thu, 22 Jan 2026 10:49:41 +0100 Subject: [PATCH] hitler --- .../itsolutions/ticketsystem/DataLoader.java | 13 ++ .../ticketsystem/TicketSystemApplication.java | 7 + .../ticketsystem/config/SecurityConfig.java | 23 +++ .../controller/AuthController.java | 45 +++--- .../controller/CommentController.java | 16 +++ .../controller/RoomController.java | 41 ++++-- .../controller/TicketController.java | 29 ++++ .../controller/UserController.java | 16 ++- .../de/itsolutions/ticketsystem/dto/Dtos.java | 135 +++++++++++++++++- .../ticketsystem/entity/Comment.java | 62 +++++++- .../itsolutions/ticketsystem/entity/Room.java | 31 +++- .../ticketsystem/entity/Ticket.java | 73 +++++++++- .../itsolutions/ticketsystem/entity/User.java | 88 +++++++++++- .../repository/CommentRepository.java | 8 ++ .../repository/RoomRepository.java | 8 ++ .../repository/TicketRepository.java | 14 ++ .../repository/UserRepository.java | 8 ++ .../ticketsystem/service/AuthService.java | 48 +++++-- .../service/CustomUserDetailsService.java | 14 ++ .../ticketsystem/service/TicketService.java | 37 +++++ Frontend/components/auth/login-form.tsx | 25 +++- Frontend/components/auth/register-form.tsx | 42 ++++-- .../components/dashboard/admin-dashboard.tsx | 18 +-- .../components/dashboard/room-management.tsx | 6 +- .../dashboard/supervisor-dashboard.tsx | 5 +- .../dashboard/teacher-dashboard.tsx | 11 +- Frontend/components/layout/app-shell.tsx | 26 +++- Frontend/components/mode-toggle.tsx | 2 +- .../components/tickets/create-ticket-form.tsx | 4 +- .../components/tickets/ticket-comments.tsx | 8 +- Frontend/components/tickets/ticket-table.tsx | 30 ++-- Frontend/components/ui/alert-dialog.tsx | 9 +- Frontend/components/ui/dialog.tsx | 2 +- Frontend/components/ui/sheet.tsx | 2 +- Frontend/components/user-theme-sync.tsx | 51 ++++--- 35 files changed, 785 insertions(+), 172 deletions(-) diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/DataLoader.java b/Backend/src/main/java/de/itsolutions/ticketsystem/DataLoader.java index df144ec..e0dddea 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/DataLoader.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/DataLoader.java @@ -7,15 +7,28 @@ import org.springframework.stereotype.Component; import java.util.List; +/** + * Component to load initial data into the database when the application starts. + */ @Component public class DataLoader implements CommandLineRunner { private final RoomRepository roomRepository; + /** + * Constructs a new DataLoader with the given RoomRepository. + * @param roomRepository The repository for managing rooms. + */ public DataLoader(RoomRepository roomRepository) { this.roomRepository = roomRepository; } + /** + * Runs the data loading logic. + * If no rooms exist, it creates and saves a few default rooms. + * @param args Command line arguments. + * @throws Exception if an error occurs during data loading. + */ @Override public void run(String... args) throws Exception { if (roomRepository.count() == 0) { diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/TicketSystemApplication.java b/Backend/src/main/java/de/itsolutions/ticketsystem/TicketSystemApplication.java index 45f07a4..ac206f9 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/TicketSystemApplication.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/TicketSystemApplication.java @@ -3,9 +3,16 @@ package de.itsolutions.ticketsystem; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +/** + * Main application class for the Ticket System. + */ @SpringBootApplication public class TicketSystemApplication { + /** + * Main method to start the Spring Boot application. + * @param args Command line arguments. + */ public static void main(String[] args) { SpringApplication.run(TicketSystemApplication.class, args); } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/config/SecurityConfig.java b/Backend/src/main/java/de/itsolutions/ticketsystem/config/SecurityConfig.java index a19c63a..a07d7f1 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/config/SecurityConfig.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/config/SecurityConfig.java @@ -16,10 +16,19 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.List; +/** + * Security configuration for the application. + */ @Configuration @EnableWebSecurity public class SecurityConfig { + /** + * Configures the security filter chain. + * @param http The HttpSecurity object to configure. + * @return The SecurityFilterChain. + * @throws Exception if an error occurs during configuration. + */ @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http @@ -35,16 +44,30 @@ public class SecurityConfig { return http.build(); } + /** + * Provides a BCryptPasswordEncoder for password hashing. + * @return The PasswordEncoder bean. + */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } + /** + * Provides an AuthenticationManager bean. + * @param authConfig The AuthenticationConfiguration. + * @return The AuthenticationManager. + * @throws Exception if an error occurs during configuration. + */ @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } + /** + * Configures CORS for the application. + * @return The CorsConfigurationSource bean. + */ @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/AuthController.java b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/AuthController.java index 3e00530..e1510f3 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/AuthController.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/AuthController.java @@ -11,6 +11,10 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.security.Principal; +/** + * REST controller for authentication-related operations. + * Handles user registration, login, current user retrieval, and updating supervised rooms. + */ @RestController @RequestMapping("/api/auth") public class AuthController { @@ -18,40 +22,43 @@ public class AuthController { private final AuthService authService; private final AuthenticationManager authenticationManager; + /** + * Constructs an AuthController with necessary services. + * @param authService The authentication service. + * @param authenticationManager The authentication manager. + */ public AuthController(AuthService authService, AuthenticationManager authenticationManager) { this.authService = authService; this.authenticationManager = authenticationManager; } /** - * Registers a new user. - * @param request Registration details - * @return The registered user + * Registers a new user in the system. + * @param request The registration request containing user details. + * @return A ResponseEntity with the registered user. */ @PostMapping("/register") public ResponseEntity register(@RequestBody Dtos.RegisterRequest request) { - // registering the user, hope they remember their password return ResponseEntity.ok(authService.register(request)); } /** - * Logs in a user. - * @param request Login credentials - * @return The user details if login succeeds + * Authenticates a user and returns their details upon successful login. + * @param request The login request containing user credentials. + * @return A ResponseEntity with the authenticated user's details. */ @PostMapping("/login") public ResponseEntity login(@RequestBody Dtos.LoginRequest request) { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword()) ); - // Return full user details return ResponseEntity.ok(authService.getUserByEmail(request.getEmail())); } /** - * Gets the currently authenticated user. - * @param principal The security principal - * @return The user + * Retrieves the currently authenticated user's information. + * @param principal The security principal representing the authenticated user. + * @return A ResponseEntity with the current user's details. */ @GetMapping("/me") public ResponseEntity getCurrentUser(Principal principal) { @@ -59,21 +66,13 @@ public class AuthController { } /** - * Updates the supervised rooms for the current user. - * @param request Room IDs - * @param principal The security principal - * @return The updated user + * Updates the list of rooms supervised by the current user. + * @param request The request containing the IDs of rooms to supervise. + * @param principal The security principal of the current user. + * @return A ResponseEntity with the updated user details. */ @PutMapping("/profile/rooms") public ResponseEntity updateMyRooms(@RequestBody Dtos.UpdateRoomsRequest request, Principal principal) { return ResponseEntity.ok(authService.updateSupervisedRooms(principal.getName(), request.getRoomIds())); } - - // Emergency endpoint to promote a user to ADMIN (Removed before production!) - // seriously, delete this before going live or we are doomed - @PostMapping("/dev-promote-admin") - public ResponseEntity promoteToAdmin(@RequestBody Dtos.LoginRequest request) { // Reusing LoginRequest for email/password check essentially or just email - // Ideally we check a secret key, but for now we just allow promoting by email if password matches or just by email for simplicity in this stuck state - return ResponseEntity.ok(authService.promoteToAdmin(request.getEmail())); - } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/CommentController.java b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/CommentController.java index cbb2e1a..716d94a 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/CommentController.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/CommentController.java @@ -17,6 +17,9 @@ import org.springframework.web.server.ResponseStatusException; import java.util.List; import java.util.Map; +/** + * REST controller for managing comments on tickets. + */ @RestController @RequestMapping("/api/tickets/{ticketId}/comments") public class CommentController { @@ -30,6 +33,12 @@ public class CommentController { @Autowired private UserRepository userRepository; + /** + * Retrieves all comments for a specific ticket. + * @param ticketId The ID of the ticket. + * @return A list of comments for the specified ticket. + * @throws ResponseStatusException if the ticket is not found. + */ @GetMapping public List getComments(@PathVariable Long ticketId) { if (!ticketRepository.existsById(ticketId)) { @@ -38,6 +47,13 @@ public class CommentController { return commentRepository.findByTicketIdOrderByCreatedAtAsc(ticketId); } + /** + * Adds a new comment to a ticket. + * @param ticketId The ID of the ticket to add the comment to. + * @param payload A map containing the comment text. + * @return The newly created comment. + * @throws ResponseStatusException if the text is empty, ticket is not found, or user is not found. + */ @PostMapping public Comment addComment(@PathVariable Long ticketId, @RequestBody Map payload) { String text = payload.get("text"); diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/RoomController.java b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/RoomController.java index 3dfa4e8..df2f206 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/RoomController.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/RoomController.java @@ -16,6 +16,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +/** + * REST controller for managing rooms. + */ @RestController @RequestMapping("/api/rooms") public class RoomController { @@ -23,11 +26,21 @@ public class RoomController { @Autowired private RoomRepository roomRepository; + /** + * Retrieves all rooms. + * @return A list of all rooms. + */ @GetMapping public List getAllRooms() { return roomRepository.findAll(); } + /** + * Creates a new room. + * @param payload A map containing the name of the room. + * @return The newly created room. + * @throws ResponseStatusException if the name is empty or the room already exists. + */ @PostMapping public Room createRoom(@RequestBody Map payload) { String name = payload.get("name"); @@ -42,6 +55,13 @@ public class RoomController { return roomRepository.save(room); } + /** + * Updates an existing room. + * @param id The ID of the room to update. + * @param payload A map containing the new name of the room. + * @return The updated room. + * @throws ResponseStatusException if the name is empty, room is not found, or new name already exists. + */ @PutMapping("/{id}") public Room updateRoom(@PathVariable Long id, @RequestBody Map payload) { String name = payload.get("name"); @@ -60,16 +80,17 @@ public class RoomController { return roomRepository.save(room); } + /** + * Deletes a room by its ID. + * @param id The ID of the room to delete. + * @return A ResponseEntity with no content if successful. + * @throws ResponseStatusException if the room is not found or cannot be deleted due to existing tickets. + */ @DeleteMapping("/{id}") public ResponseEntity deleteRoom(@PathVariable Long id) { if (!roomRepository.existsById(id)) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Room not found"); } - // Note: This might fail if constraints exist (tickets linked to room). - // Real-world app needs constraint handling (delete tickets or block). - // For simplicity here, we assume cascade or block. - // Given Ticket entity has optional=false for room, deleting room will fail unless we delete tickets first. - // Let's rely on DB error for now or add cascade logic later if requested. try { roomRepository.deleteById(id); } catch (Exception e) { @@ -78,6 +99,13 @@ public class RoomController { return ResponseEntity.noContent().build(); } + /** + * Imports rooms from a CSV file. Each line in the file is expected to be a room name. + * Only unique room names will be imported. + * @param file The MultipartFile containing the CSV data. + * @return A ResponseEntity with a message indicating the number of rooms imported. + * @throws ResponseStatusException if the file processing fails. + */ @PostMapping("/import") public ResponseEntity importRooms(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { @@ -89,9 +117,6 @@ public class RoomController { int count = 0; while ((line = reader.readLine()) != null) { String name = line.trim(); - // Basic CSV: assuming one room name per line or separated by comma - // If CSV is "id,name" or just "name". Let's assume just "name" per line or typical CSV format handling. - // Simple implementation: One room name per line. if (!name.isEmpty() && roomRepository.findByName(name).isEmpty()) { Room room = new Room(); room.setName(name); diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/TicketController.java b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/TicketController.java index 8f7bf05..fd2b1f2 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/TicketController.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/TicketController.java @@ -8,31 +8,60 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; import java.util.List; +/** + * REST controller for managing tickets. + */ @RestController @RequestMapping("/api/tickets") public class TicketController { private final TicketService ticketService; + /** + * Constructs a new TicketController with the given TicketService. + * @param ticketService The service for managing tickets. + */ public TicketController(TicketService ticketService) { this.ticketService = ticketService; } + /** + * Creates a new ticket. + * @param request The ticket creation request. + * @param principal The security principal of the user creating the ticket. + * @return A ResponseEntity containing the created ticket. + */ @PostMapping public ResponseEntity createTicket(@RequestBody Dtos.TicketRequest request, Principal principal) { return ResponseEntity.ok(ticketService.createTicket(request, principal.getName())); } + /** + * Retrieves tickets relevant to the current user. + * @param principal The security principal of the current user. + * @return A ResponseEntity containing a list of tickets. + */ @GetMapping public ResponseEntity> getTickets(Principal principal) { return ResponseEntity.ok(ticketService.getTicketsForUser(principal.getName())); } + /** + * Updates the status of a specific ticket. + * @param id The ID of the ticket to update. + * @param request The request containing the new status. + * @return A ResponseEntity containing the updated ticket. + */ @PatchMapping("/{id}/status") public ResponseEntity updateStatus(@PathVariable Long id, @RequestBody Dtos.TicketStatusRequest request) { return ResponseEntity.ok(ticketService.updateTicketStatus(id, request.getStatus())); } + /** + * Deletes a ticket by its ID. + * @param id The ID of the ticket to delete. + * @return A ResponseEntity with no content. + */ @DeleteMapping("/{id}") public ResponseEntity deleteTicket(@PathVariable Long id) { ticketService.deleteTicket(id); diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/UserController.java b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/UserController.java index 9a1652a..c1e6467 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/controller/UserController.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/controller/UserController.java @@ -8,8 +8,7 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; /** - * Controller for stuff that relates to the user, but not necessarily login/register. - * Kept separate because clean code or whatever. + * REST controller for user-related operations, excluding authentication. */ @RestController @RequestMapping("/api/users") @@ -17,19 +16,22 @@ public class UserController { private final AuthService authService; + /** + * Constructs a UserController with the necessary authentication service. + * @param authService The authentication service. + */ public UserController(AuthService authService) { this.authService = authService; } /** - * Updates the theme for the current user. - * @param request The theme update request - * @param principal The security principal (the logged in dude) - * @return The updated user + * Updates the theme preference for the currently authenticated user. + * @param request The request containing the new theme preference. + * @param principal The security principal of the logged-in user. + * @return A ResponseEntity containing the updated user. */ @PatchMapping("/theme") public ResponseEntity updateTheme(@RequestBody Dtos.ThemeUpdateRequest request, Principal principal) { - // Just delegating to service, standard procedure return ResponseEntity.ok(authService.updateTheme(principal.getName(), request.getTheme())); } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/dto/Dtos.java b/Backend/src/main/java/de/itsolutions/ticketsystem/dto/Dtos.java index 8c00fff..7827c92 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/dto/Dtos.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/dto/Dtos.java @@ -1,10 +1,15 @@ package de.itsolutions.ticketsystem.dto; -import lombok.Data; import java.util.List; +/** + * A container class for various Data Transfer Objects (DTOs) used in the application. + */ public class Dtos { + /** + * DTO for user registration requests. + */ public static class RegisterRequest { private String firstname; private String lastname; @@ -13,60 +18,186 @@ public class Dtos { private String role; private List roomIds; + /** + * Gets the first name of the user. + * @return The first name. + */ public String getFirstname() { return firstname; } + /** + * Sets the first name of the user. + * @param firstname The first name. + */ public void setFirstname(String firstname) { this.firstname = firstname; } + /** + * Gets the last name of the user. + * @return The last name. + */ public String getLastname() { return lastname; } + /** + * Sets the last name of the user. + * @param lastname The last name. + */ public void setLastname(String lastname) { this.lastname = lastname; } + /** + * Gets the email of the user. + * @return The email. + */ public String getEmail() { return email; } + /** + * Sets the email of the user. + * @param email The email. + */ public void setEmail(String email) { this.email = email; } + /** + * Gets the password of the user. + * @return The password. + */ public String getPassword() { return password; } + /** + * Sets the password of the user. + * @param password The password. + */ public void setPassword(String password) { this.password = password; } + /** + * Gets the role of the user. + * @return The role. + */ public String getRole() { return role; } + /** + * Sets the role of the user. + * @param role The role. + */ public void setRole(String role) { this.role = role; } + /** + * Gets the list of room IDs the user supervises. + * @return The list of room IDs. + */ public List getRoomIds() { return roomIds; } + /** + * Sets the list of room IDs the user supervises. + * @param roomIds The list of room IDs. + */ public void setRoomIds(List roomIds) { this.roomIds = roomIds; } } + /** + * DTO for user login requests. + */ public static class LoginRequest { private String email; private String password; + /** + * Gets the email for login. + * @return The email. + */ public String getEmail() { return email; } + /** + * Sets the email for login. + * @param email The email. + */ public void setEmail(String email) { this.email = email; } + /** + * Gets the password for login. + * @return The password. + */ public String getPassword() { return password; } + /** + * Sets the password for login. + * @param password The password. + */ public void setPassword(String password) { this.password = password; } } + /** + * DTO for updating supervised rooms. + */ public static class UpdateRoomsRequest { private List roomIds; + /** + * Gets the list of room IDs. + * @return The list of room IDs. + */ public List getRoomIds() { return roomIds; } + /** + * Sets the list of room IDs. + * @param roomIds The list of room IDs. + */ public void setRoomIds(List roomIds) { this.roomIds = roomIds; } } + /** + * DTO for creating a new ticket. + */ public static class TicketRequest { private Long roomId; private String title; private String description; + /** + * Gets the room ID for the ticket. + * @return The room ID. + */ public Long getRoomId() { return roomId; } + /** + * Sets the room ID for the ticket. + * @param roomId The room ID. + */ public void setRoomId(Long roomId) { this.roomId = roomId; } + /** + * Gets the title of the ticket. + * @return The title. + */ public String getTitle() { return title; } + /** + * Sets the title of the ticket. + * @param title The title. + */ public void setTitle(String title) { this.title = title; } + /** + * Gets the description of the ticket. + * @return The description. + */ public String getDescription() { return description; } + /** + * Sets the description of the ticket. + * @param description The description. + */ public void setDescription(String description) { this.description = description; } } + /** + * DTO for updating a ticket's status. + */ public static class TicketStatusRequest { private String status; + /** + * Gets the new status for the ticket. + * @return The status. + */ public String getStatus() { return status; } + /** + * Sets the new status for the ticket. + * @param status The status. + */ public void setStatus(String status) { this.status = status; } } - // Request payload for changing the vibe (theme) + /** + * DTO for updating a user's theme preference. + */ public static class ThemeUpdateRequest { private String theme; + /** + * Gets the new theme preference. + * @return The theme. + */ public String getTheme() { return theme; } + /** + * Sets the new theme preference. + * @param theme The theme. + */ public void setTheme(String theme) { this.theme = theme; } } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Comment.java b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Comment.java index 96318a3..e5fbc4f 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Comment.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Comment.java @@ -1,14 +1,13 @@ package de.itsolutions.ticketsystem.entity; import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; import java.time.LocalDateTime; +/** + * Represents a comment on a ticket in the ticket system. + */ @Entity @Table(name = "comments") -@Data -@NoArgsConstructor public class Comment { @Id @@ -29,14 +28,69 @@ public class Comment { @JoinColumn(name = "ticket_id", nullable = false) private Ticket ticket; + /** + * Default constructor for JPA. + */ + public Comment() { + } + + /** + * Sets the comment ID. + * @param id The comment ID. + */ public void setId(Long id) { this.id = id; } + + /** + * Gets the comment ID. + * @return The comment ID. + */ public Long getId() { return id; } + + /** + * Sets the comment text. + * @param text The comment text. + */ public void setText(String text) { this.text = text; } + + /** + * Gets the comment text. + * @return The comment text. + */ public String getText() { return text; } + + /** + * Sets the creation timestamp of the comment. + * @param createdAt The creation timestamp. + */ public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } + + /** + * Gets the creation timestamp of the comment. + * @return The creation timestamp. + */ public LocalDateTime getCreatedAt() { return createdAt; } + + /** + * Sets the author of the comment. + * @param author The author. + */ public void setAuthor(User author) { this.author = author; } + + /** + * Gets the author of the comment. + * @return The author. + */ public User getAuthor() { return author; } + + /** + * Sets the ticket this comment belongs to. + * @param ticket The ticket. + */ public void setTicket(Ticket ticket) { this.ticket = ticket; } + + /** + * Gets the ticket this comment belongs to. + * @return The ticket. + */ public Ticket getTicket() { return ticket; } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Room.java b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Room.java index aa42a50..a48af3b 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Room.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Room.java @@ -1,12 +1,12 @@ package de.itsolutions.ticketsystem.entity; import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; +/** + * Represents a room in the ticket system. + */ @Entity @Table(name = "rooms") -@NoArgsConstructor public class Room { @Id @@ -16,8 +16,33 @@ public class Room { @Column(nullable = false, unique = true) private String name; + /** + * Default constructor for JPA. + */ + public Room() { + } + + /** + * Gets the room ID. + * @return The room ID. + */ public Long getId() { return id; } + + /** + * Sets the room ID. + * @param id The room ID. + */ public void setId(Long id) { this.id = id; } + + /** + * Gets the room name. + * @return The room name. + */ public String getName() { return name; } + + /** + * Sets the room name. + * @param name The room name. + */ public void setName(String name) { this.name = name; } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Ticket.java b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Ticket.java index 85dcc52..4b9d3dd 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Ticket.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/Ticket.java @@ -1,13 +1,13 @@ package de.itsolutions.ticketsystem.entity; import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; import java.time.LocalDateTime; +/** + * Represents a ticket in the ticket system. + */ @Entity @Table(name = "tickets") -@NoArgsConstructor public class Ticket { @Id @@ -40,26 +40,93 @@ public class Ticket { @JoinColumn(name = "user_id", nullable = false) // Creator (Lehrkraft) private User owner; + /** + * Gets the ticket ID. + * @return The ticket ID. + */ public Long getId() { return id; } + + /** + * Sets the ticket ID. + * @param id The ticket ID. + */ public void setId(Long id) { this.id = id; } + + /** + * Gets the room associated with the ticket. + * @return The room. + */ public Room getRoom() { return room; } + + /** + * Sets the room for the ticket. + * @param room The room. + */ public void setRoom(Room room) { this.room = room; } + /** + * Gets the ticket title. + * @return The ticket title. + */ public String getTitle() { return title_de; } + + /** + * Sets the ticket title. + * @param title The ticket title. + */ public void setTitle(String title) { this.title_de = title; this.title_en = title; } + /** + * Gets the ticket description. + * @return The ticket description. + */ public String getDescription() { return description_de; } + + /** + * Sets the ticket description. + * @param description The ticket description. + */ public void setDescription(String description) { this.description_de = description; this.description_en = description; } + + /** + * Gets the creation timestamp of the ticket. + * @return The creation timestamp. + */ public LocalDateTime getCreatedAt() { return createdAt; } + + /** + * Sets the creation timestamp of the ticket. + * @param createdAt The creation timestamp. + */ public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } + + /** + * Gets the status of the ticket. + * @return The ticket status. + */ public String getStatus() { return status; } + + /** + * Sets the status of the ticket. + * @param status The ticket status. + */ public void setStatus(String status) { this.status = status; } + + /** + * Gets the owner of the ticket. + * @return The ticket owner. + */ public User getOwner() { return owner; } + + /** + * Sets the owner of the ticket. + * @param owner The ticket owner. + */ public void setOwner(User owner) { this.owner = owner; } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/User.java b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/User.java index 5732a8c..89d8d64 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/entity/User.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/entity/User.java @@ -1,13 +1,13 @@ package de.itsolutions.ticketsystem.entity; import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; import java.util.List; +/** + * Represents a user in the ticket system. + */ @Entity @Table(name = "users") -@NoArgsConstructor public class User { @Id @@ -49,28 +49,63 @@ public class User { ) private List supervisedRooms; + /** + * Default constructor for JPA. + */ + public User() { + } + + /** + * Gets the user ID. + * @return The user ID. + */ public Long getId() { return id; } + /** + * Sets the user ID. + * @param id The user ID. + */ public void setId(Long id) { this.id = id; } + /** + * Gets the user's first name. + * @return The first name. + */ public String getFirstname() { return name_firstname; } - // setter for firstname, keeping legacy vorname in sync because reasons... + /** + * Sets the user's first name. + * @param firstname The first name. + */ public void setFirstname(String firstname) { this.name_firstname = firstname; this.name_vorname = firstname; } + /** + * Gets the user's last name. + * @return The last name. + */ public String getLastname() { return name_lastname; } - // syncing lastname with nachname, database duplicates ftw + /** + * Sets the user's last name. + * @param lastname The last name. + */ public void setLastname(String lastname) { this.name_lastname = lastname; this.name_nachname = lastname; } + /** + * Gets the user's full name. + * @return The full name. + */ public String getName() { return this.name_column; } - // null check is good for the soul + /** + * Sets the user's full name. + * @param name The full name. + */ public void setName(String name) { if (name == null || name.isBlank()) { name = "Unknown User"; @@ -78,16 +113,55 @@ public class User { this.name_column = name; } + /** + * Gets the user's email. + * @return The email. + */ public String getEmail() { return email; } + /** + * Sets the user's email. + * @param email The email. + */ public void setEmail(String email) { this.email = email; } + /** + * Gets the user's password. + * @return The password. + */ public String getPassword() { return password; } + /** + * Sets the user's password. + * @param password The password. + */ public void setPassword(String password) { this.password = password; } + /** + * Gets the user's role. + * @return The role. + */ public String getRole() { return role; } + /** + * Sets the user's role. + * @param role The role. + */ public void setRole(String role) { this.role = role; } + /** + * Gets the list of rooms the user supervises. + * @return The list of supervised rooms. + */ public List getSupervisedRooms() { return supervisedRooms; } + /** + * Sets the list of rooms the user supervises. + * @param supervisedRooms The list of supervised rooms. + */ public void setSupervisedRooms(List supervisedRooms) { this.supervisedRooms = supervisedRooms; } - // dark mode stuff, gotta save those eyes + /** + * Gets the user's theme preference for dark mode. + * @return The theme preference. + */ public String getTheme() { return theme; } + /** + * Sets the user's theme preference for dark mode. + * @param theme The theme preference. + */ public void setTheme(String theme) { this.theme = theme; } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/CommentRepository.java b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/CommentRepository.java index 06dc040..473c786 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/CommentRepository.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/CommentRepository.java @@ -4,6 +4,14 @@ import de.itsolutions.ticketsystem.entity.Comment; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +/** + * Repository interface for managing Comment entities. + */ public interface CommentRepository extends JpaRepository { + /** + * Finds all comments for a given ticket ID, ordered by creation time in ascending order. + * @param ticketId The ID of the ticket. + * @return A list of comments for the specified ticket. + */ List findByTicketIdOrderByCreatedAtAsc(Long ticketId); } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/RoomRepository.java b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/RoomRepository.java index b95e56e..2dc3a9f 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/RoomRepository.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/RoomRepository.java @@ -5,6 +5,14 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; +/** + * Repository interface for managing Room entities. + */ public interface RoomRepository extends JpaRepository { + /** + * Finds a room by its name. + * @param name The name of the room to find. + * @return An Optional containing the found room, or empty if not found. + */ Optional findByName(String name); } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/TicketRepository.java b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/TicketRepository.java index 85e3402..07911a7 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/TicketRepository.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/TicketRepository.java @@ -4,7 +4,21 @@ import de.itsolutions.ticketsystem.entity.Ticket; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +/** + * Repository interface for managing Ticket entities. + */ public interface TicketRepository extends JpaRepository { + /** + * Finds all tickets created by a specific user, ordered by creation date in descending order. + * @param ownerId The ID of the user who created the tickets. + * @return A list of tickets owned by the specified user. + */ List findByOwnerIdOrderByCreatedAtDesc(Long ownerId); + + /** + * Finds all tickets associated with a list of room IDs, ordered by creation date in descending order. + * @param roomIds A list of room IDs. + * @return A list of tickets associated with the specified rooms. + */ List findByRoomIdInOrderByCreatedAtDesc(List roomIds); } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/UserRepository.java b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/UserRepository.java index aa765e4..5cbfb6f 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/repository/UserRepository.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/repository/UserRepository.java @@ -4,6 +4,14 @@ import de.itsolutions.ticketsystem.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; +/** + * Repository interface for managing User entities. + */ public interface UserRepository extends JpaRepository { + /** + * Finds a user by their email address. + * @param email The email address of the user to find. + * @return An Optional containing the found user, or empty if not found. + */ Optional findByEmail(String email); } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/service/AuthService.java b/Backend/src/main/java/de/itsolutions/ticketsystem/service/AuthService.java index 4122dc7..6b86d2e 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/service/AuthService.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/service/AuthService.java @@ -10,6 +10,9 @@ import org.springframework.stereotype.Service; import java.util.List; +/** + * Service class for handling user authentication and registration operations. + */ @Service public class AuthService { @@ -17,12 +20,24 @@ public class AuthService { private final RoomRepository roomRepository; private final PasswordEncoder passwordEncoder; + /** + * Constructs an AuthService with necessary repositories and password encoder. + * @param userRepository The user repository. + * @param roomRepository The room repository. + * @param passwordEncoder The password encoder. + */ public AuthService(UserRepository userRepository, RoomRepository roomRepository, PasswordEncoder passwordEncoder) { this.userRepository = userRepository; this.roomRepository = roomRepository; this.passwordEncoder = passwordEncoder; } + /** + * Registers a new user with the provided details. + * @param request The registration request data. + * @return The newly registered user. + * @throws RuntimeException if the email is already in use or first/last name are missing. + */ public User register(Dtos.RegisterRequest request) { if (userRepository.findByEmail(request.getEmail()).isPresent()) { throw new RuntimeException("Email already in use"); @@ -39,7 +54,6 @@ public class AuthService { user.setName(request.getFirstname() + " " + request.getLastname()); // Populate legacy/fallback fields user.setEmail(request.getEmail()); user.setPassword(passwordEncoder.encode(request.getPassword())); - user.setPassword(passwordEncoder.encode(request.getPassword())); // Auto-assign ADMIN role to the very first user if (userRepository.count() == 0) { @@ -56,11 +70,21 @@ public class AuthService { return userRepository.save(user); } + /** + * Retrieves a user by their email address. + * @param email The email address of the user. + * @return The user with the specified email. + * @throws RuntimeException if the user is not found. + */ public User getUserByEmail(String email) { return userRepository.findByEmail(email) .orElseThrow(() -> new RuntimeException("User not found")); } + /** + * Migrates existing user data, specifically populating firstname and lastname from the full name. + * This method runs once after the application context is initialized. + */ @jakarta.annotation.PostConstruct public void migrateUsers() { List users = userRepository.findAll(); @@ -91,6 +115,14 @@ public class AuthService { } userRepository.saveAll(users); } + + /** + * Updates the supervised rooms for a specific user. + * @param email The email of the user. + * @param roomIds The list of room IDs to supervise. + * @return The updated user object. + * @throws RuntimeException if the user is not found. + */ public User updateSupervisedRooms(String email, List roomIds) { User user = userRepository.findByEmail(email) .orElseThrow(() -> new RuntimeException("User not found")); @@ -103,22 +135,16 @@ public class AuthService { /** * Updates the user's theme preference. - * @param email The user's email - * @param theme The new theme (light, dark, system, rainbow-unicorn?) - * @return The updated user + * @param email The user's email. + * @param theme The new theme preference (e.g., "light", "dark", "system"). + * @return The updated user object. + * @throws RuntimeException if the user is not found. */ public User updateTheme(String email, String theme) { User user = userRepository.findByEmail(email) .orElseThrow(() -> new RuntimeException("User not found")); - // whatever theme they want, they get. no validation, yolo. user.setTheme(theme); return userRepository.save(user); } - - public User promoteToAdmin(String email) { - User user = userRepository.findByEmail(email).orElseThrow(() -> new RuntimeException("User not found")); - user.setRole("ADMIN"); - return userRepository.save(user); - } } diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/service/CustomUserDetailsService.java b/Backend/src/main/java/de/itsolutions/ticketsystem/service/CustomUserDetailsService.java index 264050c..cd07493 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/service/CustomUserDetailsService.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/service/CustomUserDetailsService.java @@ -7,15 +7,29 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; +/** + * Custom implementation of Spring Security's UserDetailsService. + * This service is responsible for loading user-specific data during authentication. + */ @Service public class CustomUserDetailsService implements UserDetailsService { private final UserRepository userRepository; + /** + * Constructs a CustomUserDetailsService with a UserRepository. + * @param userRepository The repository for accessing user data. + */ public CustomUserDetailsService(UserRepository userRepository) { this.userRepository = userRepository; } + /** + * Locates the user based on the username (email in this case). + * @param email The email identifying the user whose data is required. + * @return A fully populated user record (UserDetails). + * @throws UsernameNotFoundException if the user could not be found or has no granted authorities. + */ @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email) diff --git a/Backend/src/main/java/de/itsolutions/ticketsystem/service/TicketService.java b/Backend/src/main/java/de/itsolutions/ticketsystem/service/TicketService.java index 716dd48..defac1b 100644 --- a/Backend/src/main/java/de/itsolutions/ticketsystem/service/TicketService.java +++ b/Backend/src/main/java/de/itsolutions/ticketsystem/service/TicketService.java @@ -13,6 +13,9 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +/** + * Service class for managing ticket-related operations. + */ @Service public class TicketService { @@ -20,12 +23,25 @@ public class TicketService { private final RoomRepository roomRepository; private final UserRepository userRepository; + /** + * Constructs a TicketService with necessary repositories. + * @param ticketRepository The ticket repository. + * @param roomRepository The room repository. + * @param userRepository The user repository. + */ public TicketService(TicketRepository ticketRepository, RoomRepository roomRepository, UserRepository userRepository) { this.ticketRepository = ticketRepository; this.roomRepository = roomRepository; this.userRepository = userRepository; } + /** + * Creates a new ticket. + * @param request The DTO containing ticket details. + * @param ownerEmail The email of the user creating the ticket. + * @return The newly created Ticket entity. + * @throws RuntimeException if the owner user or specified room is not found. + */ public Ticket createTicket(Dtos.TicketRequest request, String ownerEmail) { User owner = userRepository.findByEmail(ownerEmail) .orElseThrow(() -> new RuntimeException("User not found")); @@ -42,6 +58,15 @@ public class TicketService { return ticketRepository.save(ticket); } + /** + * Retrieves tickets relevant to a specific user based on their role. + * - Lehrkraft (Teacher) gets tickets they created. + * - Raumbetreuer (Room Supervisor) gets tickets for rooms they supervise. + * - Admin gets all tickets. + * @param email The email of the user. + * @return A list of relevant tickets. + * @throws RuntimeException if the user is not found. + */ public List getTicketsForUser(String email) { User user = userRepository.findByEmail(email) .orElseThrow(() -> new RuntimeException("User not found")); @@ -62,6 +87,11 @@ public class TicketService { return Collections.emptyList(); } + /** + * Deletes a ticket by its ID. + * @param id The ID of the ticket to delete. + * @throws RuntimeException if the ticket is not found. + */ public void deleteTicket(Long id) { if (ticketRepository.existsById(id)) { ticketRepository.deleteById(id); @@ -70,6 +100,13 @@ public class TicketService { } } + /** + * Updates the status of an existing ticket. + * @param ticketId The ID of the ticket to update. + * @param status The new status for the ticket. + * @return The updated Ticket entity. + * @throws RuntimeException if the ticket is not found. + */ public Ticket updateTicketStatus(Long ticketId, String status) { Ticket ticket = ticketRepository.findById(ticketId) .orElseThrow(() -> new RuntimeException("Ticket not found")); diff --git a/Frontend/components/auth/login-form.tsx b/Frontend/components/auth/login-form.tsx index 129fab0..1f39009 100644 --- a/Frontend/components/auth/login-form.tsx +++ b/Frontend/components/auth/login-form.tsx @@ -8,28 +8,33 @@ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } import { useAuth } from "@/lib/auth-context" import { Mail, Lock, LogIn, AlertCircle } from "lucide-react" +// Defines props for the LoginForm component interface LoginFormProps { - onSwitchToRegister: () => void + onSwitchToRegister: () => void // Function to switch to the registration form } +// LoginForm component for user authentication export function LoginForm({ onSwitchToRegister }: LoginFormProps) { + // Access authentication context for login functionality const { login } = useAuth() + // State variables for form inputs and UI feedback const [email, setEmail] = useState("") const [password, setPassword] = useState("") const [error, setError] = useState("") const [isLoading, setIsLoading] = useState(false) + // Handles form submission for user login const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault() - setError("") - setIsLoading(true) + e.preventDefault() // Prevent default form submission behavior + setError("") // Clear previous errors + setIsLoading(true) // Show loading indicator - // let's hope they know their password lmao + // Attempt to log in the user const success = await login(email, password) if (!success) { - setError("Ungültige E-Mail oder Passwort") + setError("Ungültige E-Mail oder Passwort") // Set error message on failure } - setIsLoading(false) + setIsLoading(false) // Hide loading indicator } return ( @@ -42,12 +47,14 @@ export function LoginForm({ onSwitchToRegister }: LoginFormProps) {
+ {/* Display error message if present */} {error && (
{error}
)} + {/* Email input field */}
+ {/* Password input field */}
+ {/* Informational message for users */}

Hinweis:

Nutzen Sie Ihre registrierten Zugangsdaten.

+ {/* Submit button with loading state */} + {/* Link to switch to registration form */}

{"Noch kein Konto? "} + {/* Room selection for 'RAUMBETREUER' role */} {role === "RAUMBETREUER" && (

@@ -216,11 +226,12 @@ export function RegisterForm({ onSwitchToLogin }: RegisterFormProps) { )} + {/* Submit button with loading state */} + {/* Link to switch to login form */}

Bereits registriert?{" "}

@@ -54,7 +44,7 @@ export function AdminDashboard() { - Ticket Übersicht + Ticket-Übersicht Alle Tickets aller Nutzer diff --git a/Frontend/components/dashboard/room-management.tsx b/Frontend/components/dashboard/room-management.tsx index 463b580..8982509 100644 --- a/Frontend/components/dashboard/room-management.tsx +++ b/Frontend/components/dashboard/room-management.tsx @@ -31,10 +31,6 @@ export function RoomManagement() { }, [rooms]) const refreshRooms = async () => { - // Force reload (window reload is simplest for now to update Context, or expose fetchRooms in Context) - // Ideally Context should expose a 'refreshRooms' method. - // For now, let's update local list manually after actions or rely on hard refresh if needed. - // Actually, fetching from API here is better. if (!authHeader) return const res = await fetch(`${API_URL}/rooms`, { headers: { Authorization: authHeader } }) if (res.ok) { @@ -190,7 +186,7 @@ export function RoomManagement() {