Skip to content

Instantly share code, notes, and snippets.

@craigm26
Last active July 19, 2024 16:10
SharePoint Adobe integration library extension
# Goal: replicate the deprecated SharePoint-Adobe Integration
# setup 2 text columns in SharePoint where this action needs to be performed: "Adobe Sign Status" and "AgreementId"
# start a regular typescript project for SharePoint with the command set for library extensions.
https://learn.microsoft.com/en-us/sharepoint/dev/spfx/extensions/get-started/building-simple-cmdset-with-dialog-api
# have a (supposedly deprecated) Adobe Integration key handy.
https://na3.documents.adobe.com/account/accountSettingsPage#pageId::ACCESS_TOKENS
# you can use the client-to-server authentication method for app id and thats fine. Be wary of user clicks.
# best thing to do is (server-to-server authentication method) to start a project in developer portal in Adobe, enable Adobe Sign API and make curl request auth for a key.
# copy and paste the following code (then update the AdobeIntegrationKey), debug and gulp serve. Remove console.log messages before gulp package ship
import { Log } from '@microsoft/sp-core-library';
import {
BaseListViewCommandSet,
type Command,
type IListViewCommandSetExecuteEventParameters,
type ListViewStateChangedEventArgs
} from '@microsoft/sp-listview-extensibility';
import axios from 'axios';
import { spfi, SPFx as spSPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import { graphfi, SPFx as graphSPFx } from "@pnp/graph";
import "@pnp/sp/webs";
import "@pnp/graph/users";
export interface IAdobeSignCommandSetProperties {
sampleTextOne: string;
sampleTextTwo: string;
}
const LOG_SOURCE: string = 'AdobeSignCommandSet';
export default class AdobeSignCommandSet extends BaseListViewCommandSet<IAdobeSignCommandSetProperties> {
private sp: ReturnType<typeof spfi>;
private graph: ReturnType<typeof graphfi>;
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, 'Initialized AdobeSignCommandSet');
this.sp = spfi().using(spSPFx(this.context));
this.graph = graphfi().using(graphSPFx(this.context));
const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
if (compareOneCommand) {
compareOneCommand.visible = false;
}
const compareTwoCommand: Command = this.tryGetCommand('COMMAND_2');
if (compareTwoCommand) {
compareTwoCommand.visible = true;
}
const compareThreeCommand: Command = this.tryGetCommand('COMMAND_3');
if (compareThreeCommand) {
compareThreeCommand.visible = true;
}
const compareFourCommand: Command = this.tryGetCommand('COMMAND_4');
if (compareFourCommand) {
compareFourCommand.visible = true;
}
const compareFiveCommand: Command = this.tryGetCommand('COMMAND_5');
if (compareFiveCommand) {
compareFiveCommand.visible = true;
}
const compareSixCommand: Command = this.tryGetCommand('COMMAND_6');
if (compareSixCommand) {
compareSixCommand.visible = true;
}
this.context.listView.listViewStateChangedEvent.add(this, this._onListViewStateChanged);
document.addEventListener("DOMContentLoaded", async () => {
const urlParams = new URLSearchParams(window.location.search);
const documentUrl = decodeURIComponent(urlParams.get('state') || '');
const documentName = decodeURIComponent(urlParams.get('documentName') || '');
if (documentUrl) {
try {
const accessToken = await this._getAccessTokenMicrosoft();
const response = await this._uploadTransientDocument(documentUrl, accessToken, documentName);
if (response.data && response.data.transientDocumentId) {
// window.location.href = `https://na3.documents.adobe.com/public/compose?transientDocumentId=${response.data.transientDocumentId}`;
} else {
Log.error(LOG_SOURCE, new Error('Failed to upload transient document to Adobe Sign'));
}
} catch (error) {
Log.error(LOG_SOURCE, new Error('Error during Adobe Sign integration: ' + error.message));
}
}
});
return Promise.resolve();
}
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
console.log('Executing command: ', event.itemId);
switch (event.itemId) {
case 'COMMAND_1':
window.location.href = `https://www.adobe.com/`;
break;
case 'COMMAND_2':
window.location.href = `https://na3.documents.adobe.com/public/agreements`;
break;
case 'COMMAND_3':
console.log('COMMAND_3 is clicked');
if (this.context.listView.selectedRows && this.context.listView.selectedRows.length > 0) {
const selectedRow = this.context.listView.selectedRows[0];
if (selectedRow) {
console.log('Selected Row:', selectedRow);
const documentUrl = selectedRow.getValueByName('FileRef');
console.log('Document URL:', documentUrl);
const spItemUrl = selectedRow.getValueByName('.spItemUrl');
console.log('SP Item URL:', spItemUrl);
const documentNameWithExtension = selectedRow.getValueByName('FileLeafRef');
const documentName = this._getFileNameWithoutExtension(documentNameWithExtension);
const author = selectedRow.getValueByName('Author');
const agreementUserEmail = author[0].email;
console.log('agreementUserEmail:', agreementUserEmail);
const approverField = selectedRow.getValueByName('Approver');
const approverEmail = approverField && approverField.length > 0 ? approverField[0].email : agreementUserEmail;
console.log('Approver Email:', approverEmail);
const agreementId = selectedRow.getValueByName('AgreementID');
// if no agreementId - window.open(`https://na3.documents.adobe.com/public/compose?agrId=${agreementId}&client_id=UB7E5BXCXY`, '_blank');
if (selectedRow.getValueByName('AgreementID') && documentUrl) {
window.open(`https://na3.documents.adobe.com/public/compose?agrId=${agreementId}&client_id=UB7E5BXCXY`, '_blank');
}
// if there isn't an agreementId, AND it's a document set, then we need to create a set of transient documents
// first we need to determine if it's a document set by checking the content type value
// if it is a document set, we need to get all the documents in the set
const contentTypeId = selectedRow.getValueByName('ContentTypeId');
console.log('Content Type ID:', contentTypeId);
// now we need to create a new agreement by uploading the document to Adobe Sign as a transient document - content type is not Document
if (!selectedRow.getValueByName('AgreementID') && documentUrl && selectedRow.getValueByName('ContentTypeId').startsWith('0x0120')) {
const accessToken = 'AdobeIntegrationKey'
// The documentUrl is the URL of the document set, so we need to get all the documents in the set
this._uploadTransientDocumentDocSet(documentUrl, accessToken, spItemUrl).then((response) => {
console.log('Response:', response);
console.log('Transient Document IDs:', response.data.transientDocumentIds);
if (response.data) {
const transientDocumentIds = response.data.transientDocumentIds;
this._createDocSetAgreement(transientDocumentIds, agreementUserEmail, documentNameWithExtension, approverEmail).then((agreementId) => {
console.log('Agreement ID:', agreementId);
this._updateSharePointFieldAgreementId(selectedRow, agreementId).then(() => {
console.log('Agreement ID:', agreementId);
Log.info(LOG_SOURCE, `Agreement ID updated to: ${agreementId}`);
window.location.reload();
}).catch((error: { message: string; }) => {
console.log('Error:', error);
});
window.open(`https://na3.documents.adobe.com/public/compose?agrId=${agreementId}&client_id=UB7E5BXCXY`, '_blank');
}).catch((error) => {
Log.error(LOG_SOURCE, new Error('Failed to create agreement: ' + error.message));
});
}
}).catch((error) => {
Log.error(LOG_SOURCE, new Error('Failed to upload transient document: ' + error.message));
});
}
// this is the case where we have an agreementId, but it's not a document set
if (!selectedRow.getValueByName('AgreementID') && documentUrl && selectedRow.getValueByName('ContentTypeId').startsWith('0x0101')) {
const accessToken = 'AdobeIntegrationKey'
this._uploadTransientDocument(documentUrl, accessToken, documentName).then((response) => {
console.log('Response:', response);
console.log('Transient Document ID:', response.data.transientDocumentId);
if (response.data) {
console.log('Transient Document ID:', response.data.transientDocumentId);
const transientDocumentId = response.data.transientDocumentId;
this._createAgreement(transientDocumentId, agreementUserEmail, documentNameWithExtension, approverEmail).then((agreementId) => {
console.log('Agreement ID:', agreementId);
this._updateSharePointFieldAgreementId(selectedRow, agreementId).then(() => {
console.log('Agreement ID:', agreementId);
Log.info(LOG_SOURCE, `Agreement ID updated to: ${agreementId}`);
window.location.reload();
}).catch((error: { message: string; }) => {
console.log('Error:', error);
});
// new tab to open the agreement in Adobe Sign
// Open the agreement in Adobe Sign in a new tab
window.open(`https://na3.documents.adobe.com/public/compose?agrId=${agreementId}&client_id=UB7E5BXCXY`, '_blank');
}).catch((error) => {
Log.error(LOG_SOURCE, new Error('Failed to create agreement: ' + error.message));
});
}
}).catch((error) => {
Log.error(LOG_SOURCE, new Error('Failed to upload transient document: ' + error.message));
});
}
}
}
break;
case 'COMMAND_4':
console.log('COMMAND_4 is clicked');
if (this.context.listView.selectedRows && this.context.listView.selectedRows.length > 0) {
const selectedRow = this.context.listView.selectedRows[0];
const agreementId = selectedRow.getValueByName('AgreementID');
const author = selectedRow.getValueByName('Author');
console.log('Author:', author);
const agreementUserEmail = author[0].email;
console.log('Agreement User Email:', agreementUserEmail);
if (agreementId) {
this._fetchAgreementStatus(agreementId, agreementUserEmail).then(status => {
this._updateSharePointField(selectedRow, status).then(() => {
Log.info(LOG_SOURCE, `Agreement status updated to: ${status}`);
window.location.reload();
}).catch(error => {
Log.error(LOG_SOURCE, new Error('Failed to update agreement status in SharePoint: ' + error.message));
});
}).catch(error => {
Log.error(LOG_SOURCE, new Error('Failed to fetch agreement status from Adobe Sign: ' + error.message));
});
} else {
Log.error(LOG_SOURCE, new Error('No AgreementID found in the selected row'));
}
}
break;
case 'COMMAND_5':
console.log('COMMAND_5 is clicked');
if (this.context.listView.selectedRows && this.context.pageContext.list && this.context.listView.selectedRows.length > 0) {
const selectedRow = this.context.listView.selectedRows[0];
// determine the id of the sharepoint row
const itemId = selectedRow.getValueByName('ID');
const listId = this.context.pageContext.list.id.toString();
const siteId = this.context.pageContext.site.id.toString();
const agreementId = selectedRow.getValueByName('AgreementID');
const author = selectedRow.getValueByName('Author');
const agreementUserEmail = author[0].email;
const documentUrl = selectedRow.getValueByName('FileRef');
console.log('Document URL:', documentUrl);
const documentNameWithExtension = selectedRow.getValueByName('FileLeafRef');
const documentName = this._getFileNameWithoutExtension(documentNameWithExtension);
console.log('Document Name:', documentName);
// let's figure out what metadata we need to update the file
const itemMetadata = this._getSharePointItemMetadata(listId, itemId, siteId);
console.log('Item Metadata:', itemMetadata);
this._fetchSignedAgreement(agreementId, documentName, documentUrl, agreementUserEmail, itemId, itemMetadata).then(() => {
Log.info(LOG_SOURCE, `Signed agreement fetched successfully`);
window.location.reload();
}).catch(error => {
Log.error(LOG_SOURCE, new Error('Failed to fetch signed agreement: ' + error.message));
});
}
break;
default:
throw new Error('Unknown command');
}
}
private async _getAccessTokenMicrosoft(): Promise<string> {
const tokenProvider = await this.context.aadTokenProviderFactory.getTokenProvider();
return tokenProvider.getToken("https://graph.microsoft.com/");
}
private async _uploadTransientDocument(documentUrl: string, accessToken: string, documentName: string): Promise<any> {
const url = 'https://api.na3.adobesign.com/api/rest/v6/transientDocuments';
console.log('Document URL:', documentUrl);
try {
const documentResponse = await axios.get(documentUrl, {
responseType: 'arraybuffer'
});
const formData = new FormData();
formData.append('File', new Blob([documentResponse.data]), documentName);
formData.append('Mime-Type', 'application/pdf');
formData.append('File-Name', documentName);
console.log('Uploading transient document...');
console.log('formData:', formData);
const response = await axios.post(url, formData, {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'multipart/form-data'
}
});
return {
data: {
transientDocumentId: response.data.transientDocumentId,
}
};
} catch (error) {
console.error(error);
Log.error(LOG_SOURCE, error);
throw error;
}
}
private async _getAccessTokenSharePoint(): Promise<string> {
const tokenProvider = await this.context.aadTokenProviderFactory.getTokenProvider();
return tokenProvider.getToken(this.context.pageContext.web.absoluteUrl);
}
// _uploadTransientDocumentDocSet should be called when the content type is Document Set. This is because we need to upload all the documents in the set to Adobe Sign
private async _uploadTransientDocumentDocSet(documentUrl: string, accessTokenAdobe: string, spItemUrl: string): Promise<any> {
console.log('Document URL:', documentUrl);
console.log('SP Item URL:', spItemUrl);
const getDocumentSetContentsUrl = `${spItemUrl}/children`;
const accessTokenSharePoint = await this._getAccessTokenSharePoint();
try {
// Step 1: Fetch the list of documents within the document set
const documentSetResponse = await axios.get(getDocumentSetContentsUrl, {
headers: {
'Authorization': `Bearer ${accessTokenSharePoint}`,
'Accept': 'application/json'
}
});
const documents = documentSetResponse.data.value;
console.log('Documents in the set:', documents);
// Step 2: Iterate through the documents and upload each one as a transient document
const transientDocumentIds = await Promise.all(documents.map(async (document: any) => {
const documentFileUrl = document['@microsoft.graph.downloadUrl'];
const documentFileName = document.name;
const documentResponse = await axios.get(documentFileUrl, {
responseType: 'arraybuffer'
});
const formData = new FormData();
formData.append('File', new Blob([documentResponse.data]), documentFileName);
formData.append('Mime-Type', 'application/pdf');
formData.append('File-Name', documentFileName);
console.log('Uploading transient document:', documentFileName);
const response = await axios.post('https://api.na3.adobesign.com/api/rest/v6/transientDocuments', formData, {
headers: {
'Authorization': `Bearer ${accessTokenAdobe}`,
'Content-Type': 'multipart/form-data'
}
});
return response.data.transientDocumentId;
}));
console.log('Transient Document IDs:', transientDocumentIds);
// Step 3: Return the list of transient document IDs
return {
data: {
transientDocumentIds: transientDocumentIds
}
};
} catch (error) {
console.error(error);
Log.error(LOG_SOURCE, error);
throw error;
}
}
private async _createAgreement(transientDocumentId: string, agreementUserEmail: string, documentNameWithExtension: string, approverEmail: string): Promise<string> {
console.log('Transient Document ID:', transientDocumentId);
console.log('Agreement User Email:', agreementUserEmail);
console.log('Document Name:', documentNameWithExtension);
console.log('Approver Email:', approverEmail);
console.log('Attempting to create agreement...');
const url = `https://api.na3.adobesign.com/api/rest/v6/agreements`;
// Define the agreement request body based on the schema
const agreementRequestBody = {
fileInfos: [
{
transientDocumentId: transientDocumentId
}
],
name: documentNameWithExtension,
participantSetsInfo: [
{
order: 1,
role: 'SIGNER',
memberInfos: [
{
email: approverEmail
}
]
}
],
signatureType: 'ESIGN',
state: 'DRAFT',
senderEmail: agreementUserEmail,
};
console.log('Agreement Request Body:', agreementRequestBody);
try {
const response = await axios.post(url, agreementRequestBody, {
headers: {
'Authorization': `Bearer AdobeIntegrationKey`,
'Content-Type': 'application/json',
'x-api-user': `email:${agreementUserEmail}`
}
});
console.log('Response:', response.data);
const agreementId = response.data.id;
console.log('Agreement ID:', agreementId);
return agreementId;
} catch (error) {
console.log('Error:', error);
throw error;
}
}
private async _createDocSetAgreement(transientDocumentIds: string[], agreementUserEmail: string, documentNameWithExtension: string, approverEmail: string): Promise<string> {
console.log('Transient Document IDs:', transientDocumentIds);
console.log('Agreement User Email:', agreementUserEmail);
console.log('Document Name:', documentNameWithExtension);
console.log('Approver Email:', approverEmail);
console.log('Attempting to create agreement...');
const url = `https://api.na3.adobesign.com/api/rest/v6/agreements`;
// Define the agreement request body based on the schema
const agreementRequestBody = {
fileInfos: transientDocumentIds.map(transientDocumentId => ({
transientDocumentId: transientDocumentId
})),
name: documentNameWithExtension,
participantSetsInfo: [
{
order: 1,
role: 'SIGNER',
memberInfos: [
{
email: approverEmail
}
]
}
],
signatureType: 'ESIGN',
state: 'DRAFT',
senderEmail: agreementUserEmail,
};
console.log('Agreement Request Body:', agreementRequestBody);
try {
const response = await axios.post(url, agreementRequestBody, {
headers: {
'Authorization': `Bearer AdobeIntegrationKey`,
'Content-Type': 'application/json',
'x-api-user': `email:${agreementUserEmail}`
}
});
console.log('Response:', response.data);
const agreementId = response.data.id;
console.log('Agreement ID:', agreementId);
return agreementId;
} catch (error) {
console.log('Error:', error);
throw error;
}
}
private async _fetchAgreementStatus(agreementId: string, agreementUserEmail: string): Promise<string> {
console.log('Agreement ID:', agreementId);
console.log('Agreement User Email:', agreementUserEmail);
console.log('Attempting to fetch agreement status...');
const accessToken = 'AdobeIntegrationKey'
const url = `https://api.na3.adobesign.com/api/rest/v6/agreements/${agreementId}`;
try {
const response = await axios.get(url, {
headers: {
'Authorization': `Bearer ${accessToken}`,
'x-api-user': `email:${agreementUserEmail}`
}
});
return response.data.status;
} catch (error) {
Log.error(LOG_SOURCE, error);
console.log('Error:', error);
throw error;
}
}
private async _updateSharePointField(row: any, fieldValue: string): Promise<void> {
const itemId = row.getValueByName('ID');
console.log('Item ID:', itemId);
if (this.context.pageContext.list) {
const listId = this.context.pageContext.list.id.toString();
console.log('List ID:', listId);
const siteId = this.context.pageContext.site.id.toString();
const url = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/items/${itemId}`;
console.log('URL:', url);
try {
const accessToken = await this._getAccessTokenMicrosoft();
const response = await fetch(url, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
fields: {
'Adobe_x0020_Sign_x0020_Status': fieldValue
}
})
});
if (!response.ok) {
console.error('Error:', response.statusText);
throw new Error(`Failed to update Status: ${response.status}`);
}
console.log(`updated successfully`);
} catch (error) {
console.log('Error:', error);
throw error;
}
}
}
private async _updateSharePointFieldAgreementId(row: any, agreementId: string): Promise<void> {
const itemId = row.getValueByName('ID');
console.log('Item ID:', itemId);
console.log('Agreement ID:', agreementId);
if (this.context.pageContext.list) {
const listId = this.context.pageContext.list.id.toString();
const siteId = this.context.pageContext.site.id.toString();
console.log('List ID:', listId);
const url = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/items/${itemId}`;
console.log('URL:', url);
try {
const accessToken = await this._getAccessTokenMicrosoft();
const response = await fetch(url, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
fields: {
'AgreementID': agreementId
}
})
});
if (!response.ok) {
console.error('Error:', response.statusText);
throw new Error(`Failed to update AgreementID. Status: ${response.status}`);
}
console.log('AgreementID updated successfully');
} catch (error) {
console.log('Error:', error);
throw error;
}
}
}
private async _getSharePointItemMetadata(listId: string, itemId: string, siteId: string): Promise<any> {
const url = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/items/${itemId}`;
try {
const accessToken = await this._getAccessTokenMicrosoft();
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
console.error('Error:', response.statusText);
throw new Error(`Failed to retrieve item metadata. Status: ${response.status}`);
}
const itemMetadata = await response.json();
console.log('Item Metadata:', itemMetadata);
return itemMetadata.fields;
} catch (error) {
console.log('Error:', error);
throw error;
}
}
private async _getDriveId(siteId: string, accessToken: string): Promise<string> {
const drivesUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/drives`;
const response = await fetch(drivesUrl, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
if (!response.ok) {
throw new Error(`Failed to fetch drives. Status: ${response.status}`);
}
const data = await response.json();
const driveId = data.value[0]?.id; // Assuming the first drive is the document library
if (!driveId) {
throw new Error('Drive ID not found');
}
return driveId;
}
private async _getFolderId(siteId: string, driveId: string, folderPath: string, accessToken: string): Promise<string> {
const folderUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/drives/${driveId}/root:/${folderPath}`;
const response = await fetch(folderUrl, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
if (!response.ok) {
throw new Error(`Failed to fetch folder. Status: ${response.status}`);
}
const data = await response.json();
const folderId = data.id;
if (!folderId) {
throw new Error('Folder ID not found');
}
return folderId;
}
private async _fetchSignedAgreement(
agreementId: string,
documentName: string,
documentUrl: string,
agreementUserEmail: string,
itemId: string,
itemMetadata: any
): Promise<void> {
console.log('Agreement ID:', agreementId);
console.log('Agreement User Email:', agreementUserEmail);
console.log('Attempting to fetch signed agreement...');
console.log('Document URL:', documentUrl);
console.log('Document Name:', documentName);
console.log('Item ID:', itemId);
const siteId = this.context.pageContext.site.id.toString();
const accessTokenAdobe = 'AdobeIntegrationKey';
const urlAdobe = `https://api.na3.adobesign.com/api/rest/v6/agreements/${agreementId}/combinedDocument`;
try {
// Step 1: Fetch the signed document from Adobe Sign
const response = await axios.get(urlAdobe, {
headers: {
'Authorization': `Bearer ${accessTokenAdobe}`,
'x-api-user': `email:${agreementUserEmail}`,
'Accept': 'application/pdf'
},
responseType: 'arraybuffer'
});
const signedAgreement = response.data;
console.log('Signed Agreement:', signedAgreement);
// Step 2: Retrieve Destination Drive and Folder IDs
const accessTokenMicrosoft = await this._getAccessTokenMicrosoft();
const destinationDriveId = await this._getDriveId(siteId, accessTokenMicrosoft);
const destinationFolderPath = 'Invoices/.Signed Documents';
const destinationFolderId = await this._getFolderId(siteId, destinationDriveId, destinationFolderPath, accessTokenMicrosoft);
const fileName = `${documentName}.pdf`;
// Step 3: Copy the original file to the designated folder
const originalFilePath = documentUrl.substring(documentUrl.indexOf('/sites'), documentUrl.lastIndexOf('/'));
console.log('Original File Path:', originalFilePath);
console.log('Destination Folder Path:', destinationFolderPath);
const copyFileUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/drives/${destinationDriveId}/items/${itemId}/copy`;
const copyRequestBody = {
parentReference: {
driveId: destinationDriveId,
id: destinationFolderId,
},
name: fileName
};
console.log('Copying file to:', destinationFolderPath);
console.log('fileName:', fileName);
console.log('copyRequestBody:', copyRequestBody);
const copyFileResponse = await fetch(copyFileUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessTokenMicrosoft}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(copyRequestBody)
});
if (!copyFileResponse.ok) {
console.error('Error copying SharePoint file:', copyFileResponse.statusText);
throw new Error(`Failed to copy SharePoint file: ${copyFileResponse.status}`);
}
console.log('File copied successfully.');
// Step 4: Update the copied file content with the signed document
const copiedFileId = (await copyFileResponse.json()).id;
const fileUploadUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/drives/${destinationDriveId}/items/${copiedFileId}/content`;
const fileUploadResponse = await fetch(fileUploadUrl, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${accessTokenMicrosoft}`,
'Content-Type': 'application/pdf'
},
body: signedAgreement
});
if (!fileUploadResponse.ok) {
console.error('Error updating SharePoint file with signed agreement:', fileUploadResponse.statusText);
throw new Error(`Failed to update SharePoint file: ${fileUploadResponse.status}`);
}
const fileUploadResult = await fileUploadResponse.json();
console.log('File Upload Result:', fileUploadResult);
// Step 5: Delete the original unsigned file
const deleteFileUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/drives/${destinationDriveId}/items/${itemId}`;
const deleteFileResponse = await fetch(deleteFileUrl, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${accessTokenMicrosoft}`
}
});
if (!deleteFileResponse.ok) {
console.error('Error deleting original SharePoint file:', deleteFileResponse.statusText);
throw new Error(`Failed to delete original SharePoint file: ${deleteFileResponse.status}`);
}
console.log('Original file deleted successfully.');
} catch (error) {
console.log('Error:', error);
throw error;
}
}
private _getFileNameWithoutExtension(fileNameWithExtension: string): string {
const lastDotPosition = fileNameWithExtension.lastIndexOf('.');
if (lastDotPosition === -1) return fileNameWithExtension; // No extension found
return fileNameWithExtension.substring(0, lastDotPosition);
}
private _onListViewStateChanged = (args: ListViewStateChangedEventArgs): void => {
Log.info(LOG_SOURCE, 'List view state changed');
const compareTwoCommand: Command = this.tryGetCommand('COMMAND_2');
if (compareTwoCommand) {
compareTwoCommand.visible = this.context.listView.selectedRows?.length === 1;
}
const compareThreeCommand: Command = this.tryGetCommand('COMMAND_3');
if (compareThreeCommand) {
compareThreeCommand.visible = this.context.listView.selectedRows?.length === 1;
}
const compareFourCommand: Command = this.tryGetCommand('COMMAND_4');
if (compareFourCommand) {
compareFourCommand.visible = this.context.listView.selectedRows?.length === 1;
}
const compareFiveCommand: Command = this.tryGetCommand('COMMAND_5');
if (compareFiveCommand) {
compareFiveCommand.visible = this.context.listView.selectedRows?.length === 1;
}
this.raiseOnChange();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment