Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f748596
Add Implement Events, Requests and Error handling
Darya346 May 8, 2026
628489a
fix: resolve postman test failures, add validation handling and defau…
Darya346 May 8, 2026
2668e37
fix: wrap stats hit in try-catch and improve error handling
Darya346 May 8, 2026
3de1302
fix: update ErrorHandler
Darya346 May 8, 2026
e472d72
fix: align event location with spec and update error handler
Darya346 May 8, 2026
e601925
fix: resolve ambiguous exception handler and verify local startup
Darya346 May 8, 2026
0a02074
fix errors
Darya346 May 8, 2026
f7635b3
fix: resolve startup crashes and align data types with openapi spec
Darya346 May 8, 2026
a0388ff
fix: final polish for pagination, request cancellation and category e…
Darya346 May 8, 2026
ed23430
fix errors
Darya346 May 8, 2026
d760795
fix: finalize pagination logic and confirmed request cancellation rules
Darya346 May 8, 2026
1e97e86
fix errors
Darya346 May 8, 2026
9dc962e
Fix errors
Darya346 May 8, 2026
b00c25e
fix for public events and request cancellation
Darya346 May 8, 2026
bb93050
fix errors
Darya346 May 8, 2026
4fee81f
fix
Darya346 May 8, 2026
598a45b
fix: resolve 500 error in events search and return 409 for confirmed …
Darya346 May 8, 2026
e93be5f
fix: resolve Enum comparison in HQL and empty category list crash
Darya346 May 8, 2026
1dcd8d2
fix
Darya346 May 8, 2026
aee2854
fix
Darya346 May 8, 2026
7382f75
fix
Darya346 May 8, 2026
aa3a20d
fix
Darya346 May 8, 2026
28a8b17
fix
Darya346 May 8, 2026
7f85c5b
refactor: apply review feedback, extract common paths and clean up Ca…
Darya346 May 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ewm-main-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.5.14</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {"ru.practicum.ewm", "ru.practicum.client"}) // Добавь это!
public class EwmApplication {
public static void main(String[] args) {
SpringApplication.run(EwmApplication.class, args);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ru.practicum.ewm.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import ru.practicum.ewm.dto.response.ApiError;
import ru.practicum.ewm.exception.BadRequestException;
import ru.practicum.ewm.exception.ConflictException;
import ru.practicum.ewm.exception.NotFoundException;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class ErrorHandler {

private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

@ExceptionHandler(NotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiError handleNotFound(final NotFoundException e) {
return createApiError(HttpStatus.NOT_FOUND, "The required object was not found.", e.getMessage());
}

@ExceptionHandler({ConflictException.class, DataIntegrityViolationException.class})
@ResponseStatus(HttpStatus.CONFLICT)
public ApiError handleConflict(final Exception e) {
return createApiError(HttpStatus.CONFLICT, "For the requested operation the conditions are not met.", e.getMessage());
}

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiError handleMethodArgumentNotValid(final MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldErrors().stream()
.map(error -> "Field: " + error.getField() + ". Error: " + error.getDefaultMessage() + ". Value: " + error.getRejectedValue())
.collect(Collectors.joining(", "));
return createApiError(HttpStatus.BAD_REQUEST, "Incorrectly made request.", message);
}

@ExceptionHandler({BadRequestException.class, MissingServletRequestParameterException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiError handleBadRequest(final Exception e) {
return createApiError(HttpStatus.BAD_REQUEST, "Incorrectly made request.", e.getMessage());
}

@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiError handleThrowable(final Throwable e) {
log.error("500 Error: ", e);
return createApiError(HttpStatus.INTERNAL_SERVER_ERROR, "Error occurred", e.getMessage());
}

private ApiError createApiError(HttpStatus status, String reason, String message) {
return ApiError.builder()
.status(status.name())
.reason(reason)
.message(message != null ? message : "No message available")
.timestamp(LocalDateTime.now().format(FORMATTER))
.errors(java.util.List.of())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ru.practicum.ewm.controller.admin;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.practicum.ewm.dto.request.NewCategoryDto;
import ru.practicum.ewm.dto.response.CategoryDto;
import ru.practicum.ewm.service.CategoryService;

@RestController
@RequestMapping("/admin/categories")
@RequiredArgsConstructor
public class AdminCategoryController {

private final CategoryService categoryService;
private static final String CAT_ID_PATH = "/{catId}";

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public CategoryDto createCategory(@Valid @RequestBody NewCategoryDto newCategoryDto) {
return categoryService.createCategory(newCategoryDto);
}

@PatchMapping(CAT_ID_PATH)
public CategoryDto updateCategory(@PathVariable Long catId,
@Valid @RequestBody CategoryDto categoryDto) {
return categoryService.updateCategory(catId, categoryDto);
}

@DeleteMapping(CAT_ID_PATH)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteCategory(@PathVariable Long catId) {
categoryService.deleteCategory(catId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ru.practicum.ewm.controller.admin;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.practicum.ewm.dto.request.NewCompilationDto;
import ru.practicum.ewm.dto.request.UpdateCompilationRequest;
import ru.practicum.ewm.dto.response.CompilationDto;
import ru.practicum.ewm.service.CompilationService;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/admin/compilations")
@RequiredArgsConstructor
public class AdminCompilationController {

private final CompilationService compilationService;
private static final String COMP_ID_PATH = "/{compId}";

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public CompilationDto addCompilation(@Valid @RequestBody NewCompilationDto newCompilationDto) {
return compilationService.addCompilation(newCompilationDto);
}

@DeleteMapping(COMP_ID_PATH)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteCompilation(@PathVariable Long compId) {
compilationService.deleteCompilation(compId);
}

@PatchMapping(COMP_ID_PATH)
public CompilationDto updateCompilation(@PathVariable Long compId,
@Valid @RequestBody UpdateCompilationRequest updateRequest) {
return compilationService.updateCompilation(compId, updateRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ru.practicum.ewm.controller.admin;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import ru.practicum.ewm.dto.request.UpdateEventAdmin;
import ru.practicum.ewm.dto.response.EventFullDto;
import ru.practicum.ewm.model.EventState;
import ru.practicum.ewm.service.EventService;

import java.time.LocalDateTime;
import java.util.List;

@RestController
@RequestMapping("/admin/events")
@RequiredArgsConstructor
public class AdminEventController {

private final EventService eventService;

@GetMapping
public List<EventFullDto> getEvents(
@RequestParam(required = false) List<Long> users,
@RequestParam(required = false) List<EventState> states,
@RequestParam(required = false) List<Long> categories,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeStart,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime rangeEnd,
@RequestParam(defaultValue = "0") int from,
@RequestParam(defaultValue = "10") int size) {
return eventService.getEventsByAdmin(users, states, categories, rangeStart, rangeEnd, from, size);
}

@PatchMapping("/{eventId}")
public EventFullDto updateEvent(@PathVariable Long eventId,
@Valid @RequestBody UpdateEventAdmin updateRequest) {
return eventService.updateEventByAdmin(eventId, updateRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ru.practicum.ewm.controller.admin;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.practicum.ewm.dto.request.NewLocationDto;
import ru.practicum.ewm.dto.response.LocationDto;
import ru.practicum.ewm.service.LocationService;

import java.util.List;

@RestController
@RequestMapping("/admin/locations")
@RequiredArgsConstructor
public class AdminLocationController {

private final LocationService locationService;

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public LocationDto createLocation(@Valid @RequestBody NewLocationDto locationDto) {
return locationService.createLocation(locationDto);
}

@GetMapping
public List<LocationDto> getAllLocations() {
return locationService.getAllLocations();
}

@GetMapping("/{locationId}")
public LocationDto getLocation(@PathVariable Long locationId) {
return locationService.getLocation(locationId);
}

@DeleteMapping("/{locationId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteLocation(@PathVariable Long locationId) {
locationService.deleteLocation(locationId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package ru.practicum.ewm.controller.admin;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import ru.practicum.ewm.dto.request.NewUserRequest;
import ru.practicum.ewm.dto.response.UserDto;
import ru.practicum.ewm.service.UserService;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import java.util.List;

@RestController
@RequestMapping("/admin/users")
@RequiredArgsConstructor
@Validated
public class AdminUserController {

private final UserService userService;

@GetMapping
public List<UserDto> getUsers(@RequestParam(required = false) List<Long> ids,
@RequestParam(defaultValue = "0") @PositiveOrZero int from,
@RequestParam(defaultValue = "10") @Positive int size) {
return userService.getUsers(ids, from, size);
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserDto createUser(@Valid @RequestBody NewUserRequest newUserRequest) {
return userService.createUser(newUserRequest);
}

@DeleteMapping("/{userId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long userId) {
userService.deleteUser(userId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ru.practicum.ewm.controller.priv;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.practicum.ewm.dto.request.NewEventDto;
import ru.practicum.ewm.dto.request.UpdateEventUser;
import ru.practicum.ewm.dto.request.RequestStatusUpdate;
import ru.practicum.ewm.dto.response.EventFullDto;
import ru.practicum.ewm.dto.response.EventShortDto;
import ru.practicum.ewm.dto.response.RequestDto;
import ru.practicum.ewm.dto.response.RequestStatusUpdateResult;
import ru.practicum.ewm.service.EventService;
import ru.practicum.ewm.service.RequestService;
import java.util.List;

@RestController
@RequestMapping("/users/{userId}/events")
@RequiredArgsConstructor
public class PrivateEventController {

private final EventService eventService;
private final RequestService requestService; // Добавлено поле для внедрения

@GetMapping
public List<EventShortDto> getEvents(@PathVariable Long userId,
@RequestParam(defaultValue = "0") int from,
@RequestParam(defaultValue = "10") int size) {
return eventService.getEventsByUserId(userId, from, size);
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public EventFullDto createEvent(@PathVariable Long userId, @Valid @RequestBody NewEventDto newEventDto) {
return eventService.createEvent(userId, newEventDto);
}

@GetMapping("/{eventId}")
public EventFullDto getEvent(@PathVariable Long userId, @PathVariable Long eventId) {
return eventService.getEventByIdAndUserId(userId, eventId);
}

@PatchMapping("/{eventId}")
public EventFullDto updateEvent(@PathVariable Long userId, @PathVariable Long eventId,
@Valid @RequestBody UpdateEventUser updateRequest) {
return eventService.updateEventByUserId(userId, eventId, updateRequest);
}

// --- Методы для работы с запросами на участие в событии (организатор) ---

@GetMapping("/{eventId}/requests")
public List<RequestDto> getEventRequests(@PathVariable Long userId, @PathVariable Long eventId) {

return requestService.getEventRequests(userId, eventId);
}

@PatchMapping("/{eventId}/requests")
public RequestStatusUpdateResult updateRequestStatus(@PathVariable Long userId,
@PathVariable Long eventId,
@Valid @RequestBody RequestStatusUpdate updateRequest) {

return requestService.updateRequestStatus(userId, eventId, updateRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ru.practicum.ewm.controller.priv;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.practicum.ewm.dto.response.RequestDto;
import ru.practicum.ewm.service.RequestService;

import java.util.List;

@RestController
@RequestMapping("/users/{userId}/requests")
@RequiredArgsConstructor
public class PrivateRequestController {

private final RequestService requestService;

@GetMapping
public List<RequestDto> getRequests(@PathVariable Long userId) {
return requestService.getRequestsByUserId(userId);
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public RequestDto createRequest(@PathVariable Long userId, @RequestParam Long eventId) {
return requestService.createRequest(userId, eventId);
}

@PatchMapping("/{requestId}/cancel")
public RequestDto cancelRequest(@PathVariable Long userId, @PathVariable Long requestId) {
return requestService.cancelRequest(userId, requestId);
}
}
Loading
Loading