2121import java .util .UUID ;
2222
2323import com .fasterxml .jackson .core .JsonProcessingException ;
24- import com .fasterxml .jackson .databind .JsonMappingException ;
2524import com .fasterxml .jackson .databind .ObjectMapper ;
2625import org .apache .commons .collections4 .CollectionUtils ;
2726import org .apache .commons .lang3 .StringUtils ;
4847import org .dspace .services .ConfigurationService ;
4948import org .dspace .services .factory .DSpaceServicesFactory ;
5049import org .dspace .utils .DSpace ;
50+ import org .dspace .versioning .Version ;
51+ import org .dspace .versioning .VersionHistory ;
52+ import org .dspace .versioning .factory .VersionServiceFactory ;
53+ import org .dspace .versioning .service .VersionHistoryService ;
5154import org .dspace .web .ContextUtil ;
5255
5356/**
@@ -63,6 +66,9 @@ public class LDNMessageConsumer implements Consumer {
6366 private ConfigurationService configurationService ;
6467 private ItemService itemService ;
6568 private BitstreamService bitstreamService ;
69+ private final String RESUBMISSION_SUFFIX = "-resubmission" ;
70+ private final String ENDORSEMENT_PATTERN = "request-endorsement" ;
71+ private final String REVIEW_PATTERN = "request-review" ;
6672
6773 @ Override
6874 public void initialize () throws Exception {
@@ -83,17 +89,34 @@ public void consume(Context context, Event event) throws Exception {
8389 }
8490
8591 Item item = (Item ) event .getSubject (context );
92+ if (item == null ) {
93+ return ;
94+ }
8695 createManualLDNMessages (context , item );
8796 createAutomaticLDNMessages (context , item );
8897 }
8998
9099 private void createManualLDNMessages (Context context , Item item ) throws SQLException , JsonProcessingException {
91100 List <NotifyPatternToTrigger > patternsToTrigger =
92101 notifyPatternToTriggerService .findByItem (context , item );
102+ // Note that multiple patterns can be submitted and not all support resubmission
103+ // 1. Extract all patterns that accept resubmissions, i.e. endorsement and review
104+ List <Integer > patternsSupportingResubmission = patternsToTrigger .stream ()
105+ .filter (p -> p .getPattern ().equals (REVIEW_PATTERN ) || p .getPattern ().equals (ENDORSEMENT_PATTERN ))
106+ .map (NotifyPatternToTrigger ::getID ).toList ();
107+
108+ String resubmissionReplyToID = null ;
93109
94110 for (NotifyPatternToTrigger patternToTrigger : patternsToTrigger ) {
111+ // Only try to fetch resubmission ID if the pattern support resubmission
112+ if (patternsSupportingResubmission .contains (patternToTrigger .getID ())) {
113+ resubmissionReplyToID = findResubmissionReplyToUUID (context , item , patternToTrigger .getNotifyService ());
114+ }
115+
95116 createLDNMessage (context ,patternToTrigger .getItem (),
96- patternToTrigger .getNotifyService (), patternToTrigger .getPattern ());
117+ patternToTrigger .getNotifyService (),
118+ patternToTrigger .getPattern (),
119+ resubmissionReplyToID );
97120 }
98121 }
99122
@@ -104,9 +127,31 @@ private void createAutomaticLDNMessages(Context context, Item item) throws SQLEx
104127 for (NotifyServiceInboundPattern inboundPattern : inboundPatterns ) {
105128 if (StringUtils .isEmpty (inboundPattern .getConstraint ()) ||
106129 evaluateFilter (context , item , inboundPattern .getConstraint ())) {
107- createLDNMessage (context , item , inboundPattern .getNotifyService (), inboundPattern .getPattern ());
130+ createLDNMessage (context , item , inboundPattern .getNotifyService (),
131+ inboundPattern .getPattern (), null );
132+ }
133+ }
134+ }
135+
136+ private String findResubmissionReplyToUUID (Context context , Item item , NotifyServiceEntity service )
137+ throws SQLException {
138+ // 1.1 Check whether this is a new version submission
139+ VersionHistoryService versionHistoryService = VersionServiceFactory .getInstance ()
140+ .getVersionHistoryService ();
141+ VersionHistory versionHistory = versionHistoryService .findByItem (context , item );
142+
143+ if (versionHistory != null ) {
144+ Version currentVersion = versionHistoryService .getVersion (context , versionHistory , item );
145+ Version previousVersion = versionHistoryService .getPrevious (context , versionHistory , currentVersion );
146+ if (previousVersion != null ) {
147+ // 1.2 and a TentativeReject notification, matching the current pattern's service, was received for the
148+ // previous item version
149+ return ldnMessageService .findEndorsementOrReviewResubmissionIdByItem (context ,
150+ previousVersion .getItem (), service );
108151 }
109152 }
153+ // New submission (new item, or previous version with a tentativeReject notification not found)
154+ return null ;
110155 }
111156
112157 private boolean evaluateFilter (Context context , Item item , String constraint ) {
@@ -116,19 +161,37 @@ private boolean evaluateFilter(Context context, Item item, String constraint) {
116161 return filter != null && filter .getResult (context , item );
117162 }
118163
119- private void createLDNMessage (Context context , Item item , NotifyServiceEntity service , String pattern )
120- throws SQLException , JsonMappingException , JsonProcessingException {
121-
122- LDN ldn = getLDNMessage (pattern );
164+ private void createLDNMessage (Context context , Item item , NotifyServiceEntity service , String pattern ,
165+ String resubmissionID )
166+ throws SQLException , JsonProcessingException {
167+ // Amend current pattern name to trigger
168+ // Endorsement or Review offer resubmissions: append '-resubmission' to pattern name to choose the correct
169+ // LDN message template: e.g. request-endorsement-resubmission or request-review-resubmission
170+ LDN ldn = (resubmissionID != null )
171+ ? getLDNMessage (pattern + RESUBMISSION_SUFFIX ) : getLDNMessage (pattern );
123172 LDNMessageEntity ldnMessage =
124- ldnMessageService .create (context , format ("urn:uuid:%s" , UUID .randomUUID ()));
173+ ldnMessageService .create (context , format ("urn:uuid:%s" , UUID .randomUUID ()));
125174
126175 ldnMessage .setObject (item );
127176 ldnMessage .setTarget (service );
128177 ldnMessage .setQueueStatus (LDNMessageEntity .QUEUE_STATUS_QUEUED );
129178 ldnMessage .setQueueTimeout (Instant .now ());
130179
131- appendGeneratedMessage (ldn , ldnMessage , pattern );
180+ String actorID = null ;
181+ if (service .isUsesActorEmailId ()) {
182+ // If the service has been configured to use actorEmailId, we use the submitter's email and name
183+ if (item .getSubmitter () != null ) {
184+ actorID = item .getSubmitter ().getEmail ();
185+ } else {
186+ // Use configured fallback email (defaults to mail.admin property)
187+ actorID = configurationService .getProperty ("ldn.notification.email.submitter.fallback" );
188+ }
189+ }
190+ appendGeneratedMessage (ldn ,
191+ ldnMessage ,
192+ actorID ,
193+ (actorID != null && item .getSubmitter () != null ) ? item .getSubmitter ().getFullName () : null ,
194+ resubmissionID );
132195
133196 ObjectMapper mapper = new ObjectMapper ();
134197 Notification notification = mapper .readValue (ldnMessage .getMessage (), Notification .class );
@@ -139,6 +202,10 @@ private void createLDNMessage(Context context, Item item, NotifyServiceEntity se
139202 Collections .sort (notificationTypeArrayList );
140203 ldnMessage .setActivityStreamType (notificationTypeArrayList .get (0 ));
141204 ldnMessage .setCoarNotifyType (notificationTypeArrayList .get (1 ));
205+ // If a resubmission, set inReplyTo
206+ if (resubmissionID != null ) {
207+ ldnMessage .setInReplyTo (ldnMessageService .find (context , resubmissionID ));
208+ }
142209
143210 ldnMessageService .update (context , ldnMessage );
144211 }
@@ -151,11 +218,16 @@ private LDN getLDNMessage(String pattern) {
151218 }
152219 }
153220
154- private void appendGeneratedMessage (LDN ldn , LDNMessageEntity ldnMessage , String pattern ) {
221+ private void appendGeneratedMessage (LDN ldn , LDNMessageEntity ldnMessage , String actorID , String actorName ,
222+ String resubmissionId ) {
155223 Item item = (Item ) ldnMessage .getObject ();
156- ldn .addArgument (getUiUrl ());
224+ if (actorID != null ) {
225+ ldn .addArgument ("mailto:" + actorID );
226+ } else {
227+ ldn .addArgument (getUiUrl ());
228+ }
157229 ldn .addArgument (configurationService .getProperty ("ldn.notify.inbox" ));
158- ldn .addArgument (configurationService .getProperty ("dspace.name" ));
230+ ldn .addArgument (actorName != null ? actorName : configurationService .getProperty ("dspace.name" ));
159231 ldn .addArgument (Objects .requireNonNullElse (ldnMessage .getTarget ().getUrl (), "" ));
160232 ldn .addArgument (Objects .requireNonNullElse (ldnMessage .getTarget ().getLdnUrl (), "" ));
161233 ldn .addArgument (getUiUrl () + "/handle/" + ldnMessage .getObject ().getHandle ());
@@ -166,6 +238,17 @@ private void appendGeneratedMessage(LDN ldn, LDNMessageEntity ldnMessage, String
166238 ldn .addArgument (getRelationUri (item ));
167239 ldn .addArgument ("http://purl.org/vocab/frbr/core#supplement" );
168240 ldn .addArgument (format ("urn:uuid:%s" , UUID .randomUUID ()));
241+ if (actorID != null ) {
242+ ldn .addArgument ("Person" );
243+ } else {
244+ ldn .addArgument ("Service" );
245+ }
246+ // Param 14: UI URL, LDN message origin
247+ ldn .addArgument (getUiUrl ());
248+ // Param 15: inReplyTo ID, used in endorsement resubmission notifications
249+ if (resubmissionId != null ) {
250+ ldn .addArgument (String .format ("\" inReplyTo\" : \" %s\" ," , resubmissionId ));
251+ }
169252
170253 ldnMessage .setMessage (ldn .generateLDNMessage ());
171254 }
0 commit comments