Skip to content

Commit

Permalink
API to retrieve check-in log (#1188) (cherry-picked from 976f88a)
Browse files Browse the repository at this point in the history
  • Loading branch information
cbellone committed Feb 3, 2023
1 parent fc30659 commit e7a1fd9
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import alfio.manager.user.UserManager;
import alfio.model.*;
import alfio.model.ExtensionSupport.ExtensionMetadataValue;
import alfio.model.api.v1.admin.CheckInLogEntry;
import alfio.model.api.v1.admin.EventCreationRequest;
import alfio.model.api.v1.admin.LinkedSubscriptions;
import alfio.model.group.Group;
Expand Down Expand Up @@ -76,6 +77,7 @@ public class EventApiV1Controller {
private final ExtensionRepository extensionRepository;
private final ConfigurationManager configurationManager;
private final AdminJobManager adminJobManager;
private final CheckInManager checkInManager;

public EventApiV1Controller(EventManager eventManager,
EventNameManager eventNameManager,
Expand Down Expand Up @@ -223,6 +225,17 @@ public ResponseEntity<Boolean> generateTicketsForSubscribers(@PathVariable("slug
}));
}

@GetMapping("/{slug}/check-in-log")
public ResponseEntity<List<CheckInLogEntry>> checkInLog(@PathVariable("slug") String slug,
Principal user) {
try {
return ResponseEntity.ok(checkInManager.retrieveLogEntries(slug, user.getName()));
} catch (Exception ex) {
log.error("Error while loading check-in log entries", ex);
return ResponseEntity.internalServerError().build();
}
}

private LinkedSubscriptions retrieveLinkedSubscriptionsForEvent(String slug, int id, int organizationId) {
var subscriptionIds = eventManager.getLinkedSubscriptionIds(id, organizationId);
return new LinkedSubscriptions(slug, subscriptionIds);
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/alfio/manager/CheckInManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import alfio.manager.system.ConfigurationManager;
import alfio.model.*;
import alfio.model.Ticket.TicketStatus;
import alfio.model.api.v1.admin.CheckInLogEntry;
import alfio.model.audit.ScanAudit;
import alfio.model.checkin.AttendeeSearchResults;
import alfio.model.decorator.TicketPriceContainer;
Expand Down Expand Up @@ -565,6 +566,13 @@ public CheckInStatistics getStatistics(String eventName, String username) {
.orElse(null);
}

public List<CheckInLogEntry> retrieveLogEntries(String eventName, String username) {
return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName)
.filter(EventManager.checkOwnership(username, organizationRepository))
.map(event -> scanAuditRepository.loadEntries(event.getId()))
.orElse(List.of());
}

private boolean areStatsEnabled(EventAndOrganizationId event) {
return configurationManager.getFor(CHECK_IN_STATS, event.getConfigurationLevel()).getValueAsBooleanOrDefault();
}
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* 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.model.api.v1.admin;

import alfio.model.audit.ScanAudit;
import alfio.model.modification.AttendeeData;
import alfio.model.support.JSONData;
import alfio.util.Json;
import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column;
import com.fasterxml.jackson.core.type.TypeReference;

import java.util.List;

public class CheckInLogEntry {
private final String ticketId;
private final AttendeeData attendeeData;
private final List<ScanAudit> audit;

public CheckInLogEntry(@Column("t_uuid") String ticketId,
@Column("attendee_data") @JSONData AttendeeData attendeeData,
@Column("scans") String scansAsString) {
this.ticketId = ticketId;
this.attendeeData = attendeeData;
this.audit = Json.fromJson(scansAsString, new TypeReference<>() {});
}

public String getTicketId() {
return ticketId;
}

public AttendeeData getAttendeeData() {
return attendeeData;
}

public List<ScanAudit> getAudit() {
return audit;
}
}
20 changes: 13 additions & 7 deletions src/main/java/alfio/model/audit/ScanAudit.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,25 @@

import alfio.manager.support.CheckInStatus;
import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.ZonedDateTime;
import java.time.LocalDateTime;

public record ScanAudit(
@Column("ticket_uuid") String ticketUuid,
@Column("event_id_fk") int eventId,
@Column("scan_ts") ZonedDateTime scanTimestamp,
@Column("username") String username,
@Column("check_in_status") CheckInStatus checkInStatus,
@Column("operation") ScanAudit.Operation operation) {
@JsonProperty("ticketUuid") @Column("ticket_uuid") String ticketUuid,
@JsonProperty("scanTimestamp") @Column("scan_ts") LocalDateTime scanTimestamp,
@JsonProperty("username") @Column("username") String username,
@JsonProperty("checkInStatus") @Column("check_in_status") CheckInStatus checkInStatus,
@JsonProperty("operation") @Column("operation") ScanAudit.Operation operation) {

public enum Operation {
SCAN,
REVERT
}

@JsonIgnore
public String ticketUuid() {
return ticketUuid;
}
}
9 changes: 9 additions & 0 deletions src/main/java/alfio/repository/audit/ScanAuditRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package alfio.repository.audit;

import alfio.manager.support.CheckInStatus;
import alfio.model.api.v1.admin.CheckInLogEntry;
import alfio.model.audit.ScanAudit;
import ch.digitalfondue.npjt.Bind;
import ch.digitalfondue.npjt.Query;
Expand All @@ -38,4 +39,12 @@ Integer insert(@Bind("ticketUuid") String ticketUuid,
@Query("select * from scan_audit where event_id_fk = :eventId")
List<ScanAudit> findAllForEvent(@Bind("eventId") int eventId);

@Query("select t.uuid t_uuid, jsonb_build_object('firstName', t.first_name, 'lastName', t.last_name, 'email', t.email_address, 'metadata', coalesce(t.metadata::jsonb#>'{metadataMap, general, attributes}', '{}')) attendee_data, jsonb_agg(jsonb_build_object('ticketUuid', sa.ticket_uuid, 'scanTimestamp', sa.scan_ts, 'username', sa.username, 'checkInStatus', sa.check_in_status, 'operation', sa.operation)) scans from ticket t\n" +
" join event e on t.event_id = e.id" +
" join scan_audit sa on e.id = sa.event_id_fk and t.uuid = sa.ticket_uuid" +
" where e.id = :eventId" +
" and t.status = 'CHECKED_IN'" +
" group by 1,2")
List<CheckInLogEntry> loadEntries(@Bind("eventId") int eventId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -1067,15 +1067,15 @@ protected void testBasicFlow(Supplier<ReservationFlowContext> contextSupplier) t
assertEquals(CheckInStatus.OK_READY_TO_BE_CHECKED_IN, ticketAndCheckInResult.getResult().getStatus());
CheckInApiController.TicketCode tc = new CheckInApiController.TicketCode();
tc.setCode(ticketCode);
assertEquals(CheckInStatus.SUCCESS, checkInApiController.checkIn(context.event.getId(), ticketIdentifier, tc, new TestingAuthenticationToken("ciccio", "ciccio")).getResult().getStatus());
assertEquals(CheckInStatus.SUCCESS, checkInApiController.checkIn(context.event.getId(), ticketIdentifier, tc, new TestingAuthenticationToken(context.userId + "_api", "")).getResult().getStatus());
List<ScanAudit> audits = scanAuditRepository.findAllForEvent(context.event.getId());
assertFalse(audits.isEmpty());
assertTrue(audits.stream().anyMatch(sa -> sa.ticketUuid().equals(ticketIdentifier)));

extLogs = extensionLogRepository.getPage(null, null, null, 100, 0);
assertEventLogged(extLogs, TICKET_CHECKED_IN, 2);


validateCheckInData(context);

TicketAndCheckInResult ticketAndCheckInResultOk = checkInApiController.findTicketWithUUID(context.event.getId(), ticketIdentifier, ticketCode);
assertEquals(CheckInStatus.ALREADY_CHECK_IN, ticketAndCheckInResultOk.getResult().getStatus());
Expand Down Expand Up @@ -1265,6 +1265,10 @@ protected void testBasicFlow(Supplier<ReservationFlowContext> contextSupplier) t

}

protected void validateCheckInData(ReservationFlowContext context) {

}

protected void performAndValidatePayment(ReservationFlowContext context,
String reservationId,
int promoCodeId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
import java.util.List;

import static alfio.test.util.IntegrationTestUtil.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
@ContextConfiguration(classes = {DataSourceConfiguration.class, TestConfiguration.class, ControllerConfiguration.class})
Expand All @@ -71,6 +73,7 @@ class ReservationFlowIntegrationTest extends BaseReservationFlowTest {

private final OrganizationRepository organizationRepository;
private final UserManager userManager;
private final CheckInManager checkInManager;

@Autowired
public ReservationFlowIntegrationTest(OrganizationRepository organizationRepository,
Expand Down Expand Up @@ -109,7 +112,8 @@ public ReservationFlowIntegrationTest(OrganizationRepository organizationReposit
UserRepository userRepository,
OrganizationDeleter organizationDeleter,
PromoCodeDiscountRepository promoCodeDiscountRepository,
PromoCodeRequestManager promoCodeRequestManager) {
PromoCodeRequestManager promoCodeRequestManager,
CheckInManager checkInManager) {
super(configurationRepository,
eventManager,
eventRepository,
Expand Down Expand Up @@ -147,6 +151,7 @@ public ReservationFlowIntegrationTest(OrganizationRepository organizationReposit
promoCodeRequestManager);
this.organizationRepository = organizationRepository;
this.userManager = userManager;
this.checkInManager = checkInManager;
}

private ReservationFlowContext createContext() {
Expand Down Expand Up @@ -174,4 +179,16 @@ protected void performAdditionalTests(ReservationFlowContext context) {
var event = context.event;
BaseIntegrationTest.testTransferEventToAnotherOrg(event.getId(), event.getOrganizationId(), context.userId, jdbcTemplate);
}

@Override
protected void validateCheckInData(ReservationFlowContext context) {
var entries = checkInManager.retrieveLogEntries(context.event.getShortName(), context.userId);
assertEquals(1, entries.size());
var entry = entries.get(0);
assertNotNull(entry.getTicketId());
assertNotNull(entry.getAttendeeData());
assertNotNull(entry.getAttendeeData().getMetadata());
assertNotNull(entry.getAudit());
entry.getAudit().forEach(audit -> assertEquals(context.userId + "_api", audit.getUsername()));
}
}

0 comments on commit e7a1fd9

Please sign in to comment.