55import com .fasterxml .jackson .databind .JsonNode ;
66import com .fasterxml .jackson .databind .ObjectMapper ;
77import com .sap .cds .Result ;
8+ import com .sap .cds .Row ;
89import com .sap .cds .feature .attachments .service .AttachmentService ;
910import com .sap .cds .ql .Insert ;
11+ import com .sap .cds .ql .Select ;
1012import com .sap .cds .ql .Update ;
1113import com .sap .cds .ql .cqn .CqnAnalyzer ;
1214import com .sap .cds .ql .cqn .CqnSelect ;
1618import com .sap .cds .reflect .CdsModel ;
1719import com .sap .cds .sdm .constants .SDMConstants ;
1820import com .sap .cds .sdm .handler .TokenHandler ;
21+ import com .sap .cds .sdm .handler .applicationservice .helper .AttachmentsHandlerUtils ;
1922import com .sap .cds .sdm .model .*;
2023import com .sap .cds .sdm .persistence .DBQuery ;
2124import com .sap .cds .sdm .service .DocumentUploadService ;
2528import com .sap .cds .services .EventContext ;
2629import com .sap .cds .services .ServiceException ;
2730import com .sap .cds .services .cds .ApplicationService ;
31+ import com .sap .cds .services .draft .DraftCancelEventContext ;
2832import com .sap .cds .services .draft .DraftService ;
2933import com .sap .cds .services .handler .EventHandler ;
34+ import com .sap .cds .services .handler .annotations .Before ;
3035import com .sap .cds .services .handler .annotations .On ;
3136import com .sap .cds .services .handler .annotations .ServiceName ;
3237import com .sap .cds .services .persistence .PersistenceService ;
@@ -96,6 +101,180 @@ public void edit(EventContext context) throws IOException {
96101 editLink (context );
97102 }
98103
104+ @ Before (event = DraftService .EVENT_DRAFT_CANCEL )
105+ public void handleDraftDiscardForLinks (DraftCancelEventContext context ) throws IOException {
106+ CdsEntity parentDraftEntity = context .getTarget ();
107+ CqnAnalyzer analyzer = CqnAnalyzer .create (context .getModel ());
108+ Map <String , Object > parentKeys = analyzer .analyze (context .getCqn ()).rootKeys ();
109+ String parentEntityName = parentDraftEntity .getQualifiedName ().replace ("_drafts" , "" );
110+
111+ Optional <CdsEntity > parentActiveEntityOpt = context .getModel ().findEntity (parentEntityName );
112+ Map <String , String > compositionPathMapping =
113+ parentActiveEntityOpt
114+ .map (
115+ cdsEntity ->
116+ AttachmentsHandlerUtils .getAttachmentPathMapping (
117+ context .getModel (), cdsEntity , persistenceService ))
118+ .orElse (new HashMap <>());
119+
120+ for (Map .Entry <String , String > entry : compositionPathMapping .entrySet ()) {
121+ String attachmentCompositionDefinition = entry .getKey ();
122+ revertLinksForComposition (context , parentKeys , attachmentCompositionDefinition );
123+ }
124+ revertNestedEntityLinks (context );
125+ }
126+
127+ private void revertNestedEntityLinks (DraftCancelEventContext context ) throws IOException {
128+
129+ CdsEntity parentDraftEntity = context .getTarget ();
130+ String parentEntityName = parentDraftEntity .getQualifiedName ().replace ("_drafts" , "" );
131+ Optional <CdsEntity > parentActiveEntityOpt = context .getModel ().findEntity (parentEntityName );
132+
133+ if (parentActiveEntityOpt .isPresent ()) {
134+ CdsEntity parentActiveEntity = parentActiveEntityOpt .get ();
135+
136+ parentActiveEntity
137+ .compositions ()
138+ .forEach (
139+ composition -> {
140+ try {
141+ processNestedEntityComposition (context , composition );
142+ } catch (IOException e ) {
143+ throw new RuntimeException (e );
144+ }
145+ });
146+ }
147+ }
148+
149+ private void processNestedEntityComposition (
150+ DraftCancelEventContext context , CdsElement composition ) throws IOException {
151+
152+ CdsAssociationType associationType = (CdsAssociationType ) composition .getType ();
153+ String targetEntityName = associationType .getTarget ().getQualifiedName ();
154+ String draftTargetEntityName = targetEntityName + "_drafts" ;
155+
156+ Optional <CdsEntity > nestedDraftEntity = context .getModel ().findEntity (draftTargetEntityName );
157+
158+ if (nestedDraftEntity .isPresent ()) {
159+ Map <String , String > nestedAttachmentMapping =
160+ AttachmentsHandlerUtils .getAttachmentPathMapping (
161+ context .getModel (), associationType .getTarget (), persistenceService );
162+
163+ if (nestedAttachmentMapping .isEmpty ()) {
164+ return ;
165+ }
166+
167+ Result nestedRecords =
168+ persistenceService .run (
169+ Select .from (nestedDraftEntity .get ())
170+ .columns ("ID" )
171+ .where (e -> e .get ("IsActiveEntity" ).eq (false )));
172+
173+ for (Row nestedRecord : nestedRecords ) {
174+ Object nestedEntityId = nestedRecord .get ("ID" );
175+
176+ Map <String , Object > nestedEntityKeys = new HashMap <>();
177+ nestedEntityKeys .put ("ID" , nestedEntityId );
178+ nestedEntityKeys .put ("IsActiveEntity" , false );
179+
180+ for (Map .Entry <String , String > entry : nestedAttachmentMapping .entrySet ()) {
181+ String attachmentPath = entry .getKey ();
182+ revertLinksForComposition (context , nestedEntityKeys , attachmentPath );
183+ }
184+ }
185+ }
186+ }
187+
188+ private void revertLinksForComposition (
189+ DraftCancelEventContext context ,
190+ Map <String , Object > parentKeys ,
191+ String attachmentCompositionDefinition )
192+ throws IOException {
193+
194+ CdsModel model = context .getModel ();
195+ String draftEntityName = attachmentCompositionDefinition + "_drafts" ;
196+ CdsEntity draftEntity = model .findEntity (draftEntityName ).get ();
197+ CdsEntity activeEntity = model .findEntity (attachmentCompositionDefinition ).get ();
198+
199+ String upIdKey = getUpIdKey (draftEntity );
200+ String parentKeyName = upIdKey .replaceFirst ("^up__" , "" );
201+ Object parentId = parentKeys .get (parentKeyName );
202+
203+ CqnSelect selectDraftLinks =
204+ Select .from (draftEntity )
205+ .where (
206+ a ->
207+ a .get (upIdKey )
208+ .eq (parentId )
209+ .and (a .get ("mimeType" ).eq (SDMConstants .MIMETYPE_INTERNET_SHORTCUT ))
210+ .and (a .get ("IsActiveEntity" ).eq (false )));
211+
212+ Result draftLinks = persistenceService .run (selectDraftLinks );
213+ SDMCredentials sdmCredentials = tokenHandler .getSDMCredentials ();
214+ Boolean isSystemUser = context .getUserInfo ().isSystemUser ();
215+
216+ for (Row draftLinkRow : draftLinks ) {
217+ Map <String , Object > draftLink = new HashMap <>();
218+ draftLink .put ("ID" , draftLinkRow .get ("ID" ));
219+ draftLink .put ("linkUrl" , draftLinkRow .get ("linkUrl" ));
220+ draftLink .put ("objectId" , draftLinkRow .get ("objectId" ));
221+ draftLink .put ("fileName" , draftLinkRow .get ("fileName" ));
222+ String attachmentId = (String ) draftLink .get ("ID" );
223+ String draftLinkUrl = (String ) draftLink .get ("linkUrl" );
224+ String objectId = (String ) draftLink .get ("objectId" );
225+ String filename = (String ) draftLink .get ("fileName" );
226+
227+ String originalUrl =
228+ getOriginalUrlFromActiveTable (activeEntity , attachmentId , parentId , upIdKey );
229+
230+ if (originalUrl != null && !originalUrl .equals (draftLinkUrl )) {
231+ revertLinkInSDM (objectId , filename , originalUrl , sdmCredentials , isSystemUser );
232+ }
233+ }
234+ }
235+
236+ private String getOriginalUrlFromActiveTable (
237+ CdsEntity activeEntity , String attachmentId , Object parentId , String upIdKey ) {
238+ CqnSelect selectActiveLink =
239+ Select .from (activeEntity )
240+ .columns ("linkUrl" )
241+ .where (
242+ a ->
243+ a .get ("ID" )
244+ .eq (attachmentId )
245+ .and (a .get (upIdKey ).eq (parentId ))
246+ .and (a .get ("IsActiveEntity" ).eq (true ))
247+ .and (a .get ("mimeType" ).eq (SDMConstants .MIMETYPE_INTERNET_SHORTCUT )));
248+
249+ Result activeResult = persistenceService .run (selectActiveLink );
250+
251+ if (activeResult .rowCount () > 0 ) {
252+ Row activeRow = activeResult .single ();
253+ String originalUrl =
254+ activeRow .get ("linkUrl" ) != null ? activeRow .get ("linkUrl" ).toString () : null ;
255+ return originalUrl ;
256+ } else {
257+ return null ;
258+ }
259+ }
260+
261+ private void revertLinkInSDM (
262+ String objectId ,
263+ String filename ,
264+ String originalUrl ,
265+ SDMCredentials sdmCredentials ,
266+ Boolean isSystemUser )
267+ throws IOException {
268+
269+ CmisDocument cmisDocToRevert = new CmisDocument ();
270+ cmisDocToRevert .setObjectId (objectId );
271+ cmisDocToRevert .setFileName (filename );
272+
273+ cmisDocToRevert .setUrl (originalUrl );
274+ cmisDocToRevert .setRepositoryId (SDMConstants .REPOSITORY_ID );
275+ sdmService .editLink (cmisDocToRevert , sdmCredentials , isSystemUser );
276+ }
277+
99278 @ On (event = "openAttachment" )
100279 public void openAttachment (AttachmentReadContext context ) throws Exception {
101280 CdsModel cdsModel = context .getModel ();
@@ -115,7 +294,7 @@ public void openAttachment(AttachmentReadContext context) throws Exception {
115294 cmisDocument =
116295 dbQuery .getObjectIdForAttachmentID (attachmentEntity .get (), persistenceService , id );
117296 }
118- if (cmisDocument .getMimeType ().equalsIgnoreCase ("application/internet-shortcut" )) {
297+ if (cmisDocument .getMimeType ().equalsIgnoreCase (SDMConstants . MIMETYPE_INTERNET_SHORTCUT )) {
119298 context .setResult (cmisDocument .getUrl ());
120299 } else {
121300 context .setResult ("None" );
@@ -169,7 +348,7 @@ private void createLink(EventContext context) throws IOException {
169348 CmisDocument cmisDocument = new CmisDocument ();
170349 cmisDocument .setFolderId (folderId );
171350 cmisDocument .setFileName (filenameInRequest );
172- cmisDocument .setMimeType ("application/internet-shortcut" );
351+ cmisDocument .setMimeType (SDMConstants . MIMETYPE_INTERNET_SHORTCUT );
173352 cmisDocument .setRepositoryId (repositoryId );
174353 cmisDocument .setUrl (context .get ("url" ).toString ());
175354
0 commit comments