Skip to content

Commit

Permalink
SharePoint: Metadata (#22546)
Browse files Browse the repository at this point in the history
Read and write metadata of a list item

---------

Co-authored-by: Konrad Milewski <[email protected]>
Co-authored-by: mazhelez <[email protected]>
Co-authored-by: Maria Zhelezova <[email protected]>
  • Loading branch information
4 people authored Aug 15, 2023
1 parent 535ebb0 commit 9232b26
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 7 deletions.
10 changes: 10 additions & 0 deletions Modules/System/SharePoint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ Downloads specified file to the client.
SPClient.DownloadFileContent(SharePointFile.OdataId, SharePointFile.Name);
```

### Update Metadata for a list item (including a file)
Updates specific metadata field for list item.
In order to update metadata of a file it needs to be accessed as list item.
```
var
SharePointFile: Record "SharePoint File";
begin
SharePointClient.UpdateListItemMetaDataField('Maintenance', 10, 'SP.Data.MaintenanceItem', 'WorkOrderNo', 'TEST0001');
```

## Error handling

### Retrieve diagnostic information
Expand Down
82 changes: 79 additions & 3 deletions Modules/System/SharePoint/src/SharePointClient.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ codeunit 9100 "SharePoint Client"
/// <summary>
/// Gets all list items for the given list.
/// </summary>
/// <raises>ProcessSharePointListItemMetadata</raises>
/// <param name="ListTitle">The title of the list/</param>
/// <param name="SharePointListItem">Collection of the result (temporary record).</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
Expand All @@ -69,6 +70,7 @@ codeunit 9100 "SharePoint Client"
/// <summary>
/// Gets all list items for the given list.
/// </summary>
/// <raises>ProcessSharePointListItemMetadata</raises>
/// <param name="ListId">The GUID of the list/</param>
/// <param name="SharePointListItem">Collection of the result (temporary record).</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
Expand Down Expand Up @@ -207,6 +209,7 @@ codeunit 9100 "SharePoint Client"
/// <summary>
/// Creates a new list item in specific list.
/// </summary>
/// <raises>ProcessSharePointListItemMetadata</raises>
/// <param name="ListTitle">The title of the list.</param>
/// <param name="ListItemEntityTypeFullName">The Entity Type for the list. Parameter can be found on a list object (ListItemEntityType).</param>
/// <param name="ListItemTitle">The title of the new list item.</param>
Expand All @@ -220,6 +223,7 @@ codeunit 9100 "SharePoint Client"
/// <summary>
/// Creates a new list item in specific list.
/// </summary>
/// <raises>ProcessSharePointListItemMetadata</raises>
/// <param name="ListId">The GUID of the list.</param>
/// <param name="ListItemEntityTypeFullName">The Entity Type for the list. Parameter can be found on a list object (ListItemEntityType).</param>
/// <param name="ListItemTitle">The title of the new list item.</param>
Expand Down Expand Up @@ -249,12 +253,26 @@ codeunit 9100 "SharePoint Client"
/// <summary>
/// Lists all files in the given folder.
/// </summary>
/// <raises>ProcessSharePointFileMetadata</raises>
/// <param name="ServerRelativeUrl">URL of the parent folder.</param>
/// <param name="SharePointFile">Collection of the result (temporary record).</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure GetFolderFilesByServerRelativeUrl(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary): Boolean
begin
exit(SharePointClientImpl.GetFolderFilesByServerRelativeUrl(ServerRelativeUrl, SharePointFile));
exit(SharePointClientImpl.GetFolderFilesByServerRelativeUrl(ServerRelativeUrl, SharePointFile, false));
end;

/// <summary>
/// Lists all files in the given folder.
/// </summary>
/// <raises>ProcessSharePointFileMetadata</raises>
/// <param name="ServerRelativeUrl">URL of the parent folder.</param>
/// <param name="SharePointFile">Collection of the result (temporary record).</param>
/// <param name="ListAllFields">Include metadata in results.</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure GetFolderFilesByServerRelativeUrl(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary; ListAllFields: Boolean): Boolean
begin
exit(SharePointClientImpl.GetFolderFilesByServerRelativeUrl(ServerRelativeUrl, SharePointFile, ListAllFields));
end;

/// <summary>
Expand Down Expand Up @@ -390,18 +408,34 @@ codeunit 9100 "SharePoint Client"
/// <summary>
/// Adds a file to specific folder.
/// </summary>
/// <raises>ProcessSharePointFileMetadata</raises>
/// <remarks>Requires UI interaction to pick a file.</remarks>
/// <param name="ServerRelativeUrl">URL of the parent folder.</param>
/// <param name="SharePointFile">Collection of the result (temporary record). Always one element.</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure AddFileToFolder(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary): Boolean
begin
exit(SharePointClientImpl.AddFileToFolder(ServerRelativeUrl, SharePointFile));
exit(SharePointClientImpl.AddFileToFolder(ServerRelativeUrl, SharePointFile, false));
end;

/// <summary>
/// Adds a file to specific folder.
/// </summary>
/// <raises>ProcessSharePointFileMetadata</raises>
/// <remarks>Requires UI interaction to pick a file.</remarks>
/// <param name="ServerRelativeUrl">URL of the parent folder.</param>
/// <param name="SharePointFile">Collection of the result (temporary record). Always one element.</param>
/// <param name="ListAllFields">Include metadata in results.</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure AddFileToFolder(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary; ListAllFields: Boolean): Boolean
begin
exit(SharePointClientImpl.AddFileToFolder(ServerRelativeUrl, SharePointFile, ListAllFields));
end;

/// <summary>
/// Adds a file to specific folder.
/// </summary>
/// <raises>ProcessSharePointFileMetadata</raises>
/// <remarks>Does not require UI interaction.</remarks>
/// <param name="ServerRelativeUrl">URL of the parent folder.</param>
/// <param name="FileName">File name to use on SharePoint.</param>
Expand All @@ -410,7 +444,49 @@ codeunit 9100 "SharePoint Client"
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure AddFileToFolder(ServerRelativeUrl: Text; FileName: Text; var FileInStream: InStream; var SharePointFile: Record "SharePoint File" temporary): Boolean
begin
exit(SharePointClientImpl.AddFileToFolder(ServerRelativeUrl, FileName, FileInStream, SharePointFile));
exit(SharePointClientImpl.AddFileToFolder(ServerRelativeUrl, FileName, FileInStream, SharePointFile, false));
end;

/// <summary>
/// Adds a file to specific folder.
/// </summary>
/// <raises>ProcessSharePointFileMetadata</raises>
/// <remarks>Does not require UI interaction.</remarks>
/// <param name="ServerRelativeUrl">URL of the parent folder.</param>
/// <param name="FileName">File name to use on SharePoint.</param>
/// <param name="FileInStream">File stream to upload.</param>
/// <param name="SharePointFile">Collection of the result (temporary record). Always one element.</param>
/// <param name="ListAllFields">Include metadata in results.</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure AddFileToFolder(ServerRelativeUrl: Text; FileName: Text; var FileInStream: InStream; var SharePointFile: Record "SharePoint File" temporary; ListAllFields: Boolean): Boolean
begin
exit(SharePointClientImpl.AddFileToFolder(ServerRelativeUrl, FileName, FileInStream, SharePointFile, ListAllFields));
end;

/// <summary>
/// Updates metadata field for list item.
/// </summary>
/// <param name="ListTitle">The title of the list.</param>
/// <param name="ListItemEntityTypeFullName">The Entity Type for the list. Parameter can be found on a list object (ListItemEntityType).</param>
/// <param name="FieldName">The name of the metadata field.</param>
/// <param name="FieldValue">Value.</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure UpdateListItemMetaDataField(ListTitle: Text; ItemId: Integer; ListItemEntityTypeFullName: Text; FieldName: Text; FieldValue: Text): Boolean
begin
exit(SharePointClientImpl.UpdateListItemMetaDataField(ListTitle, ItemId, ListItemEntityTypeFullName, FieldName, FieldValue));
end;

/// <summary>
/// Updates metadata field for list item.
/// </summary>
/// <param name="ListTitle">The GUID of the list.</param>
/// <param name="ListItemEntityTypeFullName">The Entity Type for the list. Parameter can be found on a list object (ListItemEntityType).</param>
/// <param name="FieldName">The name of the metadata field.</param>
/// <param name="FieldValue">Value.</param>
/// <returns>True if the operation was successful; otherwise - false.</returns>
procedure UpdateListItemMetaDataField(ListId: Guid; ItemId: Integer; ListItemEntityTypeFullName: Text; FieldName: Text; FieldValue: Text): Boolean
begin
exit(SharePointClientImpl.UpdateListItemMetaDataField(ListId, ItemId, ListItemEntityTypeFullName, FieldName, FieldValue));
end;

#endregion
Expand Down
76 changes: 73 additions & 3 deletions Modules/System/SharePoint/src/SharePointClientImpl.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ codeunit 9101 "SharePoint Client Impl."
SharePointUriBuilder.SetMethod('Lists', ListId);
SharePointUriBuilder.SetObject('items');


SharePointRequestHelper.SetAuthorization(Authorization);
SharePointOperationResponse := SharePointRequestHelper.Get(SharePointUriBuilder);
if not SharePointOperationResponse.GetDiagnostics().IsSuccessStatusCode() then
Expand Down Expand Up @@ -458,14 +459,16 @@ codeunit 9101 "SharePoint Client Impl."
exit(true);
end;

procedure GetFolderFilesByServerRelativeUrl(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary): Boolean
procedure GetFolderFilesByServerRelativeUrl(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary; ListAllFields: Boolean): Boolean
var
SharePointFileParser: Codeunit "SharePoint File";
Result: Text;
begin
SharePointUriBuilder.ResetPath();
SharePointUriBuilder.SetMethod('GetFolderByServerRelativeUrl', ServerRelativeUrl);
SharePointUriBuilder.SetObject('Files');
if ListAllFields then
SharePointUriBuilder.AddQueryParameter('$expand', 'ListItemAllFields');

SharePointRequestHelper.SetAuthorization(Authorization);
SharePointOperationResponse := SharePointRequestHelper.Get(SharePointUriBuilder);
Expand Down Expand Up @@ -626,6 +629,7 @@ codeunit 9101 "SharePoint Client Impl."
exit(true);
end;


procedure DeleteFolder(OdataId: Text): Boolean
begin
//DELETE https://{site_url}/_api/web/GetFolderByServerRelativeUrl('{folder_name}')
Expand Down Expand Up @@ -653,7 +657,7 @@ codeunit 9101 "SharePoint Client Impl."
exit(true);
end;

procedure AddFileToFolder(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary): Boolean
procedure AddFileToFolder(ServerRelativeUrl: Text; var SharePointFile: Record "SharePoint File" temporary; ListAllFields: Boolean): Boolean
var
SharePointFileParser: Codeunit "SharePoint File";
SharePointHttpContent: Codeunit "SharePoint Http Content";
Expand All @@ -669,6 +673,8 @@ codeunit 9101 "SharePoint Client Impl."
SharePointUriBuilder.SetMethod('GetFolderByServerRelativeUrl', ServerRelativeUrl);
SharePointUriBuilder.SetObject('Files');
SharePointUriBuilder.SetMethod('add', 'url', '''' + FileName + '''');
if ListAllFields then
SharePointUriBuilder.AddQueryParameter('$expand', 'ListItemAllFields');

SharePointHttpContent.FromFileInStream(FileInStream);
SharePointRequestHelper.SetAuthorization(Authorization);
Expand All @@ -681,7 +687,7 @@ codeunit 9101 "SharePoint Client Impl."
exit(true);
end;

procedure AddFileToFolder(ServerRelativeUrl: Text; FileName: Text; var FileInStream: InStream; var SharePointFile: Record "SharePoint File" temporary): Boolean
procedure AddFileToFolder(ServerRelativeUrl: Text; FileName: Text; var FileInStream: InStream; var SharePointFile: Record "SharePoint File" temporary; ListAllFields: Boolean): Boolean
var
SharePointFileParser: Codeunit "SharePoint File";
SharePointHttpContent: Codeunit "SharePoint Http Content";
Expand All @@ -692,6 +698,8 @@ codeunit 9101 "SharePoint Client Impl."
SharePointUriBuilder.SetMethod('GetFolderByServerRelativeUrl', ServerRelativeUrl);
SharePointUriBuilder.SetObject('Files');
SharePointUriBuilder.SetMethod('add', 'url', '''' + FileName + '''');
if ListAllFields then
SharePointUriBuilder.AddQueryParameter('$expand', 'ListItemAllFields');

SharePointHttpContent.FromFileInStream(FileInStream);
SharePointRequestHelper.SetAuthorization(Authorization);
Expand All @@ -703,5 +711,67 @@ codeunit 9101 "SharePoint Client Impl."
SharePointFileParser.ParseSingleReturnValue(Result, SharePointFile);
exit(true);
end;

procedure UpdateListItemMetaDataField(ListTitle: Text; ItemId: Integer; ListItemEntityTypeFullName: Text; FieldName: Text; FieldValue: Text): Boolean
var
SharePointHttpContent: Codeunit "SharePoint Http Content";
Metadata, Payload : JsonObject;
Txt: Text;
begin
SharePointUriBuilder.ResetPath();
SharePointUriBuilder.SetObject('lists');
SharePointUriBuilder.SetMethod('GetByTitle', ListTitle);
SharePointUriBuilder.SetMethod('items', ItemId);

Metadata.Add('type', ListItemEntityTypeFullName);
Payload.Add('__metadata', Metadata);
Payload.Add(FieldName, FieldValue);

SharePointHttpContent.FromJson(Payload);

SharePointHttpContent.GetContent().ReadAs(Txt);

SharePointHttpContent.SetRequestDigest(GetRequestDigest(SharePointUriBuilder.GetHost()));
SharePointHttpContent.SetXHttpMethod('MERGE');
SharePointHttpContent.SetIfMatch('*');

SharePointOperationResponse := SharePointRequestHelper.Patch(SharePointUriBuilder, SharePointHttpContent);
if not SharePointOperationResponse.GetDiagnostics().IsSuccessStatusCode() then
exit(false);

SharePointOperationResponse.GetResultAsText(Txt);
Message(Txt);
exit(true);
end;

procedure UpdateListItemMetaDataField(ListId: Guid; ItemId: Integer; ListItemEntityTypeFullName: Text; FieldName: Text; FieldValue: Text): Boolean
var
SharePointHttpContent: Codeunit "SharePoint Http Content";
Metadata, Payload : JsonObject;
Txt: Text;
begin
SharePointUriBuilder.ResetPath();
SharePointUriBuilder.SetMethod('Lists', ListId);
SharePointUriBuilder.SetMethod('items', ItemId);

Metadata.Add('type', ListItemEntityTypeFullName);
Payload.Add('__metadata', Metadata);
Payload.Add(FieldName, FieldValue);

SharePointHttpContent.FromJson(Payload);

SharePointHttpContent.GetContent().ReadAs(Txt);

SharePointHttpContent.SetRequestDigest(GetRequestDigest(SharePointUriBuilder.GetHost()));
SharePointHttpContent.SetXHttpMethod('MERGE');
SharePointHttpContent.SetIfMatch('*');

SharePointOperationResponse := SharePointRequestHelper.Patch(SharePointUriBuilder, SharePointHttpContent);
if not SharePointOperationResponse.GetDiagnostics().IsSuccessStatusCode() then
exit(false);

SharePointOperationResponse.GetResultAsText(Txt);
exit(true);
end;
#endregion
}
26 changes: 26 additions & 0 deletions Modules/System/SharePoint/src/SharePointEvents.Codeunit.al
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
codeunit 9112 "SharePoint Events"
{
Access = Public;

[IntegrationEvent(false, false)]
/// <summary>
/// Process SharePointFile Metadata - Use to extract custom meta data into model record
/// </summary>
/// <remarks>Extend the "SharePoint File" table to store any custom data.</remarks>
/// <param name="Metadata">__metadata node of SharePointFile Json Object</param>
/// <param name="SharePointFile">SharePointFile temporary record.</param>
internal procedure ProcessSharePointFileMetadata(Metadata: JsonToken; var SharePointFile: Record "SharePoint File" temporary)
begin
end;

[IntegrationEvent(false, false)]
/// <summary>
/// Process SharePointListItem Metadata - Use to extract custom mete data into model record
/// </summary>
/// <remarks>Extend the "SharePoint List Item" table to store any custom data.</remarks>
/// <param name="Metadata">__metadata node of SharePointListItem Json Object</param>
/// <param name="SharePointListItem">SharePointListItem temporary record.</param>
internal procedure ProcessSharePointListItemMetadata(Metadata: JsonToken; var SharePointListItem: Record "SharePoint List Item" temporary)
begin
end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ codeunit 9107 "SharePoint Http Content"
ContentLength: Integer;
ContentType: Text;
RequestDigest: Text;
XHttpMethod: Text;
IfMatch: Text;

procedure FromFileInStream(var FileInStream: Instream)
begin
Expand Down Expand Up @@ -57,6 +59,26 @@ codeunit 9107 "SharePoint Http Content"
exit(RequestDigest);
end;

procedure SetXHttpMethod(XHttpMethodValue: Text)
begin
XHttpMethodValue := XHttpMethodValue;
end;

procedure GetXHttpMethod(): Text;
begin
exit(XHttpMethod);
end;

procedure SetIfMatch(IfMatchValue: Text)
begin
IfMatch := IfMatchValue;
end;

procedure GetIfMatch(): Text;
begin
exit(IfMatch);
end;

local procedure GetContentLength(var SourceInStream: InStream) Length: Integer
var
MemoryStream: DotNet MemoryStream;
Expand Down
Loading

0 comments on commit 9232b26

Please sign in to comment.