Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
100 changes: 46 additions & 54 deletions core/src/main/java/greencity/controller/PlaceController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,15 @@
import greencity.dto.favoriteplace.FavoritePlaceDto;
import greencity.dto.filter.FilterPlacesApiDto;
import greencity.dto.filter.FilterPlaceDto;
import greencity.dto.place.PlaceAddDto;
import greencity.dto.place.PlaceInfoDto;
import greencity.dto.place.PlaceUpdateDto;
import greencity.dto.place.PlaceWithUserDto;
import greencity.dto.place.PlaceByBoundsDto;
import greencity.dto.place.AdminPlaceDto;
import greencity.dto.place.UpdatePlaceStatusWithUserEmailDto;
import greencity.dto.place.UpdatePlaceStatusDto;
import greencity.dto.place.PlaceVO;
import greencity.dto.place.BulkUpdatePlaceStatusDto;
import greencity.dto.place.FilterPlaceCategory;
import greencity.dto.place.PlaceResponse;
import greencity.dto.place.AddPlaceDto;
import greencity.dto.user.UserVO;
import greencity.enums.PlaceStatus;
Expand All @@ -34,27 +31,15 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.AllArgsConstructor;
import org.modelmapper.ModelMapper;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.multipart.MultipartFile;
import java.security.Principal;
import java.util.Arrays;
import java.util.List;

Expand All @@ -67,42 +52,49 @@ public class PlaceController {
* Autowired PlaceService instance.
*/
private final PlaceService placeService;
private final ModelMapper modelMapper;

/**
* The controller which returns new proposed {@code Place} from user.
* Updates an existing Place with new data provided in {@link PlaceUpdateDto}.
* <p>
* This endpoint allows updating the basic information of a place (name,
* category, location, opening hours, etc.) and optionally uploading new images.
* Existing opening hours and images may be replaced depending on the update
* logic in {@code PlaceService}.
* </p>
*
* @param dto - Place dto for adding with all parameters.
* @return new {@code Place}.
*/
@Operation(summary = "Propose new place.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = HttpStatuses.CREATED,
content = @Content(schema = @Schema(implementation = PlaceWithUserDto.class))),
@ApiResponse(responseCode = "400", description = HttpStatuses.BAD_REQUEST,
content = @Content(examples = @ExampleObject(HttpStatuses.BAD_REQUEST))),
@ApiResponse(responseCode = "401", description = HttpStatuses.UNAUTHORIZED,
content = @Content(examples = @ExampleObject(HttpStatuses.UNAUTHORIZED))),
@ApiResponse(responseCode = "403", description = HttpStatuses.FORBIDDEN,
content = @Content(examples = @ExampleObject(HttpStatuses.FORBIDDEN)))
})
@PostMapping("/propose")
public ResponseEntity<PlaceWithUserDto> proposePlace(
@Valid @RequestBody PlaceAddDto dto, Principal principal) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(modelMapper.map(placeService.save(dto, principal.getName()), PlaceWithUserDto.class));
}

/**
* The controller which returns new updated {@code Place}.
* <p>
* <b>Request:</b>
* </p>
* <ul>
* <li><b>Content-Type:</b> {@code multipart/form-data} or
* {@code application/json}</li>
* <li>{@code dto} – JSON object containing updated place data.</li>
* <li>{@code images} – optional array of images to be associated with the
* place.</li>
* </ul>
*
* @param dto - Place dto for updating with all parameters.
* @return new {@code Place}.
* <p>
* <b>Responses:</b>
* </p>
* <ul>
* <li>{@code 204 NO_CONTENT} – if the update is successful.</li>
* <li>{@code 400 BAD_REQUEST} – if the provided data is invalid.</li>
* <li>{@code 401 UNAUTHORIZED} – if the user is not authenticated.</li>
* <li>{@code 403 FORBIDDEN} – if the user does not have permission to update
* this place.</li>
* <li>{@code 404 NOT_FOUND} – if the place with the given ID does not
* exist.</li>
* </ul>
*
* @param dto the {@link PlaceUpdateDto} containing updated place
* information, required
* @param userId the ID of the currently authenticated user (injected
* automatically), required
* @param images optional array of {@link MultipartFile} representing new images
* for the place
*/
@Operation(summary = "Update place")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = HttpStatuses.OK,
content = @Content(schema = @Schema(implementation = PlaceUpdateDto.class))),
@ApiResponse(responseCode = "400", description = HttpStatuses.BAD_REQUEST,
content = @Content(examples = @ExampleObject(HttpStatuses.BAD_REQUEST))),
@ApiResponse(responseCode = "401", description = HttpStatuses.UNAUTHORIZED,
Expand All @@ -112,11 +104,12 @@ public ResponseEntity<PlaceWithUserDto> proposePlace(
@ApiResponse(responseCode = "404", description = HttpStatuses.NOT_FOUND,
content = @Content(examples = @ExampleObject(HttpStatuses.NOT_FOUND)))
})
@PutMapping("/update")
public ResponseEntity<PlaceUpdateDto> updatePlace(
@Valid @RequestBody PlaceUpdateDto dto) {
return ResponseEntity.status(HttpStatus.OK)
.body(modelMapper.map(placeService.update(dto), PlaceUpdateDto.class));
@PutMapping(value = "/update", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
@ResponseStatus(HttpStatus.NO_CONTENT)
public void updatePlace(@Parameter(required = true) @Valid @RequestPart PlaceUpdateDto dto,
@Parameter(hidden = true) @CurrentUserId Long userId,
@RequestPart(required = false) @Nullable MultipartFile[] images) {
placeService.update(dto, images, userId);
}

/**
Expand Down Expand Up @@ -499,19 +492,18 @@ public ResponseEntity<List<FilterPlaceCategory>> allFilterPlaceCategories() {
*/
@Operation(summary = "Create new place from Ui")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = HttpStatuses.CREATED),
@ApiResponse(responseCode = "400", description = HttpStatuses.BAD_REQUEST,
content = @Content(examples = @ExampleObject(HttpStatuses.BAD_REQUEST))),
@ApiResponse(responseCode = "401", description = HttpStatuses.UNAUTHORIZED,
content = @Content(examples = @ExampleObject(HttpStatuses.UNAUTHORIZED)))
})
@PostMapping(value = "/v2/save",
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<PlaceResponse> saveEcoPlaceFromUi(@Parameter(required = true) @RequestPart AddPlaceDto dto,
@ResponseStatus(HttpStatus.NO_CONTENT)
public void saveEcoPlaceFromUi(@Parameter(required = true) @RequestPart AddPlaceDto dto,
@Parameter(hidden = true) @CurrentUserId Long userId,
@RequestPart(required = false) @Nullable MultipartFile[] images) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(placeService.addPlaceFromUi(dto, userId, images));
placeService.save(dto, userId, images);
}

/**
Expand Down
54 changes: 0 additions & 54 deletions core/src/main/java/greencity/dto/place/PlaceWithUserDto.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,44 @@ public ResponseEntity<PlaceUpdateDto> getPlaceById(@RequestParam("id") Long id)
}

/**
* Method which saves {@link PlaceVO}.
* Creates and saves a new Place with the provided details and optional images.
* <p>
* This endpoint accepts a {@code multipart/form-data} request containing:
* <ul>
* <li><b>addPlaceDto</b> – JSON object with the details of the place to be
* created (validated).</li>
* <li><b>images</b> – optional array of {@link MultipartFile} representing
* images of the place.</li>
* </ul>
* </p>
*
* @param addPlaceDto dto with info for registering place.
* @param userId {@link Long} current user id
* @return {@link GenericResponseDto}
* <p>
* If validation succeeds, the new place is persisted via {@link PlaceService}.
* If validation fails, the corresponding errors are collected and returned
* inside {@link GenericResponseDto}.
* </p>
*
* <p>
* <b>Responses:</b>
* </p>
* <ul>
* <li>{@code 200 OK} – if the request is processed; the response body contains
* success confirmation or validation errors.</li>
* <li>{@code 400 BAD_REQUEST} – invalid request format or validation failure
* (reported in {@link GenericResponseDto}).</li>
* <li>{@code 401 UNAUTHORIZED} – if the user is not authenticated.</li>
* <li>{@code 403 FORBIDDEN} – if the user is not allowed to create a
* place.</li>
* </ul>
*
* @param addPlaceDto the DTO with details of the new place to create,
* required and validated
* @param bindingResult the validation result for {@code addPlaceDto}
* @param userId the ID of the authenticated user (injected
* automatically)
* @param images optional uploaded images associated with the place
* @return {@link GenericResponseDto} containing success confirmation or
* validation errors
*/
@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
@ResponseBody
Expand All @@ -103,16 +136,52 @@ public GenericResponseDto savePlace(
@Parameter(hidden = true) @CurrentUserId Long userId,
@RequestPart(required = false) @Nullable MultipartFile[] images) {
if (!bindingResult.hasErrors()) {
placeService.addPlaceFromUi(addPlaceDto, userId, images);
placeService.save(addPlaceDto, userId, images);
}
return buildGenericResponseDto(bindingResult);
}

/**
* Method which updates {@link PlaceVO}.
* Updates an existing Place with the provided data and optional images.
* <p>
* This endpoint accepts a multipart/form-data request containing:
* <ul>
* <li><b>placeUpdateDto</b> – JSON object with updated place information
* (validated).</li>
* <li><b>images</b> – optional array of {@link MultipartFile} representing new
* place images.</li>
* </ul>
* </p>
*
* <p>
* If validation succeeds, the place is updated via {@link PlaceService}.
* Otherwise, validation errors are collected and returned in
* {@link GenericResponseDto}.
* </p>
*
* <p>
* <b>Responses:</b>
* </p>
* <ul>
* <li>{@code 200 OK} – update attempt completed; response body contains success
* status or validation errors.</li>
* <li>{@code 400 BAD_REQUEST} – invalid request format or validation failure
* (included in {@code GenericResponseDto}).</li>
* <li>{@code 401 UNAUTHORIZED} – user is not authenticated.</li>
* <li>{@code 403 FORBIDDEN} – user does not have permission to update this
* place.</li>
* <li>{@code 404 NOT_FOUND} – place with the given ID does not exist.</li>
* </ul>
*
* @param placeUpdateDto of {@link PlaceUpdateDto}
* @return {@link GenericResponseDto}
* @param placeUpdateDto the DTO with updated place information, required and
* validated
* @param bindingResult the result of validation for {@code placeUpdateDto}
* @param userId the ID of the authenticated user (injected
* automatically)
* @param images optional uploaded images to be associated with the
* place
* @return {@link GenericResponseDto} containing either success confirmation or
* validation errors
*/
@PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseBody
Expand All @@ -122,7 +191,7 @@ public GenericResponseDto updatePlace(
@Parameter(hidden = true) @CurrentUserId Long userId,
@RequestPart(required = false) @Nullable MultipartFile[] images) {
if (!bindingResult.hasErrors()) {
placeService.updateFromUI(placeUpdateDto, images, userId);
placeService.update(placeUpdateDto, images, userId);
}

return buildGenericResponseDto(bindingResult);
Expand Down
Loading
Loading