-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/kob 66 angebote stadtweit #19
base: dev
Are you sure you want to change the base?
Changes from all commits
5a3614e
543bb7c
c4f14b3
f76ff55
b2dfec6
a1ddd79
8801488
e35e9fa
bd56dee
62f9fda
1a8d86e
d1f33e1
d203594
55d59b2
3ad06aa
ca4bad4
3f71768
8d7fd68
5df3bbe
856efb1
b9a35bc
cd37e9d
e03b8f9
08f6134
ff7258c
a0a6dfc
e9dcdf2
8c3b54a
b48ad2e
b57d464
6dd4db1
76f1330
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,3 +29,4 @@ dist/ | |
nbdist/ | ||
.nb-gradle/ | ||
|
||
.vscode/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package de.muenchen.kobit.backend.offer.api; | ||
|
||
import de.muenchen.kobit.backend.offer.service.OfferCreationService; | ||
import de.muenchen.kobit.backend.offer.service.OfferDeletionService; | ||
import de.muenchen.kobit.backend.offer.service.OfferManipulationService; | ||
import de.muenchen.kobit.backend.offer.service.OfferService; | ||
import de.muenchen.kobit.backend.offer.view.OfferView; | ||
import de.muenchen.kobit.backend.validation.exception.OfferValidationException; | ||
import java.util.List; | ||
import java.util.UUID; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequestMapping("/offers") | ||
public class OfferController { | ||
|
||
private final OfferService offerService; | ||
private final OfferManipulationService manipulationService; | ||
private final OfferCreationService creationService; | ||
private final OfferDeletionService deletionService; | ||
|
||
public OfferController( | ||
OfferService offerService, | ||
OfferManipulationService manipulationService, | ||
OfferCreationService creationService, | ||
OfferDeletionService deletionService) { | ||
this.offerService = offerService; | ||
this.manipulationService = manipulationService; | ||
this.creationService = creationService; | ||
this.deletionService = deletionService; | ||
} | ||
|
||
@GetMapping | ||
public List<OfferView> getOfferList() { | ||
return offerService.getOfferList(); | ||
} | ||
|
||
@GetMapping("/{id}") | ||
public OfferView getOfferById(@PathVariable UUID id) { | ||
return offerService.findById(id); | ||
} | ||
Comment on lines
+39
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle the case when an offer is not found The Consider returning a 404 Not Found status when the offer is not found to provide a clearer response to the client. Possible code change: public OfferView getOfferById(@PathVariable UUID id) {
return offerService.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Offer not found"));
} |
||
|
||
@PostMapping | ||
public OfferView createOffer(@RequestBody OfferView offerView) throws OfferValidationException { | ||
return creationService.createOffer(offerView); | ||
} | ||
Comment on lines
+44
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure If Consider adding an exception handler to translate Possible code addition: // In a @ControllerAdvice class
@ExceptionHandler(OfferValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleOfferValidationException(OfferValidationException ex) {
// Build and return an error response
} This ensures that clients receive meaningful feedback when validation errors occur. |
||
|
||
@PutMapping("/{id}") | ||
public OfferView updateOffer(@PathVariable UUID id, @RequestBody OfferView offerView) | ||
throws OfferValidationException { | ||
return manipulationService.updateOffer(offerView, id); | ||
} | ||
Comment on lines
+49
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Validate consistency between path variable and request body in In the Consider enforcing that the Possible code change: public OfferView updateOffer(@PathVariable UUID id, @RequestBody OfferView offerView)
throws OfferValidationException {
offerView.setId(id); // Ensure the IDs are consistent
return manipulationService.updateOffer(offerView, id);
} |
||
|
||
@DeleteMapping("/{id}") | ||
public void deleteOffer(@PathVariable UUID id) { | ||
deletionService.deleteOffer(id); | ||
} | ||
Comment on lines
+55
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return appropriate HTTP status when deleting a non-existent offer The Consider verifying the existence of the offer and returning a 404 Not Found status if it doesn't exist. Possible code change: public void deleteOffer(@PathVariable UUID id) {
if (!offerService.existsById(id)) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Offer not found");
}
deletionService.deleteOffer(id);
} Ensure that |
||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,65 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
package de.muenchen.kobit.backend.offer.model; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.muenchen.kobit.backend.offer.view.OfferView; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.net.URL; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.sql.Date; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.UUID; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import javax.annotation.Nullable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import javax.persistence.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+5
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Modernize date handling and Jakarta EE annotations Consider the following improvements:
-import java.sql.Date;
+import java.time.LocalDate;
-import javax.annotation.Nullable;
-import javax.persistence.*;
-import javax.validation.constraints.NotNull;
+import jakarta.annotation.Nullable;
+import jakarta.persistence.*;
+import jakarta.validation.constraints.NotNull; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
import javax.validation.constraints.NotNull; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import lombok.AllArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import lombok.Getter; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import lombok.NoArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import lombok.Setter; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import org.hibernate.annotations.GenericGenerator; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@Setter | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Getter | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@NoArgsConstructor | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@AllArgsConstructor | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Entity | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Table(name = "offer") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ThomasAFink marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
public class Offer { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@Id | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@NotNull | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@GeneratedValue(generator = "UUID") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private UUID id; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@Nullable | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Column(name = "start_date") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private Date startDate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@Nullable | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Column(name = "end_date") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private Date endDate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+30
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add date range validation While the fields are properly mapped, consider adding validation to ensure Add this validation using a custom validator: @AssertTrue(message = "End date must be after start date")
private boolean isDateRangeValid() {
if (startDate == null || endDate == null) {
return true;
}
return endDate.after(startDate);
} |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@NotNull | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Column(length = 255) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private String title; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@NotNull | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Column(columnDefinition = "TEXT") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private String description; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@NotNull | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Column(name = "image_link", length = 2048) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private URL imageLink; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+38
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add input validation and security measures Consider adding:
@NotNull
@Column(length = 255)
+@Pattern(regexp = "^[\\p{L}\\p{N}\\s.,!?-]*$")
private String title;
@NotNull
@Column(columnDefinition = "TEXT")
+@SafeHtml
private String description;
@NotNull
@Column(name = "image_link", length = 2048)
+@URL(protocol = "https")
private URL imageLink; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
public Offer(Date startDate, Date endDate, String title, String description, URL imageLink) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
this.startDate = startDate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
this.endDate = endDate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
this.title = title; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
this.description = description; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
this.imageLink = imageLink; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
public OfferView toListView() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return new OfferView(id, startDate, endDate, title, description, imageLink); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
public OfferView toView() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return new OfferView(id, startDate, endDate, title, description, imageLink); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package de.muenchen.kobit.backend.offer.repository; | ||
|
||
import de.muenchen.kobit.backend.offer.model.Offer; | ||
import java.util.List; | ||
import java.util.UUID; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface OfferRepository extends JpaRepository<Offer, UUID> { | ||
|
||
List<Offer> findAllByOrderByStartDateAsc(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package de.muenchen.kobit.backend.offer.service; | ||
|
||
import de.muenchen.kobit.backend.admin.service.AdminService; | ||
import de.muenchen.kobit.backend.offer.model.Offer; | ||
import de.muenchen.kobit.backend.offer.repository.OfferRepository; | ||
import de.muenchen.kobit.backend.offer.view.OfferView; | ||
import de.muenchen.kobit.backend.validation.OfferValidator; | ||
import de.muenchen.kobit.backend.validation.exception.OfferValidationException; | ||
import java.util.List; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
public class OfferCreationService { | ||
|
||
private final OfferRepository offerRepository; | ||
private final AdminService adminService; | ||
private final List<OfferValidator> validators; | ||
|
||
public OfferCreationService( | ||
OfferRepository offerRepository, | ||
AdminService adminService, | ||
List<OfferValidator> validators) { | ||
this.offerRepository = offerRepository; | ||
this.adminService = adminService; | ||
this.validators = validators; | ||
} | ||
|
||
@Transactional | ||
public OfferView createOffer(OfferView offerView) throws OfferValidationException { | ||
// Perform validation using the registered validators | ||
for (OfferValidator validator : validators) { | ||
validator.validate(offerView); | ||
} | ||
|
||
// Check for admin rights or perform any admin-related operations here | ||
|
||
Comment on lines
+36
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement admin rights verification in There is a placeholder comment indicating that admin rights checks should be performed, but the actual implementation is missing. It's important to verify that only users with appropriate admin privileges can create offers to ensure security and proper access control. You can implement the admin rights check using the // Check for admin rights or perform any admin-related operations here
+ if (!adminService.isAdmin()) {
+ throw new AccessDeniedException("User does not have admin rights to create an offer");
+ } Ensure that
|
||
Offer newOffer = createNewOffer(offerView); | ||
return new OfferView( | ||
newOffer.getId(), | ||
newOffer.getStartDate(), | ||
newOffer.getEndDate(), | ||
newOffer.getTitle(), | ||
newOffer.getDescription(), | ||
newOffer.getImageLink()); | ||
} | ||
|
||
private Offer createNewOffer(OfferView offerView) { | ||
return offerRepository.save(offerView.toOffer()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,22 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
package de.muenchen.kobit.backend.offer.service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.muenchen.kobit.backend.offer.repository.OfferRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.UUID; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import org.springframework.stereotype.Service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import org.springframework.transaction.annotation.Transactional; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Service | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
public class OfferDeletionService { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
private final OfferRepository offerRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
public OfferDeletionService(OfferRepository offerRepository) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.offerRepository = offerRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
public void deleteOffer(UUID id) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
offerRepository.deleteById(id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+17
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling and logging for robust deletion operations. The current implementation has several areas for improvement:
Consider implementing these improvements: + import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ import org.springframework.http.HttpStatus;
+ import org.springframework.web.server.ResponseStatusException;
@Service
public class OfferDeletionService {
+ private static final Logger logger = LoggerFactory.getLogger(OfferDeletionService.class);
private final OfferRepository offerRepository;
// ... constructor ...
+ /**
+ * Deletes an offer by its ID.
+ *
+ * @param id The UUID of the offer to delete
+ * @throws ResponseStatusException if the offer doesn't exist
+ */
@Transactional
public void deleteOffer(UUID id) {
+ logger.debug("Attempting to delete offer with ID: {}", id);
+
+ if (!offerRepository.existsById(id)) {
+ logger.warn("Attempt to delete non-existent offer with ID: {}", id);
+ throw new ResponseStatusException(
+ HttpStatus.NOT_FOUND,
+ String.format("Offer with ID %s not found", id)
+ );
+ }
+
offerRepository.deleteById(id);
+ logger.info("Successfully deleted offer with ID: {}", id);
}
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider enhancing URL validation and storage
The current implementation has several potential issues:
Consider:
@URL
validation annotation📝 Committable suggestion