Skip to content

Commit

Permalink
insert multiple items
Browse files Browse the repository at this point in the history
  • Loading branch information
SrdjanStevanetic committed Oct 22, 2024
1 parent 5e6a93b commit 41236ef
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -167,5 +167,18 @@ public static String extractItemIdentifier(String dataEuropeanaUri, String item
return StringUtils.substring(dataEuropeanaUri, itemDataEndpoint.length());
}
}

//returns -1 if invalid or not provided
public static int parseItemsPosition(String position) {
int positionFinal = -1;
if (StringUtils.isNotEmpty(position)) {
try {
positionFinal = Integer.parseInt(position);
} catch (RuntimeException e) {
return -1;
}
}
return positionFinal;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jettison.json.JSONArray;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -453,6 +456,97 @@ void insertPinnedItems_EntityUserSets_withEditorUser() throws Exception {
// getUserSetService().deleteUserSet(identifier);
}

// test insert multiple items
@Test
void insertMultipleItems_EntityUserSets_withEditorUser() throws Exception {
WebUserSetImpl userSet = createTestUserSet(ENTITY_USER_SET_REGULAR, editorUserToken);
String identifier = userSet.getIdentifier();

List<String> newItems=new ArrayList<>();
String item1="http://data.europeana.eu/item/01/123_pinnedItem";
String item2="/02/123_pinnedItem";
JSONArray newItemsJson = new JSONArray();
newItemsJson.put(item1);
newItemsJson.put(item2);

String result = mockMvc
.perform(
put(BASE_URL + "{identifier}/items", identifier)
.content(newItemsJson.toString())
.queryParam(WebUserSetFields.PATH_PARAM_POSITION,
WebUserSetModelFields.PINNED_POSITION)
.header(HttpHeaders.AUTHORIZATION, editor2UserToken)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().is(HttpStatus.OK.value()))
.andReturn().getResponse()
.getContentAsString();

assertTrue(containsKeyOrValue(result, userSet.getId()));

UserSet existingUserSet = getUserSetService().getUserSetById(userSet.getIdentifier());
//check for the new items
assertEquals(0, existingUserSet.getItems().indexOf(item1));
assertEquals(1, existingUserSet.getItems().indexOf(item2));
assertEquals(2, existingUserSet.getPinned());
assertEquals(4, existingUserSet.getItems().size());

// insert pinned items, some of which already exist (and can be pinned or not-pinned in the set)
newItems.clear();
String item3="/03/123_pinnedItem";
newItems.add(item2);
String item4Existing=existingUserSet.getItems().get(2);
newItems.add(item4Existing);
newItems.add(item3);
getUserSetService().insertMultipleItems(newItems, WebUserSetModelFields.PINNED_POSITION, -1, existingUserSet);
//check the new items
assertEquals(0, existingUserSet.getItems().indexOf(item2));
assertEquals(1, existingUserSet.getItems().indexOf(item4Existing));
assertEquals(2, existingUserSet.getItems().indexOf(item3));
assertEquals(3, existingUserSet.getItems().indexOf(item1));
assertEquals(4, existingUserSet.getPinned());
assertEquals(5, existingUserSet.getItems().size());

//insert un-pinned items, some of which may exist (and can be pinned or not-pinned in the set)
newItems.clear();
//adding an existing pinned item in the request of un-pinned items
newItems.add(item1);
String item5="/05/123_unPinnedItem";
newItems.add(item5);
String item6Existing=existingUserSet.getItems().get(4);
newItems.add(item6Existing);
getUserSetService().insertMultipleItems(newItems, "4", 4, existingUserSet);
//check the new items
assertEquals(0, existingUserSet.getItems().indexOf(item2));
assertEquals(1, existingUserSet.getItems().indexOf(item4Existing));
assertEquals(2, existingUserSet.getItems().indexOf(item3));
assertEquals(3, existingUserSet.getItems().indexOf(item1));
assertEquals(4, existingUserSet.getPinned());
assertEquals(4, existingUserSet.getItems().indexOf(item5));
assertEquals(5, existingUserSet.getItems().indexOf(item6Existing));
assertEquals(4, existingUserSet.getPinned());
assertEquals(6, existingUserSet.getItems().size());

//insert item to the last position
newItems.clear();
String item7="/07/123_unPinnedItem";
newItems.add(item7);
getUserSetService().insertMultipleItems(newItems, null, -1, existingUserSet);
//check the new items
assertEquals(6, existingUserSet.getItems().indexOf(item7));
assertEquals(4, existingUserSet.getPinned());
assertEquals(7, existingUserSet.getItems().size());
//insert item to the position grater than the total size of items
newItems.clear();
String item8="/08/123_unPinnedItem";
newItems.add(item8);
getUserSetService().insertMultipleItems(newItems, "100", 100, existingUserSet);
//check the new items
assertEquals(7, existingUserSet.getItems().indexOf(item8));
assertEquals(4, existingUserSet.getPinned());
assertEquals(8, existingUserSet.getItems().size());

}

// test conversion of pinned -> normal item
@Test
void insertAlreadyExistingPinnedItemAsNormalItem_EntityUserSets_withEditorUser()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ private UserSetI18nConstants() {
public static final String INVALID_HEADER_FORMAT = "error.userset_invalid_header_format";
public static final String INVALID_HEADER_VALUE = "error.userset_invalid_header_value";
public static final String INVALID_SUBJECT_VALUE = "error.userset_subject_invalid_value";
public static final String INVALID_UNPINNED_ITEMS_POSITION = "error.userset_unpinned_items_position_invalid";

public static final String USERSET_VALIDATION = "error.userset_validation";
public static final String USERSET_DUPLICATION = "error.userset_duplication";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ private SwaggerConstants() {
public static final String SAMPLES_JSONLD = "Please find JSON-LD samples for user set in <a href=\"../jsp/template/jsonld.jsp\" target=\"_blank\">templates</a>. ";
public static final String SEARCH_HELP_NOTE = "Identifier is a number.";
public static final String INSERT_ITEM_NOTE = "Please create your insert item request using selected parameters.";
public static final String INSERT_MULTIPLE_ITEM_NOTE = "Please create your insert multiple items request using selected parameters.";
public static final String PUBLISH_SET_NOTE = "Please create the request for publishing the set using the provided parameters.";
public static final String CHECK_ITEM_NOTE = "Check if item is already in a user set";
public static final String DELETE_ITEM_NOTE = "Delete a item from the set ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import eu.europeana.api.commons.web.exception.ApplicationAuthenticationException;
import eu.europeana.api.commons.web.exception.HttpException;
import eu.europeana.api.commons.web.exception.ParamValidationException;
import eu.europeana.set.definitions.config.UserSetConfiguration;
import eu.europeana.set.definitions.model.UserSet;
import eu.europeana.set.definitions.model.search.UserSetFacetQuery;
import eu.europeana.set.definitions.model.search.UserSetQuery;
Expand Down Expand Up @@ -131,13 +132,16 @@ UserSet fetchItems(UserSet storedUserSet, String sort, String sortOrder, int pag
UserSet insertItem(String datasetId, String localId, String position, UserSet existingUserSet)
throws ApplicationAuthenticationException, ItemValidationException;

public UserSet insertMultipleItems(List<String> items, String position, int itemsPosition, UserSet existingUserSet)
throws ItemValidationException;

/**
* This method updates existing item list
*
* @param existingUserSet
* @return updated user set
*/
UserSet updateItemList(UserSet existingUserSet);
UserSet updateUserSetInMongo(UserSet existingUserSet);

/**
* search user sets using the given query and profile
Expand Down Expand Up @@ -257,4 +261,6 @@ ItemIdsResultPage buildItemIdsResultsPage(String setId, List<String> itemIds, in

void validateGallerySize(UserSet webUserSet, int newItems) throws ItemValidationException;

UserSet updatePagination(UserSet userSet, UserSetConfiguration config);

}
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ protected ResponseEntity<String> publishUnpublishUserSet(String identifier, Auth
}
}

@Deprecated
@PutMapping(value = {"/set/{identifier}/{datasetId}/{localId}"},
produces = {HttpHeaders.CONTENT_TYPE_JSONLD_UTF8, HttpHeaders.CONTENT_TYPE_JSON_UTF8})
@Operation(description = SwaggerConstants.INSERT_ITEM_NOTE,
Expand All @@ -433,6 +434,21 @@ public ResponseEntity<String> insertItemIntoUserSet(
return insertItemIntoUserSet(request, authentication, identifier, datasetId, localId, position);
}

@PutMapping(value = {"/set/{identifier}/items"},
produces = {HttpHeaders.CONTENT_TYPE_JSONLD_UTF8, HttpHeaders.CONTENT_TYPE_JSON_UTF8})
@Operation(description = SwaggerConstants.INSERT_MULTIPLE_ITEM_NOTE,
summary = "Insert multiple items to an existing user set")
public ResponseEntity<String> insertMultipleItemsIntoUserSet(
@PathVariable(value = WebUserSetFields.PATH_PARAM_SET_ID) String identifier,
@RequestParam(value = WebUserSetFields.PATH_PARAM_POSITION, required = false) String position,
@RequestBody List<String> items,
HttpServletRequest request) throws HttpException {
// check user credentials, if invalid respond with HTTP 401,
// or if unauthorized respond with HTTP 403
Authentication authentication = verifyWriteAccess(Operations.UPDATE, request);
return insertMultipleItemsIntoUserSet(request, authentication, identifier, items, position);
}

/**
* This method validates input values, retrieves user set object and inserts item within user set
* to given position or at the end if no valid position provided.
Expand All @@ -443,10 +459,10 @@ public ResponseEntity<String> insertItemIntoUserSet(
* @param datasetId The identifier of the dataset, typically a number
* @param localId The local identifier within the provider
* @param position The position in the existin item list
* @param profileStr The profile definition
* @return response entity that comprises response body, headers and status code
* @throws HttpException
*/
@Deprecated
protected ResponseEntity<String> insertItemIntoUserSet(HttpServletRequest request,
Authentication authentication, String identifier, String datasetId, String localId,
String position) throws HttpException {
Expand Down Expand Up @@ -482,6 +498,83 @@ protected ResponseEntity<String> insertItemIntoUserSet(HttpServletRequest reques

UserSet updatedUserSet =
getUserSetService().insertItem(datasetId, localId, position, existingUserSet);
getUserSetService().updatePagination(updatedUserSet, getConfiguration());

String serializedUserSetJsonLdStr = serializeUserSet(LdProfiles.MINIMAL, updatedUserSet);

String etag =
generateETag(updatedUserSet.getModified(), WebFields.FORMAT_JSONLD, getApiVersion());

// build response entity with headers
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HttpHeaders.ALLOW, UserSetHttpHeaders.ALLOW_PPGHD);
headers.add(UserSetHttpHeaders.VARY, HttpHeaders.PREFER);
headers.add(UserSetHttpHeaders.PREFERENCE_APPLIED, LdProfiles.MINIMAL.getPreferHeaderValue());
headers.add(UserSetHttpHeaders.ETAG, etag);
return new ResponseEntity<>(serializedUserSetJsonLdStr, headers, HttpStatus.OK);

} catch (UserSetValidationException e) {
throw new RequestValidationException(UserSetI18nConstants.USERSET_VALIDATION,
new String[] {e.getMessage()}, e);
} catch (HttpException e) {
throw e;
} catch (RuntimeException | IOException e) {
throw new InternalServerException(e);
}
}

/**
* This method validates input values, retrieves user set object and inserts multiple items
* within user set to the given position or at the end if no valid position provided.
*
* @param request
* @param authentication The Authentication object
* @param identifier The identifier of a user set
* @param items Items to be added to the set
* @param position The position in the existin item list
* @return response entity that comprises response body, headers and status code
* @throws HttpException
*/
protected ResponseEntity<String> insertMultipleItemsIntoUserSet(HttpServletRequest request,
Authentication authentication, String identifier, List<String> items, String position) throws HttpException {
try {
// check if the Set exists, if not respond with HTTP 404
// retrieve an existing user set based on its identifier
UserSet existingUserSet = getUserSetService().getUserSetById(identifier);

if (existingUserSet.isOpenSet()) {
// cannot add items to open sets
throw new RequestValidationException(UserSetI18nConstants.USER_SET_OPERATION_NOT_ALLOWED,
new String[] {"'Insert item to existing user set'", "open"});
}

// if set is not entity best item set and position is "pin", throw exception
if (!existingUserSet.isEntityBestItemsSet()
&& StringUtils.equals(position, WebUserSetFields.PINNED_POSITION)) {
throw new RequestValidationException(UserSetI18nConstants.USER_SET_OPERATION_NOT_ALLOWED,
new String[] {"Pinning item ", existingUserSet.getType()});
}

int itemsPosition=UserSetUtils.parseItemsPosition(position);
if(!StringUtils.equals(position, WebUserSetFields.PINNED) && itemsPosition>=0 && itemsPosition < existingUserSet.getPinned()) {
throw new RequestValidationException(UserSetI18nConstants.INVALID_UNPINNED_ITEMS_POSITION, null);
}

// check visibility level for given user
getUserSetService().verifyPermissionToUpdate(existingUserSet, authentication, true);

// for entity user sets, add users with 'editor' role as contributors
addContributorForEntitySet(existingUserSet, authentication);

// check timestamp if provided within the “If-Match” HTTP header, if false
// respond with HTTP 412
String eTagOrigin =
generateETag(existingUserSet.getModified(), WebFields.FORMAT_JSONLD, getApiVersion());
checkIfMatchHeader(eTagOrigin, request);

UserSet updatedUserSet =
getUserSetService().insertMultipleItems(items, position, itemsPosition, existingUserSet);
getUserSetService().updatePagination(updatedUserSet, getConfiguration());

String serializedUserSetJsonLdStr = serializeUserSet(LdProfiles.MINIMAL, updatedUserSet);

Expand Down Expand Up @@ -661,7 +754,9 @@ protected ResponseEntity<String> deleteItemFromUserSet(Authentication authentica
existingUserSet.getItems().remove(newItem);

// update an existing user set
UserSet updatedUserSet = getUserSetService().updateItemList(existingUserSet);
UserSet updatedUserSet = getUserSetService().updateUserSetInMongo(existingUserSet);
//update pagination fields (used only for the response serialization)
getUserSetService().updatePagination(updatedUserSet, getConfiguration());

// serialize to JsonLd
String serializedUserSetJsonLdStr = serializeUserSet(LdProfiles.MINIMAL, updatedUserSet);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ public abstract class BaseUserSetServiceImpl implements UserSetService {
private SearchApiClient setApiService = new SearchApiClientImpl();

Logger logger = LogManager.getLogger(getClass());


//update the pagination fields of the set (used only for the serialization to the output)
@Override
public UserSet updatePagination(UserSet userSet, UserSetConfiguration config) {
return userSetUtils.updatePagination(userSet, config);
}

protected PersistentUserSetService getMongoPersistence() {
return mongoPersistance;
Expand Down Expand Up @@ -501,6 +508,8 @@ private void validateAndSetItems(UserSet storedUserSet, UserSet userSetUpdates)
}
}

//this method is to be deprecated when the new items insert is used
@Deprecated
protected void validateItems(List<String> items) throws ItemValidationException {
if(items==null || items.isEmpty()) {
return;
Expand All @@ -518,7 +527,35 @@ protected void validateItems(List<String> items) throws ItemValidationException
throw new ItemValidationException(UserSetI18nConstants.USERSET_ITEM_INVALID_FORMAT, new String[] {invalidItems.toString()} );
}
}


//items can be either a uri or a record identifier (e.g. "/1234/XPTO_2")
protected void validateItemsStrings(List<String> items) throws ItemValidationException {
if(items==null || items.isEmpty()) {
return;
}
List<String> invalidItems = new ArrayList<>();
for(String item : items) {
try {
if(item.startsWith(getConfiguration().getItemDataEndpoint())) {
String itemWithoutBase = item.replace(getConfiguration().getItemDataEndpoint(), "");
if(!itemWithoutBase.startsWith("/")) {
itemWithoutBase = "/" + itemWithoutBase;
}
validateItemPartial(itemWithoutBase);
}
else {
validateItemPartial(item);
}
}
catch (ItemValidationException ex) {
invalidItems.add(item);
}
}
if(invalidItems.size()>0) {
throw new ItemValidationException(UserSetI18nConstants.USERSET_ITEM_INVALID_FORMAT, new String[] {invalidItems.toString()} );
}
}

protected void validateItemWhole(String item) throws ItemValidationException {
if(!item.startsWith(getConfiguration().getItemDataEndpoint())) {
throw new ItemValidationException(UserSetI18nConstants.USERSET_ITEM_INVALID_FORMAT, new String[] {item});
Expand Down
Loading

0 comments on commit 41236ef

Please sign in to comment.