I'm currently working on integrating my ticketing system, which is based on SharePoint with SPFx Form Customizer, with Azure DevOps. I'm facing an issue with file attachments: when I upload files, they appear to be broken and cannot be opened in Azure DevOps.
type export default class AzureDevOpsService {
constructor(organization, project, pat) {
this.organization = organization;
this.project = project;
this.pat = pat;
}
async createTask(title, description, attachments) {
const url = `https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/workitems/$Task?api-version=7.1-preview.3`;
const taskData = [
{
op: 'add',
path: '/fields/System.Title',
value: title
},
{
op: 'add',
path: '/fields/System.Description',
value: description
}
];
try {
// Създаване на таска в Azure DevOps
const responseTask = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json-patch+json',
'Authorization': `Basic ${btoa(`:${this.pat}`)}`
},
body: JSON.stringify(taskData)
});
if (!responseTask.ok) {
const errorText = await responseTask.text();
console.error('Error creating a task:', errorText);
throw new Error('Error creating a task');
}
const resultTask = await responseTask.json();
for (const attachment of attachments) {
const attachmentUrl = `https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/attachments?fileName=${encodeURIComponent(attachment.FileName)}&uploadType=simple&api-version=7.1-preview.3`;
const responseAttachment = await fetch(attachmentUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream; charset=utf-8',
'Authorization': `Basic ${btoa(`:${this.pat}`)}`
},
body: attachment.Content
});
if (!responseAttachment.ok) {
const errorText = await responseAttachment.text();
console.error('Error uploading attachment:', errorText);
throw new Error('Error uploading attachment');
}
const resultAttachment = await responseAttachment.json();
const linkUrl = `https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/workitems/${resultTask.id}?api-version=7.1-preview.3`;
const linkData = [
{
op: 'add',
path: '/relations/-',
value: {
rel: 'AttachedFile',
url: resultAttachment.url,
attributes: {
comment: 'Attached File'
}
}
}
];
await fetch(linkUrl, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json-patch+json',
'Authorization': `Basic ${btoa(`:${this.pat}`)}`
},
body: JSON.stringify(linkData)
});
}
return resultTask;
} catch (error) {
console.error('Unexpected error:', error);
throw error;
}
}
}
i tried converting to blob, but it didn`t work
Found a solution that worked, thanks to Bright Ran-MSFT's help! First I convert to Base64 string, then convert the Base64 string back into a Blob:
for (const attachment of attachments) {
// Fetch the file from the URL
const response = await fetch(attachment.Content.DecodedUrl);
const arrayBuffer = await response.arrayBuffer();
const bytes = new Uint8Array(arrayBuffer);
// Convert the file content into a Base64 string
let base64content = '';
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
base64content += String.fromCharCode(bytes[i]);
}
base64content = window.btoa(base64content);
// Convert the Base64 string back into a Blob
const byteCharacters = atob(base64content);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], {type: 'application/octet-stream'});
const attachmentUrl = `https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/attachments?fileName=${encodeURIComponent(attachment.FileName)}&uploadType=simple&api-version=7.1-preview.3`;
const responseAttachment = await fetch(attachmentUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
'Authorization': `Basic ${btoa(`:${this.pat}`)}`
},
body: blob
});
}