more tests and validation
This commit is contained in:
parent
c786eed28a
commit
04bbadf2e0
13 changed files with 113 additions and 99 deletions
|
@ -138,6 +138,11 @@ public class APIMessage implements Serializable {
|
|||
return ErrorMessage.FIELD_VALIDATION.of(error.toString(), args);
|
||||
}
|
||||
|
||||
public static APIMessage fieldValidationError(final String fieldName, final String defaultMessage) {
|
||||
final String[] args = StringUtils.split(defaultMessage, ":");
|
||||
return ErrorMessage.FIELD_VALIDATION.of(fieldName, args);
|
||||
}
|
||||
|
||||
public static String toHTML(final Collection<APIMessage> messages) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("<b>Messages:</b><br/><br/>");
|
||||
|
@ -182,4 +187,15 @@ public class APIMessage implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
public static class FieldValidationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 3324566460573096815L;
|
||||
|
||||
public final APIMessage apiMessage;
|
||||
|
||||
public FieldValidationException(final String fieldName, final String defaultMessage) {
|
||||
this.apiMessage = APIMessage.fieldValidationError(fieldName, defaultMessage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,4 +26,8 @@ public class SEBServerRestEndpoints {
|
|||
|
||||
public static final String LIST_ENDPOINT_SUFFIX = "/list";
|
||||
|
||||
public static final String ENDPOINT_ACTIVE = "/active";
|
||||
|
||||
public static final String ENDPOINT_INACTIVE = "/inactive";
|
||||
|
||||
}
|
||||
|
|
|
@ -170,10 +170,12 @@ public final class Form implements FormBinding {
|
|||
|
||||
//@formatter:off
|
||||
private FormFieldAccessor<?> createAccessor(final Label label, final Label field) {
|
||||
return new FormFieldAccessor<>(label, field) {
|
||||
final FormFieldAccessor<?> result = new FormFieldAccessor<>(label, field) {
|
||||
@Override public String getValue() { return field.getText(); }
|
||||
@Override public void setValue(final String value) { field.setText(value); }
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
private FormFieldAccessor<Text> createAccessor(final Label label, final Text text) {
|
||||
return new FormFieldAccessor<>(label, text) {
|
||||
|
|
|
@ -32,19 +32,6 @@ public interface ActivatableEntityDAO<T extends Entity, M extends ModelIdAware>
|
|||
* @return Result of Collection of Entity of the given institution and activity */
|
||||
Result<Collection<T>> all(Long institutionId, Boolean active);
|
||||
|
||||
/** Load all active entities of concrete type for the given institution
|
||||
*
|
||||
* NOTE: institutionId may be null. In that case this method uses a query to get all active entities of
|
||||
* concrete type from all institutions. Anyways, to not pollute the memory it is recommended to set a limit by
|
||||
* using the <code>PaginationService</code> before calling this method
|
||||
*
|
||||
* @param institutionId the identifier of the institution.
|
||||
* @return Result of Collection of Entity of the given institution */
|
||||
@Override
|
||||
default Result<Collection<T>> all(final Long institutionId) {
|
||||
return all(institutionId, true);
|
||||
}
|
||||
|
||||
/** Set all entities referred by the given Collection of EntityKey active / inactive
|
||||
*
|
||||
* @param all The Collection of EntityKeys to set active or inactive
|
||||
|
|
|
@ -53,16 +53,6 @@ public interface EntityDAO<T extends Entity, M extends ModelIdAware> {
|
|||
}).flatMap(this::byPK);
|
||||
}
|
||||
|
||||
/** Use this to get a Collection of all entities of concrete type of the given institution.
|
||||
*
|
||||
* NOTE: institutionId may be null. In that case this method uses a query to get all entities of
|
||||
* concrete type from all institutions. Anyways, to not pollute the memory it is recommended to set a limit by
|
||||
* using the <code>PaginationService</code> before calling this method
|
||||
*
|
||||
* @param institutionId the identifier of the institution.
|
||||
* @return Result of Collection of Entity of the given institution */
|
||||
Result<Collection<T>> all(Long institutionId);
|
||||
|
||||
Result<Collection<T>> loadEntities(Collection<EntityKey> keys);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
|
|
|
@ -75,27 +75,6 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
.flatMap(this::toDomainModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Result<Collection<Indicator>> all(final Long institutionId) {
|
||||
return Result.tryCatch(() -> {
|
||||
return this.indicatorRecordMapper.selectByExample()
|
||||
.join(ExamRecordDynamicSqlSupport.examRecord)
|
||||
.on(
|
||||
ExamRecordDynamicSqlSupport.id,
|
||||
SqlBuilder.equalTo(IndicatorRecordDynamicSqlSupport.examId))
|
||||
.where(
|
||||
ExamRecordDynamicSqlSupport.institutionId,
|
||||
isEqualTo(institutionId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(this::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Result<Collection<Indicator>> allMatching(final FilterMap filterMap, final Predicate<Indicator> predicate) {
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
|
@ -131,6 +132,16 @@ public class InstitutionDAOImpl implements InstitutionDAO {
|
|||
public Result<Institution> save(final String modelId, final Institution institution) {
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
final Long count = this.institutionRecordMapper.countByExample()
|
||||
.where(InstitutionRecordDynamicSqlSupport.name, isEqualTo(institution.name))
|
||||
.and(InstitutionRecordDynamicSqlSupport.id, isNotEqualTo(institution.id))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
if (count != null && count.longValue() > 0) {
|
||||
throw new FieldValidationException("name", "institution:name:exists");
|
||||
}
|
||||
|
||||
final Long pk = Long.parseLong(modelId);
|
||||
final InstitutionRecord newRecord = new InstitutionRecord(
|
||||
pk,
|
||||
|
@ -150,6 +161,16 @@ public class InstitutionDAOImpl implements InstitutionDAO {
|
|||
@Transactional
|
||||
public Result<Institution> createNew(final Institution institution) {
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
final Long count = this.institutionRecordMapper.countByExample()
|
||||
.where(InstitutionRecordDynamicSqlSupport.name, isEqualTo(institution.name))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
if (count != null && count.longValue() > 0) {
|
||||
throw new FieldValidationException("name", "institution:name:exists");
|
||||
}
|
||||
|
||||
final InstitutionRecord newRecord = new InstitutionRecord(
|
||||
null,
|
||||
institution.name,
|
||||
|
|
|
@ -279,40 +279,6 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Result<Collection<UserActivityLog>> all(final Long institutionId) {
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
if (institutionId == null) {
|
||||
return this.userLogRecordMapper
|
||||
.selectByExample()
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(UserActivityLogDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return this.userLogRecordMapper
|
||||
.selectByExample()
|
||||
.join(UserRecordDynamicSqlSupport.userRecord)
|
||||
.on(
|
||||
UserRecordDynamicSqlSupport.uuid,
|
||||
SqlBuilder.equalTo(UserActivityLogRecordDynamicSqlSupport.userUuid))
|
||||
.where(
|
||||
UserRecordDynamicSqlSupport.institutionId,
|
||||
SqlBuilder.isEqualTo(institutionId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(UserActivityLogDAOImpl::toDomainModel)
|
||||
.flatMap(DAOLoggingSupport::logUnexpectedErrorAndSkip)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Result<Collection<UserActivityLog>> loadEntities(final Collection<EntityKey> keys) {
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationException;
|
||||
|
@ -140,4 +141,14 @@ public class APIExceptionHandler extends ResponseEntityExceptionHandler {
|
|||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ExceptionHandler(FieldValidationException.class)
|
||||
public ResponseEntity<Object> handleFieldValidationException(
|
||||
final FieldValidationException ex,
|
||||
final WebRequest request) {
|
||||
|
||||
return new ResponseEntity<>(
|
||||
Arrays.asList(ex.apiMessage),
|
||||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
|
@ -56,7 +57,7 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = "/all/active",
|
||||
path = SEBServerRestEndpoints.ENDPOINT_ACTIVE,
|
||||
method = RequestMethod.GET,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
|
@ -79,7 +80,7 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = "/all/inactive",
|
||||
path = SEBServerRestEndpoints.ENDPOINT_INACTIVE,
|
||||
method = RequestMethod.GET,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
|
@ -102,22 +103,22 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = "/{id}/active",
|
||||
path = "/{modelId}" + SEBServerRestEndpoints.ENDPOINT_ACTIVE,
|
||||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public EntityProcessingReport activate(@PathVariable final String id) {
|
||||
return setActive(id, true)
|
||||
public EntityProcessingReport activate(@PathVariable final String modelId) {
|
||||
return setActive(modelId, true)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
value = "/{id}/inactive",
|
||||
value = "/{modelId}" + SEBServerRestEndpoints.ENDPOINT_INACTIVE,
|
||||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public EntityProcessingReport deactivate(@PathVariable final String id) {
|
||||
return setActive(id, false)
|
||||
public EntityProcessingReport deactivate(@PathVariable final String modelId) {
|
||||
return setActive(modelId, false)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,10 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -42,6 +44,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
|||
|
||||
import ch.ethz.seb.sebserver.SEBServer;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(
|
||||
|
@ -239,4 +242,12 @@ public abstract class AdministrationAPIIntegrationTester {
|
|||
}
|
||||
}
|
||||
|
||||
protected String getOrderedUUIDs(final Collection<? extends Entity> list) {
|
||||
return list
|
||||
.stream()
|
||||
.map(userInfo -> userInfo.getModelId())
|
||||
.collect(Collectors.toList())
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
package ch.ethz.seb.sebserver.webservice.integration.api.admin;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
@ -16,6 +18,7 @@ import java.util.List;
|
|||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
@ -367,6 +370,37 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertTrue(institutions.size() == 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testlAllActiveInactive() throws Exception {
|
||||
final String sebAdminToken = getSebAdminAccess();
|
||||
|
||||
Page<Institution> institutions = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/active")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Page<Institution>>() {
|
||||
});
|
||||
|
||||
assertNotNull(institutions);
|
||||
assertEquals("[1]", getOrderedUUIDs(institutions.content));
|
||||
|
||||
// all inactive of the own institution
|
||||
institutions = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/inactive")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Page<Institution>>() {
|
||||
});
|
||||
|
||||
assertNotNull(institutions);
|
||||
assertTrue(institutions.pageSize == 0);
|
||||
assertEquals("[]", getOrderedUUIDs(institutions.content));
|
||||
}
|
||||
|
||||
static void assertContainsInstitution(final String name, final Collection<Institution> institutions) {
|
||||
assert institutions != null;
|
||||
assert institutions.stream()
|
||||
|
|
|
@ -341,14 +341,6 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertEquals("[user7, user6, user4]", getOrderedUUIDs(userInfos.content));
|
||||
}
|
||||
|
||||
private String getOrderedUUIDs(final Collection<UserInfo> list) {
|
||||
return list
|
||||
.stream()
|
||||
.map(userInfo -> userInfo.uuid)
|
||||
.collect(Collectors.toList())
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllUserInfo() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
|
@ -982,7 +974,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// all active for the own institution
|
||||
Page<UserInfo> usersPage = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/all/active")
|
||||
this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/active")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -996,7 +988,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// all inactive of the own institution
|
||||
usersPage = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/all/inactive")
|
||||
this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/inactive")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -1012,7 +1004,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
usersPage = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT
|
||||
+ "/all/active?institutionId=2")
|
||||
+ "/active?institutionId=2")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -1028,7 +1020,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
usersPage = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT
|
||||
+ "/all/inactive?institutionId=2")
|
||||
+ "/inactive?institutionId=2")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
|
Loading…
Add table
Reference in a new issue