Skip to content

Commit

Permalink
Merge pull request #11124 from IQSS/10943-featured-items
Browse files Browse the repository at this point in the history
Dataverse Featured Items support
  • Loading branch information
ofahimIQSS authored Jan 29, 2025
2 parents 16422d5 + a8d4a05 commit 78ac64b
Show file tree
Hide file tree
Showing 35 changed files with 2,002 additions and 101 deletions.
15 changes: 15 additions & 0 deletions doc/release-notes/10943-featured-items.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CRUD endpoints for Collection Featured Items have been implemented. In particular, the following endpoints have been implemented:

- Create a feature item (POST /api/dataverses/<dataverse_id>/featuredItems)
- Update a feature item (PUT /api/dataverseFeaturedItems/<item_id>)
- Delete a feature item (DELETE /api/dataverseFeaturedItems/<item_id>)
- List all featured items in a collection (GET /api/dataverses/<dataverse_id>/featuredItems)
- Delete all featured items in a collection (DELETE /api/dataverses/<dataverse_id>/featuredItems)
- Update all featured items in a collection (PUT /api/dataverses/<dataverse_id>/featuredItems)

New settings:

- dataverse.files.featured-items.image-maxsize - It sets the maximum allowed size of the image that can be added to a featured item.
- dataverse.files.featured-items.image-uploads - It specifies the name of the subdirectory for saving featured item images within the docroot directory.

See also #10943 and #11124.
203 changes: 203 additions & 0 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,209 @@ Use the ``/settings`` API to enable or disable the enforcement of storage quotas
curl -X PUT -d 'true' http://localhost:8080/api/admin/settings/:UseStorageQuotas
List All Collection Featured Items
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

List the featured items configured for a given Dataverse collection ``id``:

.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export SERVER_URL=https://demo.dataverse.org
export ID=root
curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/dataverses/$ID/featuredItems"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/dataverses/root/featuredItems"
Update All Collection Featured Items
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Updates all featured items in the given Dataverse collection ``id``.

The data sent to the endpoint represents the desired final state of the featured items in the Dataverse collection and overwrites any existing featured items configuration.

The parameters ``id``, ``content``, ``displayOrder``, and ``fileName`` must be specified as many times as the number of items we want to add or update. The order in which these parameters are repeated must match to ensure they correspond to the same featured item.

The ``file`` parameter must be specified for each image we want to attach to featured items. Note that images can be shared between featured items, so ``fileName`` can have the same value in different featured items.

The ``id`` parameter must be ``0`` for new items or set to the item's identifier for updates. The ``fileName`` parameter should be empty to exclude an image or match the name of a file sent in a ``file`` parameter to set a new image. ``keepFile`` must always be set to ``false``, unless it's an update to a featured item where we want to preserve the existing image, if one exists.

Note that any existing featured item not included in the call with its associated identifier and corresponding properties will be removed from the collection.

The following example creates two featured items, with an image assigned to the second one:

.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export SERVER_URL=https://demo.dataverse.org
export ID=root
export FIRST_ITEM_CONTENT='Content 1'
export FIRST_ITEM_DISPLAY_ORDER=1
export SECOND_ITEM_IMAGE_FILENAME='image.png'
export SECOND_ITEM_CONTENT='Content 2'
export SECOND_ITEM_DISPLAY_ORDER=2
curl -H "X-Dataverse-key:$API_TOKEN" \
-X PUT \
-F "id=0" -F "id=0" \
-F "content=$FIRST_ITEM_CONTENT" -F "content=$SECOND_ITEM_CONTENT" \
-F "displayOrder=$FIRST_ITEM_DISPLAY_ORDER" -F "displayOrder=$SECOND_ITEM_DISPLAY_ORDER" \
-F "fileName=" -F "fileName=$SECOND_ITEM_IMAGE_FILENAME" \
-F "keepFile=false" -F "keepFile=false" \
-F "file=@$SECOND_ITEM_IMAGE_FILENAME" \
"$SERVER_URL/api/dataverses/$ID/featuredItems"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-X PUT \
-F "id=0" -F "id=0" \
-F "content=Content 1" -F "content=Content 2" \
-F "displayOrder=1" -F "displayOrder=2" \
-F "fileName=" -F "fileName=image.png" \
-F "keepFile=false" -F "keepFile=false" \
-F "[email protected]" \
"https://demo.dataverse.org/api/dataverses/root/featuredItems"
The following example creates one featured item and updates a second one, keeping the existing image it may have had:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-X PUT \
-F "id=0" -F "id=1" \
-F "content=Content 1" -F "content=Updated content 2" \
-F "displayOrder=1" -F "displayOrder=2" \
-F "fileName=" -F "fileName=" \
-F "keepFile=false" -F "keepFile=true" \
"https://demo.dataverse.org/api/dataverses/root/featuredItems"
Delete All Collection Featured Items
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Deletes the featured items configured for a given Dataverse collection ``id``:

.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export SERVER_URL=https://demo.dataverse.org
export ID=root
curl -H "X-Dataverse-key: $API_TOKEN" -X DELETE "$SERVER_URL/api/dataverses/$ID/featuredItems"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE "https://demo.dataverse.org/api/dataverses/root/featuredItems"
Create a Collection Featured Item
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Creates a featured item in the given Dataverse collection ``id``:

.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export IMAGE_FILENAME='image.png'
export CONTENT='Content for featured item.'
export DISPLAY_ORDER=1
export SERVER_URL=https://demo.dataverse.org
export ID=root
curl -H "X-Dataverse-key:$API_TOKEN" -X POST -F "file=@$IMAGE_FILENAME" -F "content=$CONTENT" -F "displayOrder=$DISPLAY_ORDER" "$SERVER_URL/api/dataverses/$ID/featuredItems"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST -F "[email protected]" -F "content=Content for featured item." -F "displayOrder=1" "https://demo.dataverse.org/api/dataverses/root/featuredItems"
A featured item may or may not contain an image. If you wish to create it without an image, omit the file parameter in the request.

Update a Collection Featured Item
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Updates a featured item given its ``id``:

.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export IMAGE_FILENAME='image.png'
export CONTENT='Content for featured item.'
export DISPLAY_ORDER=1
export SERVER_URL=https://demo.dataverse.org
export ID=1
curl -H "X-Dataverse-key:$API_TOKEN" -X PUT -F "file=@$IMAGE_FILENAME" -F "content=$CONTENT" -F "displayOrder=$DISPLAY_ORDER" "$SERVER_URL/api/dataverseFeaturedItems/$ID"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X PUT -F "[email protected]" -F "content=Content for featured item." -F "displayOrder=1" "https://demo.dataverse.org/api/dataverseFeaturedItems/1"
``content`` and ``displayOrder`` must always be provided; otherwise, an error will occur. Use the ``file`` parameter to set a new image for the featured item. To keep the existing image, omit ``file`` and send ``keepFile=true``. To remove the image, omit the file parameter.

Updating the featured item keeping the existing image:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X PUT -F "keepFile=true" -F "content=Content for featured item." -F "displayOrder=1" "https://demo.dataverse.org/api/dataverseFeaturedItems/1"
Updating the featured item removing the existing image:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X PUT -F "content=Content for featured item." -F "displayOrder=1" "https://demo.dataverse.org/api/dataverseFeaturedItems/1"
Delete a Collection Featured Item
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Deletes a featured item given its ``id``:

.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export SERVER_URL=https://demo.dataverse.org
export ID=1
curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE "$SERVER_URL/api/dataverseFeaturedItems/$ID"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE "https://demo.dataverse.org/api/dataverseFeaturedItems/1"
Get a Collection Featured Item Image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Returns the image of a featured item if one is assigned, given the featured item ``id``:

.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export SERVER_URL=https://demo.dataverse.org
export ID=1
curl -H "X-Dataverse-key:$API_TOKEN" -X GET "$SERVER_URL/api/access/dataverseFeaturedItemImage/{ID}"
The fully expanded example above (without environment variables) looks like this:

.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X GET "https://demo.dataverse.org/api/access/dataverseFeaturedItemImage/1"
Datasets
--------
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/Dataverse.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.harvard.iq.dataverse;

import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItem;
import edu.harvard.iq.dataverse.harvest.client.HarvestingClient;
import edu.harvard.iq.dataverse.authorization.DataverseRole;
import edu.harvard.iq.dataverse.search.savedsearch.SavedSearch;
Expand Down Expand Up @@ -352,6 +353,17 @@ public void setMetadataBlockFacets(List<DataverseMetadataBlockFacet> metadataBlo
this.metadataBlockFacets = metadataBlockFacets;
}

@OneToMany(mappedBy = "dataverse")
private List<DataverseFeaturedItem> dataverseFeaturedItems = new ArrayList<>();

public List<DataverseFeaturedItem> getDataverseFeaturedItems() {
return this.dataverseFeaturedItems;
}

public void setDataverseFeaturedItems(List<DataverseFeaturedItem> dataverseFeaturedItems) {
this.dataverseFeaturedItems = dataverseFeaturedItems;
}

public List<Guestbook> getParentGuestbooks() {
List<Guestbook> retList = new ArrayList<>();
Dataverse testDV = this;
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/edu/harvard/iq/dataverse/EjbDataverseEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import edu.harvard.iq.dataverse.actionlogging.ActionLogServiceBean;
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean;
import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItemServiceBean;
import edu.harvard.iq.dataverse.util.cache.CacheFactoryBean;
import edu.harvard.iq.dataverse.engine.DataverseEngine;
import edu.harvard.iq.dataverse.authorization.Permission;
Expand Down Expand Up @@ -184,7 +185,10 @@ public class EjbDataverseEngine {
ConfirmEmailServiceBean confirmEmailService;

@EJB
StorageUseServiceBean storageUseService;
StorageUseServiceBean storageUseService;

@EJB
DataverseFeaturedItemServiceBean dataverseFeaturedItemServiceBean;

@EJB
EjbDataverseEngineInner innerEngine;
Expand Down Expand Up @@ -522,6 +526,11 @@ public DatasetFieldServiceBean dsField() {
return dsField;
}

@Override
public DataverseFeaturedItemServiceBean dataverseFeaturedItems() {
return dataverseFeaturedItemServiceBean;
}

@Override
public StorageUseServiceBean storageUse() {
return storageUseService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,8 @@ protected <T> T execCommand( Command<T> cmd ) throws WrappedResponse {
}
} catch (InvalidFieldsCommandException ex) {
throw new WrappedResponse(ex, badRequest(ex.getMessage(), ex.getFieldErrors()));
} catch (InvalidCommandArgumentsException ex) {
throw new WrappedResponse(ex, error(Status.BAD_REQUEST, ex.getMessage()));
} catch (CommandException ex) {
Logger.getLogger(AbstractApiBean.class.getName()).log(Level.SEVERE, "Error while executing command " + cmd, ex);
throw new WrappedResponse(ex, error(Status.INTERNAL_SERVER_ERROR, ex.getMessage()));
Expand Down
63 changes: 26 additions & 37 deletions src/main/java/edu/harvard/iq/dataverse/api/Access.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,7 @@

package edu.harvard.iq.dataverse.api;

import edu.harvard.iq.dataverse.AuxiliaryFile;
import edu.harvard.iq.dataverse.AuxiliaryFileServiceBean;
import edu.harvard.iq.dataverse.DataCitation;
import edu.harvard.iq.dataverse.DataFile;
import edu.harvard.iq.dataverse.FileAccessRequest;
import edu.harvard.iq.dataverse.FileMetadata;
import edu.harvard.iq.dataverse.DataFileServiceBean;
import edu.harvard.iq.dataverse.Dataset;
import edu.harvard.iq.dataverse.DatasetVersion;
import edu.harvard.iq.dataverse.DatasetVersionServiceBean;
import edu.harvard.iq.dataverse.DatasetServiceBean;
import edu.harvard.iq.dataverse.Dataverse;
import edu.harvard.iq.dataverse.DataverseRequestServiceBean;
import edu.harvard.iq.dataverse.DataverseRoleServiceBean;
import edu.harvard.iq.dataverse.DataverseServiceBean;
import edu.harvard.iq.dataverse.DataverseSession;
import edu.harvard.iq.dataverse.DataverseTheme;
import edu.harvard.iq.dataverse.FileDownloadServiceBean;
import edu.harvard.iq.dataverse.GuestbookResponse;
import edu.harvard.iq.dataverse.GuestbookResponseServiceBean;
import edu.harvard.iq.dataverse.PermissionServiceBean;
import edu.harvard.iq.dataverse.PermissionsWrapper;
import edu.harvard.iq.dataverse.RoleAssignment;
import edu.harvard.iq.dataverse.UserNotification;
import edu.harvard.iq.dataverse.UserNotificationServiceBean;
import edu.harvard.iq.dataverse.ThemeWidgetFragment;
import edu.harvard.iq.dataverse.*;

import static edu.harvard.iq.dataverse.api.Datasets.handleVersion;

Expand All @@ -52,18 +27,12 @@
import edu.harvard.iq.dataverse.dataaccess.ImageThumbConverter;
import edu.harvard.iq.dataverse.datavariable.DataVariable;
import edu.harvard.iq.dataverse.datavariable.VariableServiceBean;
import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItem;
import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItemServiceBean;
import edu.harvard.iq.dataverse.engine.command.Command;
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.impl.AssignRoleCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetDatasetCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetDraftDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetLatestAccessibleDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetLatestPublishedDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetSpecificPublishedDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.RequestAccessCommand;
import edu.harvard.iq.dataverse.engine.command.impl.RevokeRoleCommand;
import edu.harvard.iq.dataverse.engine.command.impl.UpdateDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.*;
import edu.harvard.iq.dataverse.export.DDIExportServiceBean;
import edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean;
import edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry;
Expand All @@ -88,7 +57,6 @@
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import jakarta.inject.Inject;
import jakarta.json.Json;
Expand Down Expand Up @@ -133,7 +101,6 @@

import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
Expand Down Expand Up @@ -199,6 +166,8 @@ public class Access extends AbstractApiBean {
PermissionsWrapper permissionsWrapper;
@Inject
MakeDataCountLoggingServiceBean mdcLogService;
@Inject
DataverseFeaturedItemServiceBean dataverseFeaturedItemServiceBean;

//@EJB

Expand Down Expand Up @@ -2015,4 +1984,24 @@ private URI handleCustomZipDownload(User user, String customZipServiceUrl, Strin
}
return redirectUri;
}

@GET
@AuthRequired
@Produces({"image/png"})
@Path("dataverseFeaturedItemImage/{itemId}")
public InputStream getDataverseFeatureItemImage(@Context ContainerRequestContext crc, @PathParam("itemId") Long itemId) {
DataverseFeaturedItem dataverseFeaturedItem;
try {
dataverseFeaturedItem = execCommand(new GetDataverseFeaturedItemCommand(createDataverseRequest(getRequestUser(crc)), dataverseFeaturedItemServiceBean.findById(itemId)));
} catch (WrappedResponse wr) {
logger.warning("Cannot locate a dataverse featured item with id " + itemId);
return null;
}
try {
return dataverseFeaturedItemServiceBean.getImageFileAsInputStream(dataverseFeaturedItem);
} catch (IOException e) {
logger.warning("Error while obtaining the input stream for the image file associated with the dataverse featured item with id " + itemId);
return null;
}
}
}
Loading

0 comments on commit 78ac64b

Please sign in to comment.