diff --git a/dspace-api/src/main/java/org/dspace/eperson/FrequencySubscriptionParameter.java b/dspace-api/src/main/java/org/dspace/eperson/FrequencySubscriptionParameter.java new file mode 100644 index 0000000000..e735c96948 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/eperson/FrequencySubscriptionParameter.java @@ -0,0 +1,12 @@ +package org.dspace.eperson; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +/** + * @author Alba Aliu (alba.aliu at alba.aliu@atis.al) + * + */ +@Entity +@DiscriminatorValue("FREQUENCY") +public class FrequencySubscriptionParameter extends SubscriptionParameter { +} diff --git a/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java b/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java index 9e5ecaa4fb..b8f5d8be34 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java +++ b/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java @@ -120,7 +120,7 @@ public class SubscribeCLITool { collections = new ArrayList<>(); } - collections.add(subscription.getCollection()); + collections.add((Collection) subscription.getdSpaceObject()); } // Process the last person diff --git a/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java index 81c367f0ea..21890baf9e 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java @@ -2,7 +2,7 @@ * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at - * + *

* http://www.dspace.org/license/ */ package org.dspace.eperson; @@ -14,6 +14,7 @@ import org.apache.logging.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; import org.dspace.content.service.CollectionService; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -36,7 +37,6 @@ public class SubscribeServiceImpl implements SubscribeService { @Autowired(required = true) protected SubscriptionDAO subscriptionDAO; - @Autowired(required = true) protected AuthorizeService authorizeService; @Autowired(required = true) @@ -52,20 +52,27 @@ public class SubscribeServiceImpl implements SubscribeService { } @Override - public void subscribe(Context context, EPerson eperson, - Collection collection) throws SQLException, AuthorizeException { + public Subscription subscribe(Context context, EPerson eperson, + DSpaceObject dSpaceObject, + List subscriptionParameterList, + String type) throws SQLException, AuthorizeException { // Check authorisation. Must be administrator, or the eperson. if (authorizeService.isAdmin(context) - || ((context.getCurrentUser() != null) && (context - .getCurrentUser().getID().equals(eperson.getID())))) { - if (!isSubscribed(context, eperson, collection)) { - Subscription subscription = subscriptionDAO.create(context, new Subscription()); - subscription.setCollection(collection); - subscription.setePerson(eperson); + || ((context.getCurrentUser() != null) && (context + .getCurrentUser().getID().equals(eperson.getID())))) { + if (!isSubscribed(context, eperson, dSpaceObject)) { + Subscription new_subscription = subscriptionDAO.create(context, new Subscription()); + new_subscription.setSubscriptionParameterList(subscriptionParameterList); + new_subscription.setePerson(eperson); + new_subscription.setdSpaceObject(dSpaceObject); + new_subscription.setType(type); + return new_subscription; + } else { + throw new IllegalArgumentException("Subscription already exists"); } } else { throw new AuthorizeException( - "Only admin or e-person themselves can subscribe"); + "Only admin or e-person themselves can subscribe"); } } @@ -74,8 +81,8 @@ public class SubscribeServiceImpl implements SubscribeService { Collection collection) throws SQLException, AuthorizeException { // Check authorisation. Must be administrator, or the eperson. if (authorizeService.isAdmin(context) - || ((context.getCurrentUser() != null) && (context - .getCurrentUser().getID().equals(eperson.getID())))) { + || ((context.getCurrentUser() != null) && (context + .getCurrentUser().getID().equals(eperson.getID())))) { if (collection == null) { // Unsubscribe from all subscriptionDAO.deleteByEPerson(context, eperson); @@ -88,25 +95,25 @@ public class SubscribeServiceImpl implements SubscribeService { } } else { throw new AuthorizeException( - "Only admin or e-person themselves can unsubscribe"); + "Only admin or e-person themselves can unsubscribe"); } } @Override public List getSubscriptions(Context context, EPerson eperson) - throws SQLException { + throws SQLException { return subscriptionDAO.findByEPerson(context, eperson); } @Override public List getAvailableSubscriptions(Context context) - throws SQLException { + throws SQLException { return getAvailableSubscriptions(context, null); } @Override public List getAvailableSubscriptions(Context context, EPerson eperson) - throws SQLException { + throws SQLException { List collections; if (eperson != null) { context.setCurrentUser(eperson); @@ -118,8 +125,8 @@ public class SubscribeServiceImpl implements SubscribeService { @Override public boolean isSubscribed(Context context, EPerson eperson, - Collection collection) throws SQLException { - return subscriptionDAO.findByCollectionAndEPerson(context, eperson, collection) != null; + DSpaceObject dSpaceObject) throws SQLException { + return subscriptionDAO.findByCollectionAndEPerson(context, eperson, dSpaceObject) != null; } @Override @@ -131,4 +138,46 @@ public class SubscribeServiceImpl implements SubscribeService { public void deleteByEPerson(Context context, EPerson ePerson) throws SQLException { subscriptionDAO.deleteByEPerson(context, ePerson); } + + @Override + public Subscription findById(Context context, int id) throws SQLException { + return subscriptionDAO.findByID(context, Subscription.class, id); + } + + @Override + public Subscription updateSubscription(Context context, Integer id, + EPerson eperson, + DSpaceObject dSpaceObject, + List subscriptionParameterList, + String type) throws SQLException, AuthorizeException { + // must be admin or the subscriber of the subscription + if (authorizeService.isAdmin(context, context.getCurrentUser()) || eperson.equals(context.getCurrentUser())) { + Subscription subscription = subscriptionDAO.findByID(context, Subscription.class, id); + subscription.setType(type); + subscription.setdSpaceObject(dSpaceObject); + subscription.setSubscriptionParameterList(subscriptionParameterList); + subscription.setePerson(eperson); + subscriptionDAO.save(context, subscription); + return subscription; + } else { + throw new AuthorizeException("Only admin or e-person themselves can edit the subscription"); + } + } + + @Override + public void deleteSubscription(Context context, Integer id) throws SQLException, AuthorizeException { + // initially find the eperson associated with the subscription + Subscription subscription = subscriptionDAO.findByID(context, Subscription.class, id); + if (subscription != null) { + // must be admin or the subscriber of the subscription + if (authorizeService.isAdmin(context, context.getCurrentUser()) || subscription.getePerson().equals(context.getCurrentUser())) { + subscriptionDAO.delete(context, subscription); + } else { + throw new AuthorizeException("Only admin or e-person themselves can delete the subscription"); + } + } else { + throw new IllegalArgumentException("Subscription with id" + id + "is not found"); + } + + } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/Subscription.java b/dspace-api/src/main/java/org/dspace/eperson/Subscription.java index 1719888ca8..ed1f50dd94 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/Subscription.java +++ b/dspace-api/src/main/java/org/dspace/eperson/Subscription.java @@ -7,6 +7,7 @@ */ package org.dspace.eperson; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; @@ -15,13 +16,19 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; +import java.util.ArrayList; +import java.util.List; + /** * Database entity representation of the subscription table * @@ -38,16 +45,21 @@ public class Subscription implements ReloadableEntity { private Integer id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "collection_id") - private Collection collection; + @JoinColumn(name = "dspace_object_id") + private DSpaceObject dSpaceObject; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "eperson_id") private EPerson ePerson; + @Column(name = "type") + private String type; + + @OneToMany(fetch = FetchType.EAGER, mappedBy = "subscription", cascade = CascadeType.ALL) + private List subscriptionParameterList = new ArrayList<>(); /** * Protected constructor, create object using: - * {@link org.dspace.eperson.service.SubscribeService#subscribe(Context, EPerson, Collection)} + * {@link org.dspace.eperson.service.SubscribeService#subscribe(Context, EPerson, DSpaceObject, List, String)} */ protected Subscription() { @@ -58,19 +70,39 @@ public class Subscription implements ReloadableEntity { return id; } - public Collection getCollection() { - return collection; + public DSpaceObject getdSpaceObject() { + return this.dSpaceObject; } - void setCollection(Collection collection) { - this.collection = collection; + void setDSpaceObject(DSpaceObject dSpaceObject) { + this.dSpaceObject = dSpaceObject; } public EPerson getePerson() { return ePerson; } - void setePerson(EPerson ePerson) { + public void setePerson(EPerson ePerson) { this.ePerson = ePerson; } + + public void setdSpaceObject(DSpaceObject dSpaceObject) { + this.dSpaceObject = dSpaceObject; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public List getSubscriptionParameterList() { + return subscriptionParameterList; + } + + public void setSubscriptionParameterList(List subscriptionList) { + this.subscriptionParameterList = subscriptionList; + } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/SubscriptionParameter.java b/dspace-api/src/main/java/org/dspace/eperson/SubscriptionParameter.java new file mode 100644 index 0000000000..c34dcb9c5d --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/eperson/SubscriptionParameter.java @@ -0,0 +1,70 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.eperson; + + +import javax.persistence.Column; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +/** + * Database entity representation of the subscription_parameter table + * + * @author Alba Aliu at atis.al + */ + +@Entity +@Table(name = "subscription_parameter") +@DiscriminatorColumn(name = "name") +public class SubscriptionParameter { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "subscription_parameter_seq") + @SequenceGenerator(name = "subscription_parameter_seq", sequenceName = "subscription_parameter_seq", allocationSize = 1) + @Column(name = "subscription_parameter_id", unique = true, nullable = false, insertable = true) + private Integer id; + @ManyToOne + @JoinColumn(name = "subscription_id") + private Subscription subscription; + @Column + private String name; + @Column + private String value; + + + public Subscription getSubscription() { + return subscription; + } + + public void setSubscription(Subscription subscription) { + this.subscription = subscription; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java b/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java index e9f2d57059..2547657ef6 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.List; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; @@ -30,13 +31,13 @@ public interface SubscriptionDAO extends GenericDAO { public List findByEPerson(Context context, EPerson eperson) throws SQLException; - public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection) - throws SQLException; + public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, DSpaceObject dSpaceObject) + throws SQLException; public void deleteByEPerson(Context context, EPerson eperson) throws SQLException; public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson) - throws SQLException; + throws SQLException; public List findAllOrderedByEPerson(Context context) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionParameterDAO.java b/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionParameterDAO.java new file mode 100644 index 0000000000..3a8556472d --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionParameterDAO.java @@ -0,0 +1,22 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.eperson.dao; + +import org.dspace.core.GenericDAO; +import org.dspace.eperson.SubscriptionParameter; + +/** + * Database Access Object interface class for the SubscriptionParamter object. + * The implementation of this class is responsible for all database calls for the SubscriptionParameter object and is + * autowired by spring + * This class should only be accessed from a single service and should never be exposed outside of the API + * + * @author Alba Aliu at atis.al + */ +public interface SubscriptionParameterDAO extends GenericDAO { +} diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java index 6f2cb4b4fb..81428f16b5 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java @@ -16,6 +16,7 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -47,17 +48,16 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO impl } @Override - public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection) - throws SQLException { + public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, DSpaceObject dSpaceObject) + throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); javax.persistence.criteria.CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); Root subscriptionRoot = criteriaQuery.from(Subscription.class); criteriaQuery.select(subscriptionRoot); - criteriaQuery - .where(criteriaBuilder.and(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson), - criteriaBuilder.equal(subscriptionRoot.get(Subscription_.collection), collection) - ) - ); + criteriaQuery.where(criteriaBuilder.and(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson), + criteriaBuilder.equal(subscriptionRoot.get(Subscription_.dSpaceObject), dSpaceObject) + ) + ); return singleResult(context, criteriaQuery); } @@ -80,7 +80,7 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO impl @Override public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson) - throws SQLException { + throws SQLException { String hqlQuery = "delete from Subscription where collection=:collection AND ePerson=:ePerson"; Query query = createQuery(context, hqlQuery); query.setParameter("collection", collection); @@ -90,17 +90,13 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO impl @Override public List findAllOrderedByEPerson(Context context) throws SQLException { - - CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); Root subscriptionRoot = criteriaQuery.from(Subscription.class); criteriaQuery.select(subscriptionRoot); - - List orderList = new ArrayList<>(1); + List orderList = new LinkedList<>(); orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.ePerson))); criteriaQuery.orderBy(orderList); - return list(context, criteriaQuery, false, Subscription.class, -1, -1); } } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionParameterDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionParameterDAOImpl.java new file mode 100644 index 0000000000..a13696cc5a --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionParameterDAOImpl.java @@ -0,0 +1,25 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.eperson.dao.impl; + +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.eperson.SubscriptionParameter; +import org.dspace.eperson.dao.SubscriptionParameterDAO; + +/** + * Hibernate implementation of the Database Access Object interface class for the SubscriptionParameter object. + * This class is responsible for all database calls for the SubscriptionParameter object and is autowired by spring + * This class should never be accessed directly. + * + * @author Alba Aliu at atis.al + */ +public class SubscriptionParameterDAOImpl extends AbstractHibernateDAO implements SubscriptionParameterDAO { + protected SubscriptionParameterDAOImpl() { + super(); + } +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java b/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java index 347c69bf5b..5ff92eab5b 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java +++ b/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java @@ -2,7 +2,7 @@ * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at - * + *

* http://www.dspace.org/license/ */ package org.dspace.eperson.service; @@ -12,9 +12,11 @@ import java.util.List; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Subscription; +import org.dspace.eperson.SubscriptionParameter; /** * Service interface class for the Subscription object. @@ -41,14 +43,14 @@ public interface SubscribeService { * new item appears in the collection. * * @param context DSpace context - * @param eperson EPerson to subscribe - * @param collection Collection to subscribe to * @throws SQLException An exception that provides information on a database access error or other errors. * @throws AuthorizeException Exception indicating the current user of the context does not have permission * to perform a particular action. */ - public void subscribe(Context context, EPerson eperson, - Collection collection) throws SQLException, AuthorizeException; + public Subscription subscribe(Context context, EPerson eperson, + DSpaceObject dSpaceObject, + List subscriptionParameterList, + String type ) throws SQLException, AuthorizeException; /** * Unsubscribe an e-person to a collection. Passing in null @@ -83,7 +85,7 @@ public interface SubscribeService { * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getAvailableSubscriptions(Context context) - throws SQLException; + throws SQLException; /** * Find out which collections an e-person can subscribe to @@ -94,19 +96,19 @@ public interface SubscribeService { * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getAvailableSubscriptions(Context context, EPerson eperson) - throws SQLException; + throws SQLException; /** * Is that e-person subscribed to that collection? * * @param context DSpace context * @param eperson find out if this e-person is subscribed - * @param collection find out if subscribed to this collection + * @param dSpaceObject find out if subscribed to this dSpaceObject * @return true if they are subscribed * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean isSubscribed(Context context, EPerson eperson, - Collection collection) throws SQLException; + DSpaceObject dSpaceObject) throws SQLException; /** * Delete subscription by collection. @@ -125,4 +127,32 @@ public interface SubscribeService { * @throws SQLException An exception that provides information on a database access error or other errors. */ public void deleteByEPerson(Context context, EPerson ePerson) throws SQLException; + + /** + * Finds a subscription by id + * + * @param context DSpace context + * @param id the id of subscription to be searched + * @throws SQLException An exception that provides information on a database access error or other errors. + */ + public Subscription findById(Context context, int id) throws SQLException; + + /** + * Updates a subscription by id + * + * @param context DSpace context + * @throws SQLException An exception that provides information on a database access error or other errors. + */ + public Subscription updateSubscription(Context context, Integer id, EPerson eperson, + DSpaceObject dSpaceObject, + List subscriptionParameterList, + String type) throws SQLException, AuthorizeException; + + /** + * Deletes a subscription + * + * @param context DSpace context + * @throws SQLException An exception that provides information on a database access error or other errors. + */ + public void deleteSubscription(Context context, Integer id) throws SQLException, AuthorizeException; } diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql new file mode 100644 index 0000000000..69413b8807 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql @@ -0,0 +1,35 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +----------------------------------------------------------------------------------- +-- ADD table subscription_parameter +----------------------------------------------------------------------------------- + + +CREATE SEQUENCE subscription_parameter_seq; +CREATE TABLE subscription_parameter +( + subscription_parameter_id INTEGER NOT NULL, + parameter_name CHARACTER VARYING(255), + parameter_value CHARACTER VARYING(255), + subscription_id INTEGER NOT NULL, + CONSTRAINT subscription_parameter_pkey PRIMARY KEY (subscription_parameter_id), + CONSTRAINT subscription_parameter_subscription_fkey FOREIGN KEY (subscription_id) REFERENCES subscription (subscription_id) +); +-- -- +--ALTER TABLE subscription DROP CONSTRAINT subscription_collection_id_fkey; +---- -- +--ALTER TABLE subscription ALTER COLUMN collection_id RENAME TO dspace_object_id; +-- -- +ALTER TABLE subscription ADD COLUMN type CHARACTER VARYING(255); +---- -- +--ALTER TABLE subscription ADD CONSTRAINT subscription_dspaceobject_fkey FOREIGN KEY (dspace_object_id) REFERENCES dspaceobject(uuid); + + + + diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql new file mode 100644 index 0000000000..1fc1935eab --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql @@ -0,0 +1,37 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +----------------------------------------------------------------------------------- +-- ADD table subscription_parameter +----------------------------------------------------------------------------------- + + +CREATE SEQUENCE subscription_parameter_seq; +CREATE TABLE subscription_parameter +( + subscription_parameter_id INTEGER NOT NULL, + name VARCHAR(255), + value VARCHAR(255), + subscription_id INTEGER NOT NULL, + CONSTRAINT subscription_parameter_pkey PRIMARY KEY (subscription_parameter_id), + CONSTRAINT subscription_parameter_subscription_fkey FOREIGN KEY (subscription_id) + REFERENCES subscription (subscription_id) +); +-- -- + +--ALTER TABLE subscription DROP CONSTRAINT subscription_collection_id_fkey +------ -- +--ALTER TABLE subscription ALTER COLUMN collection_id RENAME TO dspace_object_id; +---- -- +ALTER TABLE subscription ADD COL +---- -- +--ALTER TABLE subscription ADD CONSTRAINT subscription_dspaceobject_fkey FOREIGN KEY (dspace_object_id) REFERENCES dspaceobject (uuid); +-- + + + diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql new file mode 100644 index 0000000000..bc382613ab --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2021.07.30__add_table_subscriptionparamter_change_columns_subscription_table.sql @@ -0,0 +1,35 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +----------------------------------------------------------------------------------- +-- ADD table subscription_parameter +----------------------------------------------------------------------------------- + + +CREATE SEQUENCE subscription_parameter_seq; +CREATE TABLE subscription_parameter +( + subscription_parameter_id INTEGER NOT NULL, + name CHARACTER VARYING(255), + value CHARACTER VARYING(255), + subscription_id INTEGER NOT NULL, + CONSTRAINT subscription_parameter_pkey PRIMARY KEY (subscription_parameter_id), + CONSTRAINT subscription_parameter_subscription_fkey FOREIGN KEY (subscription_id) REFERENCES subscription (subscription_id) +); +-- -- +--ALTER TABLE subscription DROP CONSTRAINT subscription_collection_id_fkey; +---- -- +--ALTER TABLE subscription RENAME COLUMN collection_id TO dspace_object_id; +---- -- +ALTER TABLE subscription ADD COLUMN type CHARACTER VARYING(255); +---- -- +--ALTER TABLE subscription ADD CONSTRAINT subscription_dspaceobject_fkey FOREIGN KEY (dspace_object_id) REFERENCES dspaceobject (uuid); +-- +-- +-- + diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubscriptionConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubscriptionConverter.java new file mode 100644 index 0000000000..6673f00cb1 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubscriptionConverter.java @@ -0,0 +1,50 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import org.dspace.app.rest.model.SubscriptionRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.app.rest.utils.Utils; +import org.dspace.eperson.Subscription; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * This is the converter from Entity CrisLayoutTab to the REST data model + * + * @author Danilo Di Nuzzo (danilo.dinuzzo at 4science.it) + * + */ +@Component +public class SubscriptionConverter implements DSpaceConverter { + @Autowired + protected Utils utils; + /* (non-Javadoc) + * @see org.dspace.app.rest.converter.DSpaceConverter#convert + * (java.lang.Object, org.dspace.app.rest.projection.Projection) + */ + @Autowired + private ConverterService converter; + @Override + public SubscriptionRest convert(Subscription subscription, Projection projection) { + SubscriptionRest rest = new SubscriptionRest(); + rest.setId(subscription.getID()); + rest.setSubscriptionParameterList(subscription.getSubscriptionParameterList()); + rest.setType(subscription.getType()); + return rest; + } + + /* (non-Javadoc) + * @see org.dspace.app.rest.converter.DSpaceConverter#getModelClass() + */ + @Override + public Class getModelClass() { + return Subscription.class; + } + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubscriptionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubscriptionRest.java new file mode 100644 index 0000000000..5bd9f074b4 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubscriptionRest.java @@ -0,0 +1,78 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + *

+ * http://www.dspace.org/license/ + */ + +package org.dspace.app.rest.model; + +import org.dspace.app.rest.RestResourceController; +import org.dspace.eperson.Subscription; +import org.dspace.eperson.SubscriptionParameter; + +import java.util.ArrayList; +import java.util.List; + +@LinksRest(links = { + @LinkRest( + name = SubscriptionRest.DSPACE_OBJECT, + method = "getDSpaceObject" + ), + @LinkRest( + name = SubscriptionRest.EPERSON, + method = "getEPerson" + ) +}) +public class SubscriptionRest extends BaseObjectRest{ + public static final String NAME = "subscription"; + public static final String NAME_PLURAL = "subscriptions"; + public static final String CATEGORY = "core"; + public static final String DSPACE_OBJECT = "dSpaceObject"; + public static final String EPERSON = "ePerson"; + + private Integer id; + private String type; + private List subscriptionParameterList = new ArrayList<>(); + + @Override + public String getCategory() { + return CATEGORY; + } + + @Override + public Class getController() { + return RestResourceController.class; + } + + @Override + public String getType() { + return NAME; + } + + public void setType(String type) { + this.type = type; + } + + public List getSubscriptionParameterList() { + return subscriptionParameterList; + } + + public void setSubscriptionParameterList(List subscriptionParameterList) { + this.subscriptionParameterList = subscriptionParameterList; + } + public String getSubscriptionType() { + return this.type; + } + + @Override + public Integer getId() { + return id; + } + + @Override + public void setId(Integer id) { + this.id = id; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubscriptionResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubscriptionResource.java new file mode 100644 index 0000000000..0f688e1b96 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubscriptionResource.java @@ -0,0 +1,22 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import org.dspace.app.rest.model.SubscriptionRest; +import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource; +import org.dspace.app.rest.utils.Utils; + +/** + * The Resource representation of a Script object + */ +@RelNameDSpaceResource(SubscriptionRest.NAME) +public class SubscriptionResource extends DSpaceResource { + public SubscriptionResource(SubscriptionRest data, Utils utils) { + super(data, utils); + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionDSpaceObjectLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionDSpaceObjectLinkRepository.java new file mode 100644 index 0000000000..0c4623f93b --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionDSpaceObjectLinkRepository.java @@ -0,0 +1,63 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + *

+ * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import org.apache.poi.poifs.crypt.DataSpaceMapUtils; +import org.dspace.app.rest.model.DSpaceObjectRest; +import org.dspace.app.rest.model.SubscriptionRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.dspace.eperson.Subscription; +import org.dspace.eperson.service.SubscribeService; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; +import javax.transaction.Transactional; +import java.sql.SQLException; + +/** + * Link repository for "mappedCollections" subresource of an individual item. + */ +@Component(SubscriptionRest.CATEGORY + "." + SubscriptionRest.NAME + "." + SubscriptionRest.DSPACE_OBJECT) +@Transactional +public class SubscriptionDSpaceObjectLinkRepository extends AbstractDSpaceRestRepository implements LinkRestRepository { + + @Autowired + SubscribeService subscribeService; + + @Autowired + ItemService itemService; + + public DSpaceObjectRest getDSpaceObject(@Nullable HttpServletRequest request, + Integer subscriptionId, + @Nullable Pageable optionalPageable, + Projection projection) { + try { + Context context = obtainContext(); + Subscription subscription = subscribeService.findById(context, subscriptionId); + if (subscription == null) { + throw new ResourceNotFoundException("No such subscription: " + subscriptionId); + } + HibernateProxy hibernateProxy = (HibernateProxy) subscription.getdSpaceObject(); + LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer(); + + return converter.toRest(initializer.getImplementation(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionEPersonLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionEPersonLinkRepository.java new file mode 100644 index 0000000000..6490498a33 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionEPersonLinkRepository.java @@ -0,0 +1,51 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import org.dspace.app.rest.model.EPersonRest; +import org.dspace.app.rest.model.SubscriptionRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.core.Context; +import org.dspace.eperson.Subscription; +import org.dspace.eperson.service.EPersonService; +import org.dspace.eperson.service.SubscribeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; +import java.sql.SQLException; + +/** + * Link repository for "mappedCollections" subresource of an individual item. + */ +@Component(SubscriptionRest.CATEGORY + "." + SubscriptionRest.NAME + "." + SubscriptionRest.EPERSON) +public class SubscriptionEPersonLinkRepository extends AbstractDSpaceRestRepository implements LinkRestRepository { + + @Autowired + SubscribeService subscribeService; + + public EPersonRest getEPerson(@Nullable HttpServletRequest request, + Integer subscriptionId, + @Nullable Pageable optionalPageable, + Projection projection) { + try { + Context context = obtainContext(); + Subscription subscription = subscribeService.findById(context, subscriptionId); + if (subscription == null) { + throw new ResourceNotFoundException("No such subscription: " + subscriptionId); + } + + return converter.toRest(subscription.getePerson(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionRestRepository.java new file mode 100644 index 0000000000..fd6812a4ca --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubscriptionRestRepository.java @@ -0,0 +1,171 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + *

+ * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dspace.app.rest.SearchRestMethod; +import org.dspace.app.rest.converter.ConverterService; +import org.dspace.app.rest.exception.UnprocessableEntityException; +import org.dspace.app.rest.model.SubscriptionRest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.DSpaceObject; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Subscription; +import org.dspace.eperson.service.EPersonService; +import org.dspace.eperson.service.SubscribeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + +/** + * This is the repository responsible to manage SubscriptionRest object + * + * @author Alba Aliu at atis.al + */ + +@Component(SubscriptionRest.CATEGORY + "." + SubscriptionRest.NAME) +public class SubscriptionRestRepository extends DSpaceRestRepository { + private static final Logger log = LogManager.getLogger(); + @Autowired + AuthorizeService authorizeService; + @Autowired + SubscribeService subscribeService; + @Autowired + protected ConverterService converter; + @Autowired + protected EPersonService personService; + @Autowired(required = true) + protected ContentServiceFactory contentServiceFactory; + + + @Override + @PreAuthorize("hasAuthority('ADMIN')") + public SubscriptionRest findOne(Context context, Integer id) { + try { + Subscription subscription = subscribeService.findById(context, id); + if (subscription == null) { + throw new ResourceNotFoundException("The subscription for ID: " + id + " could not be found"); + } + return converter.toRest(subscription, utils.obtainProjection()); + } catch (SQLException sqlException) { + throw new RuntimeException(sqlException.getMessage(), sqlException); + } + } + + @Override + @PreAuthorize("hasAuthority('ADMIN')") + public Page findAll(Context context, Pageable pageable) { + try { + List subscriptionList = subscribeService.findAll(context); + return converter.toRestPage(subscriptionList, pageable, utils.obtainProjection()); + } catch (SQLException sqlException) { + throw new RuntimeException(sqlException.getMessage(), sqlException); + } + } + + @SearchRestMethod(name = "findByEPerson") + public Page findAllByEPerson(Context context, String id) { + try { + EPerson ePerson = personService.findByNetid(context, id); + if (context.getCurrentUser().equals(ePerson) || authorizeService.isAdmin(context, ePerson)) { + List subscriptionList = subscribeService.getSubscriptions(context, ePerson); + return converter.toRest(subscriptionList, utils.obtainProjection()); + } else { + throw new AuthorizeException("Only admin or e-person themselves can search for it's subscription"); + } + } catch (SQLException | AuthorizeException sqlException) { + throw new RuntimeException(sqlException.getMessage(), sqlException); + } + } + + @Override + @PreAuthorize("isAuthenticated()") + protected SubscriptionRest createAndReturn(Context context) { + HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest(); + ObjectMapper mapper = new ObjectMapper(); + SubscriptionRest subscriptionRest = null; + DSpaceObject dSpaceObject = null; + try { + subscriptionRest = mapper.readValue(req.getInputStream(), SubscriptionRest.class); + } catch (IOException e1) { + throw new UnprocessableEntityException("error parsing the body"); + } + try { +// EPerson ePerson = personService.findByNetid(context, subscriptionRest.getePerson().getNetid()) ; + Subscription subscription = subscribeService.subscribe(context, null, + dSpaceObject, + subscriptionRest.getSubscriptionParameterList(), + subscriptionRest.getType()); + return converter.toRest(subscription, utils.obtainProjection()); + } catch (SQLException | AuthorizeException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + @Override + @PreAuthorize("isAuthenticated()") + protected SubscriptionRest put(Context context, HttpServletRequest request, String apiCategory, String model, + Integer id, JsonNode jsonNode) throws SQLException, AuthorizeException { + SubscriptionRest subscriptionRest = null; + try { + subscriptionRest = new ObjectMapper().readValue(jsonNode.toString(), SubscriptionRest.class); + } catch (IOException e) { + throw new UnprocessableEntityException("Error parsing subscription json: " + e.getMessage()); + } + Subscription subscription = null; + String notFoundException = "ResourceNotFoundException:" + apiCategory + "." + model + + " with id: " + id + " not found"; + try { + subscription = subscribeService.findById(context, id); + if (subscription == null) { + throw new ResourceNotFoundException(notFoundException); + } + } catch (SQLException e) { + throw new ResourceNotFoundException(notFoundException); + } + if (id.equals(subscriptionRest.getId())) { + subscription = subscribeService.updateSubscription(context, subscriptionRest.getId(), null, + null, subscriptionRest.getSubscriptionParameterList(), subscriptionRest.getType()); + return converter.toRest(subscription, utils.obtainProjection()); + } else { + throw new IllegalArgumentException("The id in the Json and the id in the url do not match: " + + id + ", " + + subscriptionRest.getId()); + } + } + + @Override + @PreAuthorize("isAuthenticated()") + public void delete(Context context, Integer id) { + try { + subscribeService.deleteSubscription(context, id); + } catch (SQLException | AuthorizeException sqlException) { + throw new RuntimeException(sqlException.getMessage(), sqlException); + } + } + + @Override + public Class getDomainClass() { + return SubscriptionRest.class; + } + +} diff --git a/dspace/config/hibernate.cfg.xml b/dspace/config/hibernate.cfg.xml index 085ed0bd6e..73002fc692 100644 --- a/dspace/config/hibernate.cfg.xml +++ b/dspace/config/hibernate.cfg.xml @@ -66,7 +66,7 @@ - +