SEBSERV-14 #added pagination to user activity log API
This commit is contained in:
parent
83b3d190bb
commit
20a9f8e705
4 changed files with 197 additions and 65 deletions
|
@ -23,7 +23,7 @@ public final class Page<T> {
|
|||
}
|
||||
|
||||
public static final String ATTR_NUMBER_OF_PAGES = "numberOfPages";
|
||||
public static final String ATTR_PAGE_NUMBER = "pageNum";
|
||||
public static final String ATTR_PAGE_NUMBER = "pageNumber";
|
||||
public static final String ATTR_PAGE_SIZE = "pageSize";
|
||||
public static final String ATTR_SORT_BY = "sortBy";
|
||||
public static final String ATTR_SORT_ORDER = "sortOrder";
|
||||
|
|
|
@ -9,20 +9,22 @@
|
|||
package ch.ethz.seb.sebserver.webservice.servicelayer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mybatis.dynamic.sql.SqlColumn;
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport.UserRecord;
|
||||
|
||||
@Service
|
||||
public class PaginationService {
|
||||
|
@ -30,12 +32,16 @@ public class PaginationService {
|
|||
private final int defaultPageSize;
|
||||
private final int maxPageSize;
|
||||
|
||||
private final Map<String, Map<String, String>> sortColumnMapping;
|
||||
|
||||
public PaginationService(
|
||||
@Value("${sebserver.webservice.api.pagination.defaultPageSize:10}") final int defaultPageSize,
|
||||
@Value("${sebserver.webservice.api.pagination.maxPageSize:500}") final int maxPageSize) {
|
||||
|
||||
this.defaultPageSize = defaultPageSize;
|
||||
this.maxPageSize = maxPageSize;
|
||||
this.sortColumnMapping = new HashMap<>();
|
||||
initSortColumnMapping();
|
||||
}
|
||||
|
||||
public void setOnePageLimit(final SqlTable table) {
|
||||
|
@ -70,12 +76,12 @@ public class PaginationService {
|
|||
final com.github.pagehelper.Page<Object> startPage =
|
||||
PageHelper.startPage(_pageNumber, _pageSize, true, true, false);
|
||||
|
||||
final SqlColumn<?> sortColumn = verifySortColumn(sortBy, table);
|
||||
if (sortColumn != null) {
|
||||
final String sortColumnName = verifySortColumnName(sortBy, table);
|
||||
if (StringUtils.isNoneBlank(sortColumnName)) {
|
||||
if (sortOrder == Page.SortOrder.DESCENDING) {
|
||||
PageHelper.orderBy(sortColumn.name() + " DESC");
|
||||
PageHelper.orderBy(sortColumnName + " DESC");
|
||||
} else {
|
||||
PageHelper.orderBy(sortColumn.name());
|
||||
PageHelper.orderBy(sortColumnName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,33 +101,51 @@ public class PaginationService {
|
|||
return new Page<>(page.getPages(), pageNumber, sortBy, sortOrder, pageList);
|
||||
}
|
||||
|
||||
private SqlColumn<?> verifySortColumn(final String sortBy, final SqlTable table) {
|
||||
if (table == UserRecordDynamicSqlSupport.userRecord) {
|
||||
return verifySortColumn(sortBy, UserRecordDynamicSqlSupport.userRecord);
|
||||
private String verifySortColumnName(final String sortBy, final SqlTable table) {
|
||||
|
||||
if (StringUtils.isBlank(sortBy)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String, String> mapping = this.sortColumnMapping.get(table.name());
|
||||
if (mapping != null) {
|
||||
return mapping.get(sortBy);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private SqlColumn<?> verifySortColumn(final String sortBy, final UserRecord table) {
|
||||
// TODO is it possible to generate this within MyBatis generator?
|
||||
private void initSortColumnMapping() {
|
||||
// User Table
|
||||
final Map<String, String> userTableMap = new HashMap<>();
|
||||
userTableMap.put(Domain.USER.ATTR_NAME, UserRecordDynamicSqlSupport.name.name());
|
||||
userTableMap.put(Domain.USER.ATTR_USERNAME, UserRecordDynamicSqlSupport.username.name());
|
||||
userTableMap.put(Domain.USER.ATTR_EMAIL, UserRecordDynamicSqlSupport.email.name());
|
||||
userTableMap.put(Domain.USER.ATTR_LOCALE, UserRecordDynamicSqlSupport.locale.name());
|
||||
this.sortColumnMapping.put(UserRecordDynamicSqlSupport.userRecord.name(), userTableMap);
|
||||
|
||||
if (StringUtils.isBlank(sortBy)) {
|
||||
return UserRecordDynamicSqlSupport.id;
|
||||
}
|
||||
// User Activity Log Table
|
||||
final Map<String, String> userActivityLogTableMap = new HashMap<>();
|
||||
userActivityLogTableMap.put(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_USER_UUID,
|
||||
UserActivityLogRecordDynamicSqlSupport.userUuid.name());
|
||||
userActivityLogTableMap.put(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE,
|
||||
UserActivityLogRecordDynamicSqlSupport.activityType.name());
|
||||
userActivityLogTableMap.put(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID,
|
||||
UserActivityLogRecordDynamicSqlSupport.entityId.name());
|
||||
userActivityLogTableMap.put(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_TYPE,
|
||||
UserActivityLogRecordDynamicSqlSupport.entityType.name());
|
||||
userActivityLogTableMap.put(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP,
|
||||
UserActivityLogRecordDynamicSqlSupport.timestamp.name());
|
||||
this.sortColumnMapping.put(
|
||||
UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord.name(),
|
||||
userActivityLogTableMap);
|
||||
|
||||
if (sortBy.equals(UserRecordDynamicSqlSupport.name.name())) {
|
||||
return UserRecordDynamicSqlSupport.name;
|
||||
}
|
||||
|
||||
if (sortBy.equals(UserRecordDynamicSqlSupport.username.name())) {
|
||||
return UserRecordDynamicSqlSupport.username;
|
||||
}
|
||||
|
||||
if (sortBy.equals(UserRecordDynamicSqlSupport.email.name())) {
|
||||
return UserRecordDynamicSqlSupport.email;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -24,8 +23,12 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
|
@ -37,13 +40,16 @@ public class UserActivityLogController {
|
|||
|
||||
private final UserActivityLogDAO userActivityLogDAO;
|
||||
private final AuthorizationGrantService authorizationGrantService;
|
||||
private final PaginationService paginationService;
|
||||
|
||||
public UserActivityLogController(
|
||||
final UserActivityLogDAO userActivityLogDAO,
|
||||
final AuthorizationGrantService authorizationGrantService) {
|
||||
final AuthorizationGrantService authorizationGrantService,
|
||||
final PaginationService paginationService) {
|
||||
|
||||
this.userActivityLogDAO = userActivityLogDAO;
|
||||
this.authorizationGrantService = authorizationGrantService;
|
||||
this.paginationService = paginationService;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
|
@ -51,10 +57,11 @@ public class UserActivityLogController {
|
|||
@RequestParam(required = false) final Long from,
|
||||
@RequestParam(required = false) final Long to,
|
||||
@RequestParam(required = false) final String activityTypes,
|
||||
@RequestParam(required = false) final String entityTypes,
|
||||
final Principal principal) {
|
||||
@RequestParam(required = false) final String entityTypes) {
|
||||
|
||||
return _getAll(null, from, to, activityTypes, entityTypes, principal);
|
||||
checkBaseReadPrivilege();
|
||||
this.paginationService.setOnePageLimit(UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord);
|
||||
return _getAll(null, from, to, activityTypes, entityTypes);
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/{userId}", method = RequestMethod.GET)
|
||||
|
@ -63,10 +70,60 @@ public class UserActivityLogController {
|
|||
@RequestParam(required = false) final Long from,
|
||||
@RequestParam(required = false) final Long to,
|
||||
@RequestParam(required = false) final String activityTypes,
|
||||
@RequestParam(required = false) final String entityTypes,
|
||||
final Principal principal) {
|
||||
@RequestParam(required = false) final String entityTypes) {
|
||||
|
||||
return _getAll(userId, from, to, activityTypes, entityTypes, principal);
|
||||
checkBaseReadPrivilege();
|
||||
this.paginationService.setOnePageLimit(UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord);
|
||||
return _getAll(userId, from, to, activityTypes, entityTypes);
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/page", method = RequestMethod.GET)
|
||||
public Page<UserActivityLog> getPage(
|
||||
@RequestParam(required = false) final Long from,
|
||||
@RequestParam(required = false) final Long to,
|
||||
@RequestParam(required = false) final String activityTypes,
|
||||
@RequestParam(required = false) final String entityTypes,
|
||||
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
|
||||
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
|
||||
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
|
||||
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
|
||||
|
||||
checkBaseReadPrivilege();
|
||||
return this.paginationService.getPage(
|
||||
pageNumber,
|
||||
pageSize,
|
||||
sortBy,
|
||||
sortOrder,
|
||||
UserRecordDynamicSqlSupport.userRecord,
|
||||
() -> _getAll(null, from, to, activityTypes, entityTypes));
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/page/{userId}", method = RequestMethod.GET)
|
||||
public Page<UserActivityLog> getPageForUser(
|
||||
@PathVariable final String userId,
|
||||
@RequestParam(required = false) final Long from,
|
||||
@RequestParam(required = false) final Long to,
|
||||
@RequestParam(required = false) final String activityTypes,
|
||||
@RequestParam(required = false) final String entityTypes,
|
||||
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
|
||||
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
|
||||
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
|
||||
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
|
||||
|
||||
checkBaseReadPrivilege();
|
||||
return this.paginationService.getPage(
|
||||
pageNumber,
|
||||
pageSize,
|
||||
sortBy,
|
||||
sortOrder,
|
||||
UserRecordDynamicSqlSupport.userRecord,
|
||||
() -> _getAll(userId, from, to, activityTypes, entityTypes));
|
||||
}
|
||||
|
||||
private void checkBaseReadPrivilege() {
|
||||
this.authorizationGrantService.checkHasAnyPrivilege(
|
||||
EntityType.USER_ACTIVITY_LOG,
|
||||
PrivilegeType.READ_ONLY);
|
||||
}
|
||||
|
||||
private Collection<UserActivityLog> _getAll(
|
||||
|
@ -74,13 +131,7 @@ public class UserActivityLogController {
|
|||
final Long from,
|
||||
final Long to,
|
||||
final String activityTypes,
|
||||
final String entityTypes,
|
||||
final Principal principal) {
|
||||
|
||||
// fist check if current user has any privileges for this action
|
||||
this.authorizationGrantService.checkHasAnyPrivilege(
|
||||
EntityType.USER_ACTIVITY_LOG,
|
||||
PrivilegeType.READ_ONLY);
|
||||
final String entityTypes) {
|
||||
|
||||
final Set<String> _activityTypes = (activityTypes != null)
|
||||
? Collections.unmodifiableSet(new HashSet<>(
|
||||
|
@ -108,7 +159,6 @@ public class UserActivityLogController {
|
|||
|
||||
return this.userActivityLogDAO.all(userId, from, to, record -> true)
|
||||
.getOrThrow();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -163,6 +163,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
|||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.numberOfPages == 1);
|
||||
assertNotNull(userInfos.content);
|
||||
assertTrue(userInfos.content.size() == 7);
|
||||
assertEquals("[user1, user2, user3, user4, user5, user6, user7]", getOrderedUUIDs(userInfos.content));
|
||||
|
@ -180,6 +181,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
|||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.numberOfPages == 1);
|
||||
assertNotNull(userInfos.content);
|
||||
assertTrue(userInfos.content.size() == 7);
|
||||
assertEquals("[user7, user6, user5, user4, user3, user2, user1]", getOrderedUUIDs(userInfos.content));
|
||||
|
@ -200,10 +202,45 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
|||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.numberOfPages == 3);
|
||||
assertNotNull(userInfos.content);
|
||||
assertTrue(userInfos.content.size() == 3);
|
||||
assertEquals("[user1, user2, user3]", getOrderedUUIDs(userInfos.content));
|
||||
|
||||
// second page default sort order
|
||||
userInfos = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT
|
||||
+ "/page?pageNumber=2&pageSize=3")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Page<UserInfo>>() {
|
||||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.numberOfPages == 3);
|
||||
assertNotNull(userInfos.content);
|
||||
assertTrue(userInfos.content.size() == 3);
|
||||
assertEquals("[user4, user5, user6]", getOrderedUUIDs(userInfos.content));
|
||||
|
||||
// third page default sort order
|
||||
userInfos = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT
|
||||
+ "/page?pageNumber=3&pageSize=3")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Page<UserInfo>>() {
|
||||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.numberOfPages == 3);
|
||||
assertNotNull(userInfos.content);
|
||||
assertTrue(userInfos.content.size() == 1);
|
||||
assertEquals("[user7]", getOrderedUUIDs(userInfos.content));
|
||||
|
||||
// first page descending sort order
|
||||
userInfos = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
|
@ -216,6 +253,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
|||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.numberOfPages == 3);
|
||||
assertNotNull(userInfos.content);
|
||||
assertTrue(userInfos.content.size() == 3);
|
||||
assertEquals("[user7, user6, user5]", getOrderedUUIDs(userInfos.content));
|
||||
|
@ -230,7 +268,39 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void getAllUserInfoWithSearchInactive() throws Exception {
|
||||
public void getAllUserInfo() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<List<UserInfo>>() {
|
||||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.size() == 7);
|
||||
assertNotNull(getUserInfo("deactivatedUser", userInfos));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllUserInfoWithOnlyActice() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<List<UserInfo>>() {
|
||||
});
|
||||
|
||||
assertNotNull(userInfos);
|
||||
assertTrue(userInfos.size() == 6);
|
||||
assertNull(getUserInfo("deactivatedUser", userInfos));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllUserInfoOnlyInactive() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false")
|
||||
|
@ -245,22 +315,6 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
|||
assertNotNull(getUserInfo("deactivatedUser", userInfos));
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void getAllUserInfoWithFilterNameAndNoActiveFlagSet() throws Exception {
|
||||
// final String token = getSebAdminAccess();
|
||||
// final List<UserInfo> userInfos = this.jsonMapper.readValue(
|
||||
// this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false")
|
||||
// .header("Authorization", "Bearer " + token))
|
||||
// .andExpect(status().isOk())
|
||||
// .andReturn().getResponse().getContentAsString(),
|
||||
// new TypeReference<List<UserInfo>>() {
|
||||
// });
|
||||
//
|
||||
// assertNotNull(userInfos);
|
||||
// assertTrue(userInfos.size() == 1);
|
||||
// assertNotNull(getUserInfo("deactivatedUser", userInfos));
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void getAllUserInfoWithSearchUsernameLike() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
|
@ -688,11 +742,15 @@ public class UserAPITest extends AdministrationAPIIntegrationTest {
|
|||
}
|
||||
|
||||
private UserInfo getUserInfo(final String name, final Collection<UserInfo> infos) {
|
||||
return infos
|
||||
.stream()
|
||||
.filter(ui -> ui.username.equals(name))
|
||||
.findFirst()
|
||||
.orElseThrow(NoSuchElementException::new);
|
||||
try {
|
||||
return infos
|
||||
.stream()
|
||||
.filter(ui -> ui.username.equals(name))
|
||||
.findFirst()
|
||||
.orElseThrow(NoSuchElementException::new);
|
||||
} catch (final Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue