I’m currently developing an automatic migration path for one of our Confluence plugins. The objective is to modify certain XML files after a successful migration. Our app retrieves the XML Attachments via the REST API, searches for specific strings (e.g., server Confluence page links), updates them using mapping data to their new migrated counterparts (e.g., Cloud Confluence pages), and then uploads them to the cloud. Surprisingly, this process doesn’t work on the first run but completes successfully on the second attempt:
First Execution: The corresponding REST API request for attachments returns no attachments, even though they are accessible on the cloud.
Second Execution: The corresponding REST API request for attachments returns all attachments as expected.
The current code functions as follows:
The cloud app listens for the listener-triggered and app-data-uploaded events of its server counterpart.
The cloud app queries all attachments and filters them based on specific file types.
The cloud app queries mappings with different namespaces.
The cloud app utilizes the mappings to update strings within the XML attachments.
The cloud app pushes the updated attachments to Confluence.
Example:
private async setMigrationNotification(req, res) {
try {
console.log(`Received listener-triggered event`);
// wait for event since app-data is not uploaded yet
if (req.body.eventType === "app-data-uploaded" && !this.appDataUploaded) {
console.log(`Received app-data-uploaded event`);
this.appDataUploaded = true;
this.transferId = req.body.transferId;
this.clientKeyId = req.body.migrationDetails.confluenceClientKey;
this.cloudUrl = req.body.migrationDetails.cloudUrl + "/wiki";
if (await this.getAppData("attachment-data")) {
console.log(`App data was uploaded successfully. We can start the migration process now...`);
// TEST:
const testAttachments = await this.confluenceApiService.getAllAttachments(this.getHttpClient(this.clientKeyId));
if (testAttachments) {
console.log(`Got ${testAttachments.length} Attachments`);
}
await this.updateProgress(this.transferId, MigrationStatusEnum.IN_PROGRESS, 0, "Starting migration process.");
await this.startAttachmentMigration();
}
console.log(`Returning status code 200 to migration server.`);
return res.status(HttpStatusCodeEnum.OK).json(true);
}
return res.status(HttpStatusCodeEnum.OK).json(true);
} catch (err) {
console.log(`Error ${err}`);
}
}
Is there something wrong with the code, or am I missing something else?
Thanks for your post. We recommend returning HTTP 2xx right away when you receive the message and then starting the work to process the files. This is because we expect a response within 5 seconds
You should queue the work for the actual processing with a slight delay (up to 60 seconds) as well to make sure the uploaded has completed in the AWS S3 bucket. Most of the back-end system are asynchronous and sometimes if you request the data right away it won’t be ready.
I know this isn’t ideal, but app migration ins’t a race to the end.
Thank you for your quick reply. I have made the changes you suggested. Unfortunately, the error persists. I am using the REST endpoint api/v2/attachments to retrieve all attachments from the migrated cloud site. Although I now wait 60 seconds before starting the migration process of our application, I can only retrieve the attachments of the default demonstration space.
Observations:
Surprisingly, when I request the endpoint via cURL with the administrator’s credentials, I can retrieve all attachments, while the app cannot.
If I perform the migration steps separately (first normal space and user migration without app migration and then the app migration without space and user migration), the app can retrieve all migrated attachments.
Can we see the code for this.confluenceApiService.getAllAttachments(this.getHttpClient(this.clientKeyId)); and this.startAttachmentMigration(); because that’s really where the action is happening.
I am not sure the root cause but what has been described sounds like perhaps the app does not have the authorization to retrieve the migrated attachments at that point in time but when you remigrate it manages to gain it later on.
I would need to reproduce this issue to know but currently it doesn’t sound like an ideal experience. We could try re-authenticating which may create a JWT with the right permissions.
To further investigate the issue, I’d like to clarify the steps to reproduce the problem. Here are the required steps:
Start app migration with multiple spaces, pages, and attachments
Query api/v2/attachments as app during app migration
If you require additional information or specific configurations, please let me know.
You suggested to re-authenticate to potentially generate a JWT with the correct permissions. Could you please provide the exact steps for re-authentication?
Could you please provide the exact steps for re-authentication?
I see you are probably using an Atlassian library which handles this so it would be difficult for you to do.
Let me try reproduce this so we have a common understanding are you just using something like this Bitbucket and what is your atlassian-connect.json in particular the scopes field?
I am using a test dataset with multiple spaces, pages, and attachments. During migration, the app can receive a minority of the attachments, but most are not accessible as previously described. I would guess that you need to test with more than one attachment. The test dataset I used contains more than 50 attachments.