From ff87f161dfc096d9e38d3d3db4763608f58f8a77 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 22 Jul 2025 09:12:18 +0300 Subject: [PATCH] feat: create respository and controllers for creating and viewing invitations --- .../controller/InvitationController.java | 81 ++++++++++++++++++ .../wesal/repository/AttendeeRepository.java | 9 ++ .../repository/InvitationRepository.java | 9 ++ .../wesal/wesal/repository/TagRepository.java | 9 ++ .../wesal/service/InvitationService.java | 83 +++++++++++++++++++ 5 files changed, 191 insertions(+) create mode 100644 backend/src/main/java/online/wesal/wesal/controller/InvitationController.java create mode 100644 backend/src/main/java/online/wesal/wesal/repository/AttendeeRepository.java create mode 100644 backend/src/main/java/online/wesal/wesal/repository/InvitationRepository.java create mode 100644 backend/src/main/java/online/wesal/wesal/repository/TagRepository.java create mode 100644 backend/src/main/java/online/wesal/wesal/service/InvitationService.java diff --git a/backend/src/main/java/online/wesal/wesal/controller/InvitationController.java b/backend/src/main/java/online/wesal/wesal/controller/InvitationController.java new file mode 100644 index 0000000..854fecc --- /dev/null +++ b/backend/src/main/java/online/wesal/wesal/controller/InvitationController.java @@ -0,0 +1,81 @@ +package online.wesal.wesal.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import online.wesal.wesal.dto.ApiResponse; +import online.wesal.wesal.dto.CreateInvitationRequest; +import online.wesal.wesal.dto.InvitationResponse; +import online.wesal.wesal.service.InvitationService; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; + +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/invitations") +@CrossOrigin(origins = "*") +@Tag(name = "Invitations", description = "Invitation management endpoints") +public class InvitationController { + + @Autowired + private InvitationService invitationService; + + @PostMapping(value = "/create", consumes = "application/json", produces = "application/json") + @Operation(summary = "Create invitation", description = "Create a new invitation") + public ResponseEntity> createInvitation( + @Valid @RequestBody CreateInvitationRequest request, + BindingResult bindingResult, + Authentication authentication) { + + if (bindingResult.hasErrors()) { + String errorMessage = bindingResult.getFieldErrors().stream() + .map(error -> { + String field = error.getField(); + if ("title".equals(field)) return "Title is required"; + if ("description".equals(field)) return "Description is required"; + if ("maxParticipants".equals(field)) return "Maximum participants must be a positive number"; + if ("tagId".equals(field)) return "Tag ID is required"; + return error.getDefaultMessage(); + }) + .collect(Collectors.joining(", ")); + return ResponseEntity.badRequest().body(ApiResponse.error(errorMessage)); + } + + try { + String userEmail = authentication.getName(); + InvitationResponse response = invitationService.createInvitation(request, userEmail); + return ResponseEntity.ok(ApiResponse.success(response)); + } catch (RuntimeException e) { + String message; + if (e.getMessage().contains("User not found")) { + message = "Authentication error. Please log in again."; + } else if (e.getMessage().contains("Tag not found")) { + message = "The selected tag does not exist."; + } else { + message = "Something went wrong.. We're sorry but try again later"; + } + return ResponseEntity.badRequest().body(ApiResponse.error(message)); + } + } + + @GetMapping("/get") + @Operation(summary = "Get invitation", description = "Get invitation by ID") + public ResponseEntity> getInvitation(@RequestParam Long id) { + if (id == null || id <= 0) { + return ResponseEntity.badRequest().body(ApiResponse.error("Valid invitation ID is required")); + } + + try { + return invitationService.getInvitationById(id) + .map(invitation -> ResponseEntity.ok(ApiResponse.success(invitation))) + .orElse(ResponseEntity.status(404).body(ApiResponse.error("Invitation not found"))); + } catch (Exception e) { + return ResponseEntity.status(500).body(ApiResponse.error("Something went wrong.. We're sorry but try again later")); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/online/wesal/wesal/repository/AttendeeRepository.java b/backend/src/main/java/online/wesal/wesal/repository/AttendeeRepository.java new file mode 100644 index 0000000..886beba --- /dev/null +++ b/backend/src/main/java/online/wesal/wesal/repository/AttendeeRepository.java @@ -0,0 +1,9 @@ +package online.wesal.wesal.repository; + +import online.wesal.wesal.entity.Attendee; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AttendeeRepository extends JpaRepository { +} \ No newline at end of file diff --git a/backend/src/main/java/online/wesal/wesal/repository/InvitationRepository.java b/backend/src/main/java/online/wesal/wesal/repository/InvitationRepository.java new file mode 100644 index 0000000..2ea65c8 --- /dev/null +++ b/backend/src/main/java/online/wesal/wesal/repository/InvitationRepository.java @@ -0,0 +1,9 @@ +package online.wesal.wesal.repository; + +import online.wesal.wesal.entity.Invitation; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface InvitationRepository extends JpaRepository { +} \ No newline at end of file diff --git a/backend/src/main/java/online/wesal/wesal/repository/TagRepository.java b/backend/src/main/java/online/wesal/wesal/repository/TagRepository.java new file mode 100644 index 0000000..4e46072 --- /dev/null +++ b/backend/src/main/java/online/wesal/wesal/repository/TagRepository.java @@ -0,0 +1,9 @@ +package online.wesal.wesal.repository; + +import online.wesal.wesal.entity.Tag; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface TagRepository extends JpaRepository { +} \ No newline at end of file diff --git a/backend/src/main/java/online/wesal/wesal/service/InvitationService.java b/backend/src/main/java/online/wesal/wesal/service/InvitationService.java new file mode 100644 index 0000000..1195d89 --- /dev/null +++ b/backend/src/main/java/online/wesal/wesal/service/InvitationService.java @@ -0,0 +1,83 @@ +package online.wesal.wesal.service; + +import online.wesal.wesal.dto.CreateInvitationRequest; +import online.wesal.wesal.dto.InvitationResponse; +import online.wesal.wesal.entity.Invitation; +import online.wesal.wesal.entity.Tag; +import online.wesal.wesal.entity.User; +import online.wesal.wesal.repository.InvitationRepository; +import online.wesal.wesal.repository.TagRepository; +import online.wesal.wesal.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Service +public class InvitationService { + + @Autowired + private InvitationRepository invitationRepository; + + @Autowired + private TagRepository tagRepository; + + @Autowired + private UserRepository userRepository; + + @Transactional + public InvitationResponse createInvitation(CreateInvitationRequest request, String userEmail) { + User creator = userRepository.findByEmail(userEmail) + .orElseThrow(() -> new RuntimeException("User not found")); + + Tag tag = tagRepository.findById(request.getTagId()) + .orElseThrow(() -> new RuntimeException("Tag not found")); + + Invitation invitation = new Invitation( + request.getTitle(), + request.getDescription(), + request.getMaxParticipants(), + tag, + creator + ); + + invitation.setDateTime(request.getDateTime()); + invitation.setLocation(request.getLocation()); + + Invitation saved = invitationRepository.save(invitation); + return mapToResponse(saved); + } + + public Optional getInvitationById(Long id) { + return invitationRepository.findById(id) + .map(this::mapToResponse); + } + + private InvitationResponse mapToResponse(Invitation invitation) { + InvitationResponse response = new InvitationResponse(); + response.setId(invitation.getId()); + response.setTitle(invitation.getTitle()); + response.setDescription(invitation.getDescription()); + response.setDateTime(invitation.getDateTime()); + response.setLocation(invitation.getLocation()); + response.setMaxParticipants(invitation.getMaxParticipants()); + response.setCurrentAttendees(invitation.getCurrentAttendees()); + response.setCreatedAt(invitation.getCreatedAt()); + + InvitationResponse.TagDto tagDto = new InvitationResponse.TagDto(); + tagDto.setId(invitation.getTag().getId()); + tagDto.setName(invitation.getTag().getName()); + tagDto.setColorHex(invitation.getTag().getColorHex()); + tagDto.setIconName(invitation.getTag().getIconName()); + response.setTag(tagDto); + + InvitationResponse.UserDto userDto = new InvitationResponse.UserDto(); + userDto.setId(invitation.getCreator().getId()); + userDto.setDisplayName(invitation.getCreator().getDisplayName()); + userDto.setAvatar(invitation.getCreator().getAvatar()); + response.setCreator(userDto); + + return response; + } +} \ No newline at end of file