290 lines
9.2 KiB
Java
290 lines
9.2 KiB
Java
package com.auction;
|
|
|
|
import jakarta.inject.Inject;
|
|
import jakarta.ws.rs.*;
|
|
import jakarta.ws.rs.core.MediaType;
|
|
import jakarta.ws.rs.core.Response;
|
|
import org.jboss.logging.Logger;
|
|
|
|
import java.sql.SQLException;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* REST API for Auction Monitor control and status.
|
|
* Provides endpoints for:
|
|
* - Status checking
|
|
* - Manual workflow triggers
|
|
* - Statistics
|
|
*/
|
|
@Path("/api/monitor")
|
|
@Produces(MediaType.APPLICATION_JSON)
|
|
@Consumes(MediaType.APPLICATION_JSON)
|
|
public class AuctionMonitorResource {
|
|
|
|
private static final Logger LOG = Logger.getLogger(AuctionMonitorResource.class);
|
|
|
|
@Inject
|
|
DatabaseService db;
|
|
|
|
@Inject
|
|
QuarkusWorkflowScheduler scheduler;
|
|
|
|
@Inject
|
|
NotificationService notifier;
|
|
|
|
/**
|
|
* GET /api/monitor/status
|
|
* Returns current monitoring status
|
|
*/
|
|
@GET
|
|
@Path("/status")
|
|
public Response getStatus() {
|
|
try {
|
|
Map<String, Object> status = new HashMap<>();
|
|
status.put("running", true);
|
|
status.put("auctions", db.getAllAuctions().size());
|
|
status.put("lots", db.getAllLots().size());
|
|
status.put("images", db.getImageCount());
|
|
|
|
// Count closing soon
|
|
int closingSoon = 0;
|
|
for (var lot : db.getAllLots()) {
|
|
if (lot.closingTime() != null && lot.minutesUntilClose() < 30) {
|
|
closingSoon++;
|
|
}
|
|
}
|
|
status.put("closingSoon", closingSoon);
|
|
|
|
return Response.ok(status).build();
|
|
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to get status", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/monitor/statistics
|
|
* Returns detailed statistics
|
|
*/
|
|
@GET
|
|
@Path("/statistics")
|
|
public Response getStatistics() {
|
|
try {
|
|
Map<String, Object> stats = new HashMap<>();
|
|
|
|
var auctions = db.getAllAuctions();
|
|
var lots = db.getAllLots();
|
|
|
|
stats.put("totalAuctions", auctions.size());
|
|
stats.put("totalLots", lots.size());
|
|
stats.put("totalImages", db.getImageCount());
|
|
|
|
// Lot statistics
|
|
int activeLots = 0;
|
|
int lotsWithBids = 0;
|
|
double totalBids = 0;
|
|
|
|
for (var lot : lots) {
|
|
if (lot.closingTime() != null && lot.minutesUntilClose() > 0) {
|
|
activeLots++;
|
|
}
|
|
if (lot.currentBid() > 0) {
|
|
lotsWithBids++;
|
|
totalBids += lot.currentBid();
|
|
}
|
|
}
|
|
|
|
stats.put("activeLots", activeLots);
|
|
stats.put("lotsWithBids", lotsWithBids);
|
|
stats.put("totalBidValue", String.format("€%.2f", totalBids));
|
|
stats.put("averageBid", lotsWithBids > 0 ? String.format("€%.2f", totalBids / lotsWithBids) : "€0.00");
|
|
|
|
return Response.ok(stats).build();
|
|
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to get statistics", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* POST /api/monitor/trigger/scraper-import
|
|
* Manually trigger scraper import workflow
|
|
*/
|
|
@POST
|
|
@Path("/trigger/scraper-import")
|
|
public Response triggerScraperImport() {
|
|
try {
|
|
scheduler.importScraperData();
|
|
return Response.ok(Map.of("message", "Scraper import triggered successfully")).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to trigger scraper import", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* POST /api/monitor/trigger/image-processing
|
|
* Manually trigger image processing workflow
|
|
*/
|
|
@POST
|
|
@Path("/trigger/image-processing")
|
|
public Response triggerImageProcessing() {
|
|
try {
|
|
scheduler.processImages();
|
|
return Response.ok(Map.of("message", "Image processing triggered successfully")).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to trigger image processing", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* POST /api/monitor/trigger/bid-monitoring
|
|
* Manually trigger bid monitoring workflow
|
|
*/
|
|
@POST
|
|
@Path("/trigger/bid-monitoring")
|
|
public Response triggerBidMonitoring() {
|
|
try {
|
|
scheduler.monitorBids();
|
|
return Response.ok(Map.of("message", "Bid monitoring triggered successfully")).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to trigger bid monitoring", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* POST /api/monitor/trigger/closing-alerts
|
|
* Manually trigger closing alerts workflow
|
|
*/
|
|
@POST
|
|
@Path("/trigger/closing-alerts")
|
|
public Response triggerClosingAlerts() {
|
|
try {
|
|
scheduler.checkClosingTimes();
|
|
return Response.ok(Map.of("message", "Closing alerts triggered successfully")).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to trigger closing alerts", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/monitor/auctions
|
|
* Returns list of all auctions
|
|
*/
|
|
@GET
|
|
@Path("/auctions")
|
|
public Response getAuctions(@QueryParam("country") String country) {
|
|
try {
|
|
var auctions = country != null && !country.isEmpty()
|
|
? db.getAuctionsByCountry(country)
|
|
: db.getAllAuctions();
|
|
|
|
return Response.ok(auctions).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to get auctions", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/monitor/lots
|
|
* Returns list of active lots
|
|
*/
|
|
@GET
|
|
@Path("/lots")
|
|
public Response getActiveLots() {
|
|
try {
|
|
var lots = db.getActiveLots();
|
|
return Response.ok(lots).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to get lots", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/monitor/lots/closing-soon
|
|
* Returns lots closing within specified minutes (default 30)
|
|
*/
|
|
@GET
|
|
@Path("/lots/closing-soon")
|
|
public Response getLotsClosingSoon(@QueryParam("minutes") @DefaultValue("30") int minutes) {
|
|
try {
|
|
var allLots = db.getActiveLots();
|
|
var closingSoon = allLots.stream()
|
|
.filter(lot -> lot.closingTime() != null && lot.minutesUntilClose() < minutes)
|
|
.toList();
|
|
|
|
return Response.ok(closingSoon).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to get closing lots", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/monitor/lots/{lotId}/images
|
|
* Returns images for a specific lot
|
|
*/
|
|
@GET
|
|
@Path("/lots/{lotId}/images")
|
|
public Response getLotImages(@PathParam("lotId") int lotId) {
|
|
try {
|
|
var images = db.getImagesForLot(lotId);
|
|
return Response.ok(images).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to get lot images", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* POST /api/monitor/test-notification
|
|
* Send a test notification
|
|
*/
|
|
@POST
|
|
@Path("/test-notification")
|
|
public Response sendTestNotification(Map<String, String> request) {
|
|
try {
|
|
String message = request.getOrDefault("message", "Test notification from Auction Monitor");
|
|
String title = request.getOrDefault("title", "Test Notification");
|
|
int priority = Integer.parseInt(request.getOrDefault("priority", "0"));
|
|
|
|
notifier.sendNotification(message, title, priority);
|
|
|
|
return Response.ok(Map.of("message", "Test notification sent successfully")).build();
|
|
} catch (Exception e) {
|
|
LOG.error("Failed to send test notification", e);
|
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
.entity(Map.of("error", e.getMessage()))
|
|
.build();
|
|
}
|
|
}
|
|
}
|