-
-
Notifications
You must be signed in to change notification settings - Fork 356
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#41 - move admin api controllers to a more appropriate package (api.a…
…dmin)
- Loading branch information
Showing
9 changed files
with
852 additions
and
2 deletions.
There are no files selected for viewing
158 changes: 158 additions & 0 deletions
158
src/main/java/alfio/controller/api/admin/CheckInApiController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/** | ||
* This file is part of alf.io. | ||
* | ||
* alf.io is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* alf.io is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with alf.io. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package alfio.controller.api.admin; | ||
|
||
import alfio.manager.CheckInManager; | ||
import alfio.model.Event; | ||
import alfio.model.Ticket; | ||
import alfio.model.Ticket.TicketStatus; | ||
import alfio.repository.EventRepository; | ||
import alfio.repository.TicketRepository; | ||
import lombok.Data; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import static alfio.util.OptionalWrapper.optionally; | ||
import static org.springframework.web.bind.annotation.RequestMethod.GET; | ||
import static org.springframework.web.bind.annotation.RequestMethod.POST; | ||
|
||
@RestController | ||
@RequestMapping("/admin/api") | ||
public class CheckInApiController { | ||
|
||
private final TicketRepository ticketRepository; | ||
private final EventRepository eventRepository; | ||
private final CheckInManager checkInManager; | ||
|
||
@Data | ||
public static class TicketCode { | ||
private String code; | ||
} | ||
|
||
public enum CheckInStatus { | ||
EVENT_NOT_FOUND, TICKET_NOT_FOUND, EMPTY_TICKET_CODE, INVALID_TICKET_CODE, INVALID_TICKET_STATE, ALREADY_CHECK_IN, MUST_PAY, SUCCESS | ||
} | ||
|
||
@Data | ||
public static class CheckInResult { | ||
private final CheckInStatus status; | ||
private final String message; | ||
} | ||
|
||
@Data | ||
public static class OnSitePaymentConfirmation { | ||
private final boolean status; | ||
private final String message; | ||
} | ||
|
||
@Autowired | ||
public CheckInApiController(EventRepository eventRepository, TicketRepository ticketRepository, CheckInManager checkInManager) { | ||
this.eventRepository = eventRepository; | ||
this.ticketRepository = ticketRepository; | ||
this.checkInManager = checkInManager; | ||
} | ||
|
||
@RequestMapping(value = "/check-in/{eventId}/ticket/{ticketIdentifier}", method = GET) | ||
public Ticket findTicketWithUUID(@PathVariable("eventId") int eventId, @PathVariable("ticketIdentifier") String ticketIdentifier) { | ||
Optional<Event> event = optionally(() -> eventRepository.findById(eventId)); | ||
Optional<Ticket> ticket = optionally(() -> ticketRepository.findByUUID(ticketIdentifier)); | ||
|
||
if(event.isPresent() && ticket.isPresent()) { | ||
return ticket.get(); | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
@RequestMapping(value = "/check-in/{eventId}/ticket/{ticketIdentifier}", method = POST) | ||
public CheckInResult checkIn(@PathVariable("eventId") int eventId, @PathVariable("ticketIdentifier") String ticketIdentifier, @RequestBody TicketCode ticketCode) { | ||
|
||
Optional<Event> event = optionally(() -> eventRepository.findById(eventId)); | ||
|
||
if (!event.isPresent()) { | ||
return new CheckInResult(CheckInStatus.EVENT_NOT_FOUND, "Event with id " + eventId + " not found"); | ||
} | ||
|
||
Optional<Ticket> ticket = optionally(() -> ticketRepository.findByUUID(ticketIdentifier)); | ||
|
||
if (!ticket.isPresent()) { | ||
return new CheckInResult(CheckInStatus.TICKET_NOT_FOUND, "Ticket with uuid " + ticketIdentifier + " not found"); | ||
} | ||
|
||
if(ticketCode == null || StringUtils.isEmpty(ticketCode.getCode())) { | ||
return new CheckInResult(CheckInStatus.EMPTY_TICKET_CODE, "Missing ticket code"); | ||
} | ||
|
||
return handleCheckIn(event.get(), ticket.get(), ticketCode.getCode()); | ||
} | ||
|
||
|
||
private CheckInResult handleCheckIn(Event event, Ticket ticket, String ticketCode) { | ||
|
||
if (!ticketCode.equals(ticket.ticketCode(event.getPrivateKey()))) { | ||
return new CheckInResult(CheckInStatus.INVALID_TICKET_CODE, "Ticket qr code does not match"); | ||
} | ||
|
||
final TicketStatus ticketStatus = ticket.getStatus(); | ||
|
||
if (ticketStatus == TicketStatus.TO_BE_PAID) { | ||
return new CheckInResult(CheckInStatus.MUST_PAY, "Must pay for ticket"); //TODO: must say how much | ||
} | ||
|
||
if (ticketStatus == TicketStatus.CHECKED_IN) { | ||
return new CheckInResult(CheckInStatus.ALREADY_CHECK_IN, "Error: already checked in"); | ||
} | ||
|
||
if (ticket.getStatus() != TicketStatus.ACQUIRED) { | ||
return new CheckInResult(CheckInStatus.INVALID_TICKET_STATE, "Invalid ticket state, expected ACQUIRED state, received " + ticket.getStatus()); | ||
} | ||
|
||
checkInManager.checkIn(ticket.getUuid()); | ||
return new CheckInResult(CheckInStatus.SUCCESS, "success"); | ||
} | ||
|
||
@RequestMapping(value = "/check-in/{eventId}/ticket/{ticketIdentifier}/confirm-on-site-payment", method = POST) | ||
public OnSitePaymentConfirmation confirmOnSitePayment(@PathVariable("eventId") int eventId, @PathVariable("ticketIdentifier") String ticketIdentifier) { | ||
|
||
Optional<Ticket> ticket = optionally(() -> ticketRepository.findByUUID(ticketIdentifier)); | ||
|
||
if (!ticket.isPresent()) { | ||
return new OnSitePaymentConfirmation(false, "Ticket with uuid " + ticketIdentifier + " not found"); | ||
} | ||
|
||
Ticket t = ticket.get(); | ||
|
||
if (t.getStatus() != TicketStatus.TO_BE_PAID) { | ||
return new OnSitePaymentConfirmation(false, "Invalid ticket state, expected TO_BE_PAID state, received " + t.getStatus()); | ||
} | ||
|
||
checkInManager.acquire(t.getUuid()); | ||
return new OnSitePaymentConfirmation(true, "ok"); | ||
} | ||
|
||
@RequestMapping(value = "/check-in/{eventId}/ticket", method = GET) | ||
public List<Ticket> listAllTickets(@PathVariable("eventId") int eventId) { | ||
return ticketRepository.findAllByEventId(eventId); | ||
} | ||
} |
178 changes: 178 additions & 0 deletions
178
src/main/java/alfio/controller/api/admin/EventApiController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
/** | ||
* This file is part of alf.io. | ||
* | ||
* alf.io is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* alf.io is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with alf.io. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package alfio.controller.api.admin; | ||
|
||
import alfio.manager.EventManager; | ||
import alfio.manager.support.OrderSummary; | ||
import alfio.model.TicketReservation; | ||
import alfio.model.modification.EventModification; | ||
import alfio.model.modification.EventWithStatistics; | ||
import alfio.model.modification.TicketAllocationModification; | ||
import alfio.model.modification.TicketCategoryModification; | ||
import alfio.model.transaction.PaymentProxy; | ||
import alfio.util.ValidationResult; | ||
import alfio.util.Validator; | ||
import com.opencsv.CSVReader; | ||
import lombok.extern.log4j.Log4j2; | ||
import org.apache.commons.lang3.Validate; | ||
import org.apache.commons.lang3.tuple.Triple; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.validation.Errors; | ||
import org.springframework.web.bind.annotation.*; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.math.BigDecimal; | ||
import java.security.Principal; | ||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.springframework.web.bind.annotation.RequestMethod.*; | ||
|
||
@RestController | ||
@RequestMapping("/admin/api") | ||
@Log4j2 | ||
public class EventApiController { | ||
|
||
private static final String OK = "OK"; | ||
private final EventManager eventManager; | ||
|
||
@Autowired | ||
public EventApiController(EventManager eventManager) { | ||
this.eventManager = eventManager; | ||
} | ||
|
||
@ExceptionHandler(Exception.class) | ||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) | ||
public String unhandledException(Exception e) { | ||
if(!IllegalArgumentException.class.isInstance(e)) { | ||
log.warn("unhandled exception", e); | ||
} | ||
return e.getMessage(); | ||
} | ||
|
||
|
||
@RequestMapping(value = "/paymentProxies", method = GET) | ||
@ResponseStatus(HttpStatus.OK) | ||
public List<PaymentProxy> getPaymentProxies() { | ||
return Arrays.asList(PaymentProxy.values()); | ||
} | ||
|
||
@RequestMapping(value = "/events", method = GET) | ||
public List<EventWithStatistics> getAllEvents(Principal principal) { | ||
return eventManager.getAllEventsWithStatistics(principal.getName()); | ||
} | ||
|
||
@RequestMapping(value = "/events/{name}", method = GET) | ||
public Map<String, Object> getSingleEvent(@PathVariable("name") String eventName, Principal principal) { | ||
Map<String, Object> out = new HashMap<>(); | ||
final String username = principal.getName(); | ||
final EventWithStatistics event = eventManager.getSingleEventWithStatistics(eventName, username); | ||
out.put("event", event); | ||
out.put("organization", eventManager.loadOrganizer(event.getEvent(), username)); | ||
return out; | ||
} | ||
|
||
@RequestMapping(value = "/events/check", method = POST) | ||
public ValidationResult validateEvent(@RequestBody EventModification eventModification) { | ||
return ValidationResult.success(); | ||
} | ||
|
||
@RequestMapping(value = "/events/new", method = POST) | ||
public String insertEvent(@RequestBody EventModification eventModification) { | ||
eventManager.createEvent(eventModification); | ||
return OK; | ||
} | ||
|
||
@RequestMapping(value = "/events/{id}/header/update", method = POST) | ||
public ValidationResult updateHeader(@PathVariable("id") int id, @RequestBody EventModification eventModification, Errors errors, Principal principal) { | ||
return Validator.validateEventHeader(eventModification, errors).ifSuccess(() -> eventManager.updateEventHeader(id, eventModification, principal.getName())); | ||
} | ||
|
||
@RequestMapping(value = "/events/{id}/prices/update", method = POST) | ||
public ValidationResult updatePrices(@PathVariable("id") int id, @RequestBody EventModification eventModification, Errors errors, Principal principal) { | ||
return Validator.validateEventPrices(eventModification, errors).ifSuccess(() -> eventManager.updateEventPrices(id, eventModification, principal.getName())); | ||
} | ||
|
||
@RequestMapping(value = "/events/{eventId}/categories/{categoryId}/update", method = POST) | ||
public ValidationResult updateExistingCategory(@PathVariable("eventId") int eventId, @PathVariable("categoryId") int categoryId, @RequestBody TicketCategoryModification category, Errors errors, Principal principal) { | ||
return Validator.validateCategory(category, errors).ifSuccess(() -> eventManager.updateCategory(categoryId, eventId, category, principal.getName())); | ||
} | ||
|
||
@RequestMapping(value = "/events/{eventId}/categories/new", method = POST) | ||
public ValidationResult createCategory(@PathVariable("eventId") int eventId, @RequestBody TicketCategoryModification category, Errors errors, Principal principal) { | ||
return Validator.validateCategory(category, errors).ifSuccess(() -> eventManager.insertCategory(eventId, category, principal.getName())); | ||
} | ||
|
||
@RequestMapping(value = "/events/reallocate", method = PUT) | ||
public String reallocateTickets(@RequestBody TicketAllocationModification form) { | ||
eventManager.reallocateTickets(form.getSrcCategoryId(), form.getTargetCategoryId(), form.getEventId()); | ||
return OK; | ||
} | ||
|
||
@RequestMapping(value = "/events/{eventName}/pending-payments") | ||
public List<SerializablePair<TicketReservation, OrderSummary>> getPendingPayments(@PathVariable("eventName") String eventName, Principal principal) { | ||
return eventManager.getPendingPayments(eventName, principal.getName()).stream().map(SerializablePair::fromPair).collect(Collectors.toList()); | ||
} | ||
|
||
@RequestMapping(value = "/events/{eventName}/pending-payments/{reservationId}/confirm", method = POST) | ||
public String confirmPayment(@PathVariable("eventName") String eventName, @PathVariable("reservationId") String reservationId, Principal principal) { | ||
eventManager.confirmPayment(eventName, reservationId, principal.getName()); | ||
return OK; | ||
} | ||
|
||
@RequestMapping(value = "/events/{eventName}/pending-payments/{reservationId}", method = DELETE) | ||
public String deletePendingPayment(@PathVariable("eventName") String eventName, @PathVariable("reservationId") String reservationId, Principal principal) { | ||
eventManager.deletePendingOfflinePayment(eventName, reservationId, principal.getName()); | ||
return OK; | ||
} | ||
|
||
@RequestMapping(value = "/events/{eventName}/pending-payments/bulk-confirmation", method = POST) | ||
public List<Triple<Boolean, String, String>> bulkConfirmation(@PathVariable("eventName") String eventName, | ||
Principal principal, | ||
@RequestParam("file") MultipartFile file) throws IOException { | ||
|
||
try(InputStreamReader isr = new InputStreamReader(file.getInputStream())) { | ||
CSVReader reader = new CSVReader(isr); | ||
String username = principal.getName(); | ||
return reader.readAll().stream() | ||
.map(line -> { | ||
String reservationID = null; | ||
try { | ||
Validate.isTrue(line.length >= 2); | ||
reservationID = line[0]; | ||
eventManager.confirmPayment(eventName, reservationID, new BigDecimal(line[1]), username); | ||
return Triple.of(Boolean.TRUE, reservationID, ""); | ||
} catch (Exception e) { | ||
return Triple.of(Boolean.FALSE, Optional.ofNullable(reservationID).orElse(""), e.getMessage()); | ||
} | ||
}) | ||
.collect(Collectors.toList()); | ||
} | ||
} | ||
|
||
@RequestMapping(value = "/events/{eventName}/categories/{categoryId}/tickets/{ticketId}/toggle-locking", method = PUT) | ||
public boolean toggleTicketLocking(@PathVariable("eventName") String eventName, | ||
@PathVariable("categoryId") int categoryId, | ||
@PathVariable("ticketId") int ticketId, | ||
Principal principal) { | ||
return eventManager.toggleTicketLocking(eventName, categoryId, ticketId, principal.getName()); | ||
} | ||
|
||
} |
Oops, something went wrong.