SEBSERV-191 backend implementation
This commit is contained in:
parent
458cc9486e
commit
2f2a3670b7
9 changed files with 532 additions and 29 deletions
|
@ -68,6 +68,10 @@ public class ClientEvent implements Entity, IndicatorValueHolder {
|
|||
}
|
||||
}
|
||||
|
||||
public enum ExportType {
|
||||
CSV
|
||||
}
|
||||
|
||||
@JsonProperty(Domain.CLIENT_EVENT.ATTR_ID)
|
||||
public final Long id;
|
||||
|
||||
|
|
|
@ -77,6 +77,30 @@ public interface PaginationService {
|
|||
final String tableName,
|
||||
final Supplier<Result<Collection<T>>> delegate);
|
||||
|
||||
/** Fetches a paged batch of objects
|
||||
*
|
||||
* NOTE: Paging always depends on SQL level. It depends on the collection given by the SQL select statement
|
||||
* that is executed within MyBatis by using the MyBatis page service.
|
||||
* Be aware that if the delegate that is given here applies an additional filter to the filtering done
|
||||
* on SQL level, this will lead to paging with not fully filled pages or even to empty pages if the filter
|
||||
* filters a lot of the entries given by the SQL statement away.
|
||||
* So we recommend to apply as much of the filtering as possible on the SQL level and only if necessary and
|
||||
* not avoidable, apply a additional filter on software-level that eventually filter one or two entities
|
||||
* for a page.
|
||||
*
|
||||
* @param pageNumber the current page number
|
||||
* @param pageSize the (full) size of the page
|
||||
* @param sort the name of the sort column with a leading '-' for descending sort order
|
||||
* @param tableName the name of the SQL table on which the pagination is applying to
|
||||
* @param delegate a collection supplier the does the underling SQL query with specified pagination attributes
|
||||
* @return Result refers to a Collection of specified type of objects or to an exception on error case */
|
||||
<T> Result<Collection<T>> fetch(
|
||||
final int pageNumber,
|
||||
final int pageSize,
|
||||
final String sort,
|
||||
final String tableName,
|
||||
final Supplier<Result<Collection<T>>> delegate);
|
||||
|
||||
/** Use this to build a current Page from a given list of objects.
|
||||
*
|
||||
* @param <T> the Type if list entities
|
||||
|
|
|
@ -147,6 +147,20 @@ public class PaginationServiceImpl implements PaginationService {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Result<Collection<T>> fetch(
|
||||
final int pageNumber,
|
||||
final int pageSize,
|
||||
final String sort,
|
||||
final String tableName,
|
||||
final Supplier<Result<Collection<T>>> delegate) {
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
setPagination(pageNumber, pageSize, sort, tableName);
|
||||
return delegate.get().getOrThrow();
|
||||
});
|
||||
}
|
||||
|
||||
private String verifySortColumnName(final String sort, final String columnName) {
|
||||
|
||||
if (StringUtils.isBlank(sort)) {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.exam;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.ExportType;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
|
||||
public interface SEBClientEventAdminService {
|
||||
|
||||
Result<EntityProcessingReport> deleteAllClientEvents(Collection<String> ids);
|
||||
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
void exportSEBClientLogs(
|
||||
OutputStream output,
|
||||
FilterMap filterMap,
|
||||
String sort,
|
||||
final Predicate<ClientEvent> predicate,
|
||||
ExportType exportType,
|
||||
boolean includeConnectionDetails,
|
||||
boolean includeExamDetails);
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.exam;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.ExportType;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||
|
||||
public interface SEBClientEventExporter {
|
||||
|
||||
ExportType exportType();
|
||||
|
||||
void streamHeader(
|
||||
OutputStream output,
|
||||
boolean includeConnectionDetails,
|
||||
boolean includeExamDetails);
|
||||
|
||||
void streamData(
|
||||
OutputStream output,
|
||||
ClientEventRecord eventData,
|
||||
ClientConnectionRecord connectionData,
|
||||
Exam examData);
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.exam.impl;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.ExportType;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.SEBClientEventAdminService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.SEBClientEventExporter;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@WebServiceProfile
|
||||
public class SEBClientEventAdminServiceImpl implements SEBClientEventAdminService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SEBClientEventAdminServiceImpl.class);
|
||||
|
||||
private final PaginationService paginationService;
|
||||
private final ClientEventDAO clientEventDAO;
|
||||
private final SEBClientEventExportTransactionHandler sebClientEventExportTransactionHandler;
|
||||
private final EnumMap<ExportType, SEBClientEventExporter> exporter;
|
||||
|
||||
public SEBClientEventAdminServiceImpl(
|
||||
final PaginationService paginationService,
|
||||
final ClientEventDAO clientEventDAO,
|
||||
final SEBClientEventExportTransactionHandler sebClientEventExportTransactionHandler,
|
||||
final Collection<SEBClientEventExporter> exporter) {
|
||||
|
||||
this.paginationService = paginationService;
|
||||
this.clientEventDAO = clientEventDAO;
|
||||
this.sebClientEventExportTransactionHandler = sebClientEventExportTransactionHandler;
|
||||
|
||||
this.exporter = new EnumMap<>(ExportType.class);
|
||||
exporter.forEach(exp -> this.exporter.putIfAbsent(exp.exportType(), exp));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<EntityProcessingReport> deleteAllClientEvents(final Collection<String> ids) {
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return EntityProcessingReport.ofEmptyError();
|
||||
}
|
||||
|
||||
final Set<EntityKey> sources = ids.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.CLIENT_EVENT))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final Result<Collection<EntityKey>> delete = this.clientEventDAO.delete(sources);
|
||||
if (delete.hasError()) {
|
||||
return new EntityProcessingReport(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.UNEXPECTED.of(delete.getError()))));
|
||||
} else {
|
||||
return new EntityProcessingReport(
|
||||
sources,
|
||||
delete.get(),
|
||||
Collections.emptyList());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportSEBClientLogs(
|
||||
final OutputStream output,
|
||||
final FilterMap filterMap,
|
||||
final String sort,
|
||||
final Predicate<ClientEvent> predicate,
|
||||
final ExportType exportType,
|
||||
final boolean includeConnectionDetails,
|
||||
final boolean includeExamDetails) {
|
||||
|
||||
new exportRunner(
|
||||
this.exporter.get(exportType),
|
||||
includeConnectionDetails,
|
||||
includeExamDetails,
|
||||
new Pager(filterMap, sort, predicate),
|
||||
output)
|
||||
.run();
|
||||
|
||||
}
|
||||
|
||||
private class exportRunner {
|
||||
|
||||
private final SEBClientEventExporter exporter;
|
||||
private final boolean includeConnectionDetails;
|
||||
private final boolean includeExamDetails;
|
||||
private final Iterator<Collection<ClientEventRecord>> pager;
|
||||
private final OutputStream output;
|
||||
|
||||
private final Map<Long, Exam> examCache;
|
||||
private final Map<Long, ClientConnectionRecord> connectionCache;
|
||||
|
||||
public exportRunner(
|
||||
final SEBClientEventExporter exporter,
|
||||
final boolean includeConnectionDetails,
|
||||
final boolean includeExamDetails,
|
||||
final Iterator<Collection<ClientEventRecord>> pager,
|
||||
final OutputStream output) {
|
||||
|
||||
this.exporter = exporter;
|
||||
this.includeConnectionDetails = includeConnectionDetails;
|
||||
this.includeExamDetails = includeExamDetails;
|
||||
this.pager = pager;
|
||||
this.output = output;
|
||||
|
||||
this.connectionCache = includeConnectionDetails ? new HashMap<>() : null;
|
||||
this.examCache = includeExamDetails ? new HashMap<>() : null;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
// first stream header line
|
||||
this.exporter.streamHeader(this.output, this.includeConnectionDetails, this.includeExamDetails);
|
||||
|
||||
// then batch with the pager and stream line per line
|
||||
while (this.pager.hasNext()) {
|
||||
this.pager.next().forEach(rec -> {
|
||||
this.exporter.streamData(
|
||||
this.output,
|
||||
rec,
|
||||
this.includeConnectionDetails ? getConnection(rec.getClientConnectionId()) : null,
|
||||
this.includeExamDetails ? getExam(rec.getClientConnectionId()) : null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private ClientConnectionRecord getConnection(final Long connectionId) {
|
||||
if (!this.connectionCache.containsKey(connectionId)) {
|
||||
SEBClientEventAdminServiceImpl.this.sebClientEventExportTransactionHandler
|
||||
.clientConnectionById(connectionId)
|
||||
.map(e -> this.connectionCache.put(connectionId, e))
|
||||
.onError(error -> log.error("Failed to get ClientConnectionRecord for id: {}",
|
||||
connectionId,
|
||||
error));
|
||||
}
|
||||
|
||||
return this.connectionCache.get(connectionId);
|
||||
}
|
||||
|
||||
private Exam getExam(final Long connectionId) {
|
||||
final ClientConnectionRecord connection = getConnection(connectionId);
|
||||
final Long examId = connection.getExamId();
|
||||
if (!this.examCache.containsKey(examId)) {
|
||||
SEBClientEventAdminServiceImpl.this.sebClientEventExportTransactionHandler
|
||||
.examById(examId)
|
||||
.map(e -> this.examCache.put(examId, e))
|
||||
.onError(error -> log.error("Failed to get Exam for id: {}",
|
||||
examId,
|
||||
error));
|
||||
}
|
||||
|
||||
return this.examCache.get(examId);
|
||||
}
|
||||
}
|
||||
|
||||
private class Pager implements Iterator<Collection<ClientEventRecord>> {
|
||||
|
||||
private final FilterMap filterMap;
|
||||
private final String sort;
|
||||
private final Predicate<ClientEvent> predicate;
|
||||
|
||||
private int pageNumber = 0;
|
||||
private final int pageSize = 100;
|
||||
|
||||
private Collection<ClientEventRecord> nextRecords;
|
||||
|
||||
public Pager(
|
||||
final FilterMap filterMap,
|
||||
final String sort,
|
||||
final Predicate<ClientEvent> predicate) {
|
||||
|
||||
this.filterMap = filterMap;
|
||||
this.sort = sort;
|
||||
this.predicate = predicate;
|
||||
|
||||
fetchNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.nextRecords != null && !this.nextRecords.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClientEventRecord> next() {
|
||||
final Collection<ClientEventRecord> result = this.nextRecords;
|
||||
fetchNext();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fetchNext() {
|
||||
try {
|
||||
|
||||
this.nextRecords = SEBClientEventAdminServiceImpl.this.paginationService.fetch(
|
||||
this.pageNumber,
|
||||
this.pageSize,
|
||||
this.sort,
|
||||
ClientEventRecordDynamicSqlSupport.clientEventRecord.name(),
|
||||
() -> SEBClientEventAdminServiceImpl.this.sebClientEventExportTransactionHandler
|
||||
.allMatching(this.filterMap, this.predicate))
|
||||
.getOrThrow();
|
||||
|
||||
this.pageNumber++;
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to fetch next batch: ", e);
|
||||
this.nextRecords = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.exam.impl;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.ExportType;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.SEBClientEventExporter;
|
||||
|
||||
public class SEBClientEventCSVExporter implements SEBClientEventExporter {
|
||||
|
||||
@Override
|
||||
public ExportType exportType() {
|
||||
return ExportType.CSV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamHeader(
|
||||
final OutputStream output,
|
||||
final boolean includeConnectionDetails,
|
||||
final boolean includeExamDetails) {
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamData(
|
||||
final OutputStream output,
|
||||
final ClientEventRecord eventData,
|
||||
final ClientConnectionRecord connectionData,
|
||||
final Exam examData) {
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
private String toCSVString(final String text) {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.exam.impl;
|
||||
|
||||
import static org.mybatis.dynamic.sql.SqlBuilder.equalTo;
|
||||
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlBuilder;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@WebServiceProfile
|
||||
public class SEBClientEventExportTransactionHandler {
|
||||
|
||||
private final ClientEventRecordMapper clientEventRecordMapper;
|
||||
private final ClientConnectionRecordMapper clientConnectionRecordMapper;
|
||||
private final ExamDAO examDAO;
|
||||
|
||||
public SEBClientEventExportTransactionHandler(
|
||||
final ClientEventRecordMapper clientEventRecordMapper,
|
||||
final ClientConnectionRecordMapper clientConnectionRecordMapper,
|
||||
final ExamDAO examDAO) {
|
||||
|
||||
this.clientEventRecordMapper = clientEventRecordMapper;
|
||||
this.clientConnectionRecordMapper = clientConnectionRecordMapper;
|
||||
this.examDAO = examDAO;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Result<Collection<ClientEventRecord>> allMatching(
|
||||
final FilterMap filterMap,
|
||||
final Predicate<ClientEvent> predicate) {
|
||||
|
||||
return Result.tryCatch(() -> this.clientEventRecordMapper
|
||||
.selectByExample()
|
||||
.leftJoin(ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord)
|
||||
.on(
|
||||
ClientConnectionRecordDynamicSqlSupport.id,
|
||||
equalTo(ClientEventRecordDynamicSqlSupport.clientConnectionId))
|
||||
.where(
|
||||
ClientConnectionRecordDynamicSqlSupport.institutionId,
|
||||
isEqualToWhenPresent(filterMap.getInstitutionId()))
|
||||
.and(
|
||||
ClientConnectionRecordDynamicSqlSupport.examId,
|
||||
isEqualToWhenPresent(filterMap.getClientEventExamId()))
|
||||
.and(
|
||||
ClientConnectionRecordDynamicSqlSupport.examUserSessionId,
|
||||
SqlBuilder.isLikeWhenPresent(filterMap.getSQLWildcard(ClientConnection.FILTER_ATTR_SESSION_ID)))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.clientConnectionId,
|
||||
isEqualToWhenPresent(filterMap.getClientEventConnectionId()))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.type,
|
||||
isEqualToWhenPresent(filterMap.getClientEventTypeId()))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.type,
|
||||
SqlBuilder.isNotEqualTo(EventType.LAST_PING.id))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.clientTime,
|
||||
SqlBuilder.isGreaterThanOrEqualToWhenPresent(filterMap.getClientEventClientTimeFrom()))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.clientTime,
|
||||
SqlBuilder.isLessThanOrEqualToWhenPresent(filterMap.getClientEventClientTimeTo()))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.serverTime,
|
||||
SqlBuilder.isGreaterThanOrEqualToWhenPresent(filterMap.getClientEventServerTimeFrom()))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.serverTime,
|
||||
SqlBuilder.isLessThanOrEqualToWhenPresent(filterMap.getClientEventServerTimeTo()))
|
||||
.and(
|
||||
ClientEventRecordDynamicSqlSupport.text,
|
||||
SqlBuilder.isLikeWhenPresent(filterMap.getClientEventText()))
|
||||
.build()
|
||||
.execute());
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Result<ClientConnectionRecord> clientConnectionById(final Long id) {
|
||||
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectByPrimaryKey(id));
|
||||
}
|
||||
|
||||
public Result<Exam> examById(final Long id) {
|
||||
return this.examDAO.byPK(id);
|
||||
}
|
||||
|
||||
}
|
|
@ -8,13 +8,9 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
@ -28,13 +24,10 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry;
|
||||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||
|
@ -53,6 +46,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.SEBClientEventAdminService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
||||
|
||||
@WebServiceProfile
|
||||
|
@ -62,6 +56,7 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
|
|||
|
||||
private final ExamDAO examDao;
|
||||
private final ClientEventDAO clientEventDAO;
|
||||
private final SEBClientEventAdminService sebClientEventAdminService;
|
||||
|
||||
protected ClientEventController(
|
||||
final AuthorizationService authorization,
|
||||
|
@ -70,7 +65,8 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
|
|||
final UserActivityLogDAO userActivityLogDAO,
|
||||
final PaginationService paginationService,
|
||||
final BeanValidationService beanValidationService,
|
||||
final ExamDAO examDao) {
|
||||
final ExamDAO examDao,
|
||||
final SEBClientEventAdminService sebClientEventAdminService) {
|
||||
|
||||
super(authorization,
|
||||
bulkActionService,
|
||||
|
@ -81,6 +77,7 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
|
|||
|
||||
this.examDao = examDao;
|
||||
this.clientEventDAO = entityDAO;
|
||||
this.sebClientEventAdminService = sebClientEventAdminService;
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
|
@ -136,27 +133,9 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
|
|||
|
||||
this.checkWritePrivilege(institutionId);
|
||||
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return EntityProcessingReport.ofEmptyError();
|
||||
}
|
||||
|
||||
final Set<EntityKey> sources = ids.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.CLIENT_EVENT))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final Result<Collection<EntityKey>> delete = this.clientEventDAO.delete(sources);
|
||||
|
||||
if (delete.hasError()) {
|
||||
return new EntityProcessingReport(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.UNEXPECTED.of(delete.getError()))));
|
||||
} else {
|
||||
return new EntityProcessingReport(
|
||||
sources,
|
||||
delete.get(),
|
||||
Collections.emptyList());
|
||||
}
|
||||
return this.sebClientEventAdminService
|
||||
.deleteAllClientEvents(ids)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue