Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions lib/persistence/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,13 @@ async function updateLinkInDraft(req, data) {

async function editLinkInDraft(req, data) {
try {
await UPDATE(req.target).set({
linkUrl: data.linkUrl
}).where({ ID: data.ID });
const updateData = {
linkUrl: data.linkUrl
};
if (data.note !== undefined) {
updateData.note = data.note;
}
await UPDATE(req.target).set(updateData).where({ ID: data.ID });
} catch (err) {
if (req.error) {
req.error(500, `Failed to update the link: ${err.message}`);
Expand Down
100 changes: 99 additions & 1 deletion lib/sdm.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ module.exports = class SDMAttachmentsService extends (
) {
init() {
this.creds = this.options.credentials;
// Temporary storage for original URLs during draft editing
this.originalUrlMap = new Map();
return super.init();
}
getSDMCredentials() {
Expand Down Expand Up @@ -857,18 +859,112 @@ module.exports = class SDMAttachmentsService extends (
const status = response?.status || response?.code;

if (status === 200 || status === 201) {
let baselineUrl = existingAttachment.linkUrl;
const attachmentKey = `${attachmentId}`;
if (this.originalUrlMap.has(attachmentKey)) {
baselineUrl = this.originalUrlMap.get(attachmentKey);
} else {
this.originalUrlMap.set(attachmentKey, baselineUrl);
}

const updatedFields = {
ID: attachmentId,
linkUrl: newLinkUrl
linkUrl: newLinkUrl,
note: `__BASELINE_URL__:${baselineUrl}`
};
await editLinkInDraft(req, updatedFields);
return {
success: true,
message: "Link edited successfully"
};
} else if (status === 403) {
console.warn(`[editLink] user not authorised`, { user: req.user?.id, response: response?.response?.data });
req.reject(400, userNotAuthorisedErrorEditLink);
} else {
console.error(`[editLink] other error`, { message: response?.response?.data?.message, response: response.response.data });
req.reject(response?.response?.data?.message);
}
}
async handleDraftSaveForLinks(req) {
if (!req.target?.name) {
const entityPatterns = [
'ProcessorService.Incidents.attachments',
'ProcessorService.Incidents.attachments.drafts'
];

for (const entityName of entityPatterns) {
const attachmentsEntity = cds.model.definitions[entityName];
if (attachmentsEntity) {
await this.updateBaselinesForEntity(entityName);
}
}
}
}

async updateBaselinesForEntity(attachmentsEntityName) {
for (const [attachmentKey] of this.originalUrlMap.entries()) {
const attachment = await global.SELECT.one.from(attachmentsEntityName)
.where({
ID: attachmentKey,
mimeType: "application/internet-shortcut",
note: { like: "__BASELINE_URL__:%" }
});

if (attachment) {
this.originalUrlMap.set(attachmentKey, attachment.linkUrl);
await global.UPDATE(attachmentsEntityName)
.set({ note: null })
.where({ ID: attachmentKey });
}
}
}

async handleDraftDiscardForLinks(req) {
let parentId = req.data.ID;
const attachmentsEntityName = req.target.name.replace('.drafts', '.attachments.drafts');
const attachmentsEntity = cds.model.definitions[attachmentsEntityName];
const upKey = attachmentsEntity.keys?.up_?.keys?.[0]?.$generatedFieldName || 'up__ID';
const draftAttachments = await global.SELECT.from(attachmentsEntityName)
.where({
[upKey]: parentId,
mimeType: "application/internet-shortcut",
note: { like: "__BASELINE_URL__:%" }
});

const token = await fetchAccessToken(
this.creds,
req.user.authInfo?.token?.getTokenValue() || req.user.tokenInfo.getTokenValue()
);

for (const attachment of draftAttachments) {
if (attachment.note?.startsWith("__BASELINE_URL__:")) {
const baselineUrl = attachment.note.substring("__BASELINE_URL__:".length);

if (baselineUrl && attachment.linkUrl !== baselineUrl) {
await this.revertLinkInSDM(attachment, baselineUrl, token);
const attachmentKey = `${attachment.ID}`;
this.originalUrlMap.delete(attachmentKey);
}
}
}
}

async revertLinkInSDM(draftAttachment, originalLinkUrl, token) {
try {
const filenameToUpdate = draftAttachment.filename.replace(/\.url$/, '');
const objectIdToUpdate = draftAttachment.url;

await editLink(
objectIdToUpdate,
filenameToUpdate,
originalLinkUrl,
this.creds,
token
);
} catch (error) {
console.error(`[revertLinkInSDM] error reverting link for attachment ${draftAttachment.ID}:`, error.message);
throw error;
}
}

async handleRequest(response, objectId) {
Expand Down Expand Up @@ -904,6 +1000,8 @@ module.exports = class SDMAttachmentsService extends (
this.attachDraftDeletionData.bind(this)
);
srv.before(["DELETE"], [ target.drafts], this.attachURLsToDeleteFromAttachmentsDraft.bind(this));
srv.before("DELETE", entity.drafts, this.handleDraftDiscardForLinks.bind(this));
srv.after("SAVE", entity, this.handleDraftSaveForLinks.bind(this));
srv.before("READ", [target, target.drafts], this.setRepository.bind(this))
srv.before("READ", [target, target.drafts], this.filterAttachments.bind(this))
srv.before("SAVE", entity, this.renameHandler.bind(this));
Expand Down
Loading