diff --git a/src/System Application/App/SharePoint/src/graph/SharePointGraphClient.Codeunit.al b/src/System Application/App/SharePoint/src/graph/SharePointGraphClient.Codeunit.al
index 2c324cb6df..6c64915e0d 100644
--- a/src/System Application/App/SharePoint/src/graph/SharePointGraphClient.Codeunit.al
+++ b/src/System Application/App/SharePoint/src/graph/SharePointGraphClient.Codeunit.al
@@ -209,6 +209,47 @@ codeunit 9119 "SharePoint Graph Client"
exit(SharePointGraphClientImpl.CreateListItem(ListId, Title, GraphListItem));
end;
+ ///
+ /// Gets a single item from a SharePoint list.
+ ///
+ /// ID of the list.
+ /// ID of the item.
+ /// Record to store the result.
+ /// An operation response object containing the result of the operation.
+ /// Required Microsoft Graph permission: Sites.Read.All
+ procedure GetListItem(ListId: Text; ItemId: Text; var GraphListItem: Record "SharePoint Graph List Item" temporary): Codeunit "SharePoint Graph Response"
+ begin
+ exit(SharePointGraphClientImpl.GetListItem(ListId, ItemId, GraphListItem));
+ end;
+
+ ///
+ /// Gets a single item from a SharePoint list.
+ ///
+ /// ID of the list.
+ /// ID of the item.
+ /// Record to store the result.
+ /// A wrapper for optional header and query parameters.
+ /// An operation response object containing the result of the operation.
+ /// Required Microsoft Graph permission: Sites.Read.All
+ procedure GetListItem(ListId: Text; ItemId: Text; var GraphListItem: Record "SharePoint Graph List Item" temporary; GraphOptionalParameters: Codeunit "Graph Optional Parameters"): Codeunit "SharePoint Graph Response"
+ begin
+ exit(SharePointGraphClientImpl.GetListItem(ListId, ItemId, GraphListItem, GraphOptionalParameters));
+ end;
+
+ ///
+ /// Updates an existing list item's fields.
+ ///
+ /// ID of the list.
+ /// ID of the item to update.
+ /// JSON object containing the fields to update.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ /// Required Microsoft Graph permission: Sites.ReadWrite.All
+ procedure UpdateListItem(ListId: Text; ItemId: Text; FieldsJsonObject: JsonObject; var GraphListItem: Record "SharePoint Graph List Item" temporary): Codeunit "SharePoint Graph Response"
+ begin
+ exit(SharePointGraphClientImpl.UpdateListItem(ListId, ItemId, FieldsJsonObject, GraphListItem));
+ end;
+
#endregion
#region Drive and Items
@@ -730,6 +771,62 @@ codeunit 9119 "SharePoint Graph Client"
#endregion
+ #region Update Item
+
+ ///
+ /// Updates a drive item's properties (name, description, etc.) by ID.
+ ///
+ /// ID of the item to update.
+ /// JSON object containing the properties to update (e.g., name, description).
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ /// Required Microsoft Graph permission: Sites.ReadWrite.All.
+ procedure UpdateDriveItem(ItemId: Text; UpdatePropertiesJsonObject: JsonObject; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ begin
+ exit(SharePointGraphClientImpl.UpdateDriveItem(ItemId, UpdatePropertiesJsonObject, GraphDriveItem));
+ end;
+
+ ///
+ /// Updates a drive item's properties (name, description, etc.) by path.
+ ///
+ /// Path to the item (e.g., 'Documents/file.docx').
+ /// JSON object containing the properties to update (e.g., name, description).
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ /// Required Microsoft Graph permission: Sites.ReadWrite.All.
+ procedure UpdateDriveItemByPath(ItemPath: Text; UpdatePropertiesJsonObject: JsonObject; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ begin
+ exit(SharePointGraphClientImpl.UpdateDriveItemByPath(ItemPath, UpdatePropertiesJsonObject, GraphDriveItem));
+ end;
+
+ ///
+ /// Renames a drive item by ID.
+ ///
+ /// ID of the item to rename.
+ /// New name for the item.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ /// Required Microsoft Graph permission: Sites.ReadWrite.All.
+ procedure RenameDriveItem(ItemId: Text; NewName: Text; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ begin
+ exit(SharePointGraphClientImpl.RenameDriveItem(ItemId, NewName, GraphDriveItem));
+ end;
+
+ ///
+ /// Renames a drive item by path.
+ ///
+ /// Path to the item (e.g., 'Documents/file.docx').
+ /// New name for the item.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ /// Required Microsoft Graph permission: Sites.ReadWrite.All.
+ procedure RenameDriveItemByPath(ItemPath: Text; NewName: Text; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ begin
+ exit(SharePointGraphClientImpl.RenameDriveItemByPath(ItemPath, NewName, GraphDriveItem));
+ end;
+
+ #endregion
+
///
/// Creates an OData query to filter items in SharePoint
///
diff --git a/src/System Application/App/SharePoint/src/graph/SharePointGraphClientImpl.Codeunit.al b/src/System Application/App/SharePoint/src/graph/SharePointGraphClientImpl.Codeunit.al
index 3f392d432b..a05b54fea2 100644
--- a/src/System Application/App/SharePoint/src/graph/SharePointGraphClientImpl.Codeunit.al
+++ b/src/System Application/App/SharePoint/src/graph/SharePointGraphClientImpl.Codeunit.al
@@ -86,6 +86,14 @@ codeunit 9120 "SharePoint Graph Client Impl."
InvalidTargetPathErr: Label 'Target path cannot be empty';
FailedToCopyItemErr: Label 'Failed to copy item: %1', Comment = '%1 = Error message';
FailedToMoveItemErr: Label 'Failed to move item: %1', Comment = '%1 = Error message';
+ InvalidUpdateBodyErr: Label 'Update properties cannot be empty';
+ FailedToUpdateDriveItemErr: Label 'Failed to update drive item: %1', Comment = '%1 = Error message';
+ FailedToParseUpdatedDriveItemErr: Label 'Failed to parse updated drive item details from response';
+ InvalidNewNameErr: Label 'New name cannot be empty';
+ InvalidFieldsErr: Label 'Fields JSON object cannot be empty';
+ FailedToRetrieveListItemErr: Label 'Failed to retrieve list item: %1', Comment = '%1 = Error message';
+ FailedToParseListItemErr: Label 'Failed to parse list item details from response';
+ FailedToUpdateListItemErr: Label 'Failed to update list item: %1', Comment = '%1 = Error message';
GraphSharePointCategoryLbl: Label 'AL Graph SharePoint', Locked = true;
OperationSuccessTelemetryMsg: Label '%1 completed successfully.', Locked = true, Comment = '%1 = Operation name';
@@ -548,6 +556,125 @@ codeunit 9120 "SharePoint Graph Client Impl."
exit(CreateListItem(ListId, FieldsJsonObject, GraphListItem));
end;
+ ///
+ /// Gets a single item from a SharePoint list.
+ ///
+ /// ID of the list.
+ /// ID of the item.
+ /// Record to store the result.
+ /// An operation response object containing the result of the operation.
+ procedure GetListItem(ListId: Text; ItemId: Text; var GraphListItem: Record "SharePoint Graph List Item" temporary): Codeunit "SharePoint Graph Response"
+ var
+ GraphOptionalParameters: Codeunit "Graph Optional Parameters";
+ begin
+ exit(GetListItem(ListId, ItemId, GraphListItem, GraphOptionalParameters));
+ end;
+
+ ///
+ /// Gets a single item from a SharePoint list.
+ ///
+ /// ID of the list.
+ /// ID of the item.
+ /// Record to store the result.
+ /// A wrapper for optional header and query parameters.
+ /// An operation response object containing the result of the operation.
+ procedure GetListItem(ListId: Text; ItemId: Text; var GraphListItem: Record "SharePoint Graph List Item" temporary; GraphOptionalParameters: Codeunit "Graph Optional Parameters"): Codeunit "SharePoint Graph Response"
+ var
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ JsonResponse: JsonObject;
+ ErrorMessage: Text;
+ begin
+ EnsureInitialized();
+ EnsureSiteId();
+
+ SharePointGraphResponse.SetRequestHelper(SharePointGraphRequestHelper);
+
+ if ListId = '' then begin
+ SharePointGraphResponse.SetError(InvalidListIdErr);
+ Session.LogMessage('', InvalidListIdErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if ItemId = '' then begin
+ SharePointGraphResponse.SetError(InvalidItemIdErr);
+ Session.LogMessage('', InvalidItemIdErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if not SharePointGraphRequestHelper.Get(SharePointGraphUriBuilder.GetListItemByIdEndpoint(ListId, ItemId), JsonResponse, GraphOptionalParameters) then begin
+ ErrorMessage := StrSubstNo(FailedToRetrieveListItemErr, SharePointGraphRequestHelper.GetDiagnostics().GetResponseReasonPhrase());
+ SharePointGraphResponse.SetError(ErrorMessage);
+ Session.LogMessage('', ErrorMessage, Verbosity::Error, DataClassification::CustomerContent, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ GraphListItem.Init();
+ GraphListItem.ListId := CopyStr(ListId, 1, MaxStrLen(GraphListItem.ListId));
+ if not SharePointGraphParser.ParseListItemDetail(JsonResponse, GraphListItem) then begin
+ SharePointGraphResponse.SetError(FailedToParseListItemErr);
+ Session.LogMessage('', FailedToParseListItemErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+ GraphListItem.Insert();
+
+ SharePointGraphResponse.SetSuccess();
+ Session.LogMessage('', StrSubstNo(OperationSuccessTelemetryMsg, 'GetListItem'), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ ///
+ /// Updates an existing list item's fields.
+ ///
+ /// ID of the list.
+ /// ID of the item to update.
+ /// JSON object containing the fields to update.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ procedure UpdateListItem(ListId: Text; ItemId: Text; FieldsJsonObject: JsonObject; var GraphListItem: Record "SharePoint Graph List Item" temporary): Codeunit "SharePoint Graph Response"
+ var
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ JsonResponse: JsonObject;
+ ErrorMessage: Text;
+ begin
+ EnsureInitialized();
+ EnsureSiteId();
+
+ SharePointGraphResponse.SetRequestHelper(SharePointGraphRequestHelper);
+
+ if ListId = '' then begin
+ SharePointGraphResponse.SetError(InvalidListIdErr);
+ Session.LogMessage('', InvalidListIdErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if ItemId = '' then begin
+ SharePointGraphResponse.SetError(InvalidItemIdErr);
+ Session.LogMessage('', InvalidItemIdErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if FieldsJsonObject.Keys().Count() = 0 then begin
+ SharePointGraphResponse.SetError(InvalidFieldsErr);
+ Session.LogMessage('', InvalidFieldsErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if not SharePointGraphRequestHelper.Patch(SharePointGraphUriBuilder.GetUpdateListItemFieldsEndpoint(ListId, ItemId), FieldsJsonObject, JsonResponse) then begin
+ ErrorMessage := StrSubstNo(FailedToUpdateListItemErr, SharePointGraphRequestHelper.GetDiagnostics().GetResponseReasonPhrase());
+ SharePointGraphResponse.SetError(ErrorMessage);
+ Session.LogMessage('', ErrorMessage, Verbosity::Error, DataClassification::CustomerContent, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ SharePointGraphResponse := GetListItem(ListId, ItemId, GraphListItem);
+ if not SharePointGraphResponse.IsSuccessful() then
+ exit(SharePointGraphResponse);
+
+ SharePointGraphResponse.SetSuccess();
+ Session.LogMessage('', StrSubstNo(OperationSuccessTelemetryMsg, 'UpdateListItem'), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
#endregion
#region Drive and Items
@@ -2047,6 +2174,151 @@ codeunit 9120 "SharePoint Graph Client Impl."
exit(MoveItem(TempGraphDriveItem.Id, TargetFolderId, NewName));
end;
+ ///
+ /// Updates a drive item's properties (name, description, etc.) by ID.
+ ///
+ /// ID of the item to update.
+ /// JSON object containing the properties to update.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ procedure UpdateDriveItem(ItemId: Text; UpdatePropertiesJsonObject: JsonObject; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ var
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ ResponseJson: JsonObject;
+ ErrorMessage: Text;
+ begin
+ EnsureInitialized();
+ EnsureSiteId();
+ EnsureDefaultDriveId();
+
+ SharePointGraphResponse.SetRequestHelper(SharePointGraphRequestHelper);
+
+ if ItemId = '' then begin
+ SharePointGraphResponse.SetError(InvalidItemIdErr);
+ Session.LogMessage('', InvalidItemIdErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if UpdatePropertiesJsonObject.Keys().Count() = 0 then begin
+ SharePointGraphResponse.SetError(InvalidUpdateBodyErr);
+ Session.LogMessage('', InvalidUpdateBodyErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if not SharePointGraphRequestHelper.Patch(SharePointGraphUriBuilder.GetDriveItemByIdEndpoint(ItemId), UpdatePropertiesJsonObject, ResponseJson) then begin
+ ErrorMessage := StrSubstNo(FailedToUpdateDriveItemErr, SharePointGraphRequestHelper.GetDiagnostics().GetResponseReasonPhrase());
+ SharePointGraphResponse.SetError(ErrorMessage);
+ Session.LogMessage('', ErrorMessage, Verbosity::Error, DataClassification::CustomerContent, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ GraphDriveItem.Init();
+ GraphDriveItem.DriveId := CopyStr(DefaultDriveId, 1, MaxStrLen(GraphDriveItem.DriveId));
+ if not SharePointGraphParser.ParseDriveItemDetail(ResponseJson, GraphDriveItem) then begin
+ SharePointGraphResponse.SetError(FailedToParseUpdatedDriveItemErr);
+ Session.LogMessage('', FailedToParseUpdatedDriveItemErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+ GraphDriveItem.Insert();
+
+ SharePointGraphResponse.SetSuccess();
+ Session.LogMessage('', StrSubstNo(OperationSuccessTelemetryMsg, 'UpdateDriveItem'), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ ///
+ /// Updates a drive item's properties (name, description, etc.) by path.
+ ///
+ /// Path to the item (e.g., 'Documents/file.docx').
+ /// JSON object containing the properties to update.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ procedure UpdateDriveItemByPath(ItemPath: Text; UpdatePropertiesJsonObject: JsonObject; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ var
+ TempGraphDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ EnsureInitialized();
+ EnsureSiteId();
+ EnsureDefaultDriveId();
+
+ SharePointGraphResponse.SetRequestHelper(SharePointGraphRequestHelper);
+
+ if ItemPath = '' then begin
+ SharePointGraphResponse.SetError(InvalidItemPathErr);
+ Session.LogMessage('', InvalidItemPathErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ if UpdatePropertiesJsonObject.Keys().Count() = 0 then begin
+ SharePointGraphResponse.SetError(InvalidUpdateBodyErr);
+ Session.LogMessage('', InvalidUpdateBodyErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ SharePointGraphResponse := GetDriveItemByPath(ItemPath, TempGraphDriveItem);
+ if not SharePointGraphResponse.IsSuccessful() then
+ exit(SharePointGraphResponse);
+
+ exit(UpdateDriveItem(TempGraphDriveItem.Id, UpdatePropertiesJsonObject, GraphDriveItem));
+ end;
+
+ ///
+ /// Renames a drive item by ID.
+ ///
+ /// ID of the item to rename.
+ /// New name for the item.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ procedure RenameDriveItem(ItemId: Text; NewName: Text; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ var
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ RequestJsonObj: JsonObject;
+ begin
+ EnsureInitialized();
+ EnsureSiteId();
+ EnsureDefaultDriveId();
+
+ SharePointGraphResponse.SetRequestHelper(SharePointGraphRequestHelper);
+
+ if NewName = '' then begin
+ SharePointGraphResponse.SetError(InvalidNewNameErr);
+ Session.LogMessage('', InvalidNewNameErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ RequestJsonObj.Add('name', NewName);
+ exit(UpdateDriveItem(ItemId, RequestJsonObj, GraphDriveItem));
+ end;
+
+ ///
+ /// Renames a drive item by path.
+ ///
+ /// Path to the item (e.g., 'Documents/file.docx').
+ /// New name for the item.
+ /// Record to store the updated item details.
+ /// An operation response object containing the result of the operation.
+ procedure RenameDriveItemByPath(ItemPath: Text; NewName: Text; var GraphDriveItem: Record "SharePoint Graph Drive Item" temporary): Codeunit "SharePoint Graph Response"
+ var
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ RequestJsonObj: JsonObject;
+ begin
+ EnsureInitialized();
+ EnsureSiteId();
+ EnsureDefaultDriveId();
+
+ SharePointGraphResponse.SetRequestHelper(SharePointGraphRequestHelper);
+
+ if NewName = '' then begin
+ SharePointGraphResponse.SetError(InvalidNewNameErr);
+ Session.LogMessage('', InvalidNewNameErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GraphSharePointCategoryLbl);
+ exit(SharePointGraphResponse);
+ end;
+
+ RequestJsonObj.Add('name', NewName);
+ exit(UpdateDriveItemByPath(ItemPath, RequestJsonObj, GraphDriveItem));
+ end;
+
#endregion
///
diff --git a/src/System Application/App/SharePoint/src/graph/helpers/SharePointGraphUriBuilder.Codeunit.al b/src/System Application/App/SharePoint/src/graph/helpers/SharePointGraphUriBuilder.Codeunit.al
index d1b6395ee8..d10dbbbb1c 100644
--- a/src/System Application/App/SharePoint/src/graph/helpers/SharePointGraphUriBuilder.Codeunit.al
+++ b/src/System Application/App/SharePoint/src/graph/helpers/SharePointGraphUriBuilder.Codeunit.al
@@ -24,7 +24,9 @@ codeunit 9121 "SharePoint Graph Uri Builder"
ListsLbl: Label '/sites/%1/lists', Locked = true;
ListByIdLbl: Label '/sites/%1/lists/%2', Locked = true;
ListItemsLbl: Label '/sites/%1/lists/%2/items', Locked = true;
+ ListItemByIdLbl: Label '/sites/%1/lists/%2/items/%3', Locked = true;
CreateListItemLbl: Label '/sites/%1/lists/%2/items', Locked = true;
+ UpdateListItemFieldsLbl: Label '/sites/%1/lists/%2/items/%3/fields', Locked = true;
SiteByHostAndPathLbl: Label '/sites/%1:%2', Locked = true;
DriveLbl: Label '/sites/%1/drive', Locked = true;
DrivesLbl: Label '/sites/%1/drives', Locked = true;
@@ -113,6 +115,28 @@ codeunit 9121 "SharePoint Graph Uri Builder"
exit(StrSubstNo(CreateListItemLbl, SiteId, EscapeDataString(ListId)));
end;
+ ///
+ /// Gets the endpoint for getting a single list item by ID.
+ ///
+ /// The list ID.
+ /// The item ID.
+ /// The endpoint.
+ procedure GetListItemByIdEndpoint(ListId: Text; ItemId: Text): Text
+ begin
+ exit(StrSubstNo(ListItemByIdLbl, SiteId, EscapeDataString(ListId), EscapeDataString(ItemId)));
+ end;
+
+ ///
+ /// Gets the endpoint for updating list item fields.
+ ///
+ /// The list ID.
+ /// The item ID.
+ /// The endpoint.
+ procedure GetUpdateListItemFieldsEndpoint(ListId: Text; ItemId: Text): Text
+ begin
+ exit(StrSubstNo(UpdateListItemFieldsLbl, SiteId, EscapeDataString(ListId), EscapeDataString(ItemId)));
+ end;
+
///
/// Gets the endpoint for getting the default drive.
///
diff --git a/src/System Application/Test Library/SharePoint/src/graph/SharePointGraphTestLibrary.Codeunit.al b/src/System Application/Test Library/SharePoint/src/graph/SharePointGraphTestLibrary.Codeunit.al
index 07b1c5b4c9..d33f90d748 100644
--- a/src/System Application/Test Library/SharePoint/src/graph/SharePointGraphTestLibrary.Codeunit.al
+++ b/src/System Application/Test Library/SharePoint/src/graph/SharePointGraphTestLibrary.Codeunit.al
@@ -30,6 +30,31 @@ codeunit 132975 "SharePoint Graph Test Library"
MockHttpClientHandler.ExpectSendToFailWithError(ErrorText);
end;
+ procedure AddMockResponse(StatusCode: Integer; ResponseBody: Text)
+ begin
+ MockHttpClientHandler.AddResponse(StatusCode, ResponseBody);
+ end;
+
+ procedure AddMockResponse(var NewHttpResponseMessage: Codeunit "Http Response Message")
+ begin
+ MockHttpClientHandler.AddResponse(NewHttpResponseMessage);
+ end;
+
+ procedure GetMockHttpRequestUri(Index: Integer): Text
+ begin
+ exit(MockHttpClientHandler.GetHttpRequestUri(Index));
+ end;
+
+ procedure GetMockHttpRequestMethod(Index: Integer): Text
+ begin
+ exit(MockHttpClientHandler.GetHttpRequestMethod(Index));
+ end;
+
+ procedure GetMockRequestCount(): Integer
+ begin
+ exit(MockHttpClientHandler.GetRequestCount());
+ end;
+
procedure ResetMockHandler()
begin
Clear(this.MockHttpClientHandler);
diff --git a/src/System Application/Test Library/SharePoint/src/graph/SharePointHttpClientHandler.Codeunit.al b/src/System Application/Test Library/SharePoint/src/graph/SharePointHttpClientHandler.Codeunit.al
index 4389d9dd66..7b5334339a 100644
--- a/src/System Application/Test Library/SharePoint/src/graph/SharePointHttpClientHandler.Codeunit.al
+++ b/src/System Application/Test Library/SharePoint/src/graph/SharePointHttpClientHandler.Codeunit.al
@@ -13,9 +13,14 @@ codeunit 132981 "SharePoint Http Client Handler" implements "Http Client Handler
InherentPermissions = X;
var
- HttpRequestMessage: Codeunit "Http Request Message";
- HttpResponseMessage: Codeunit "Http Response Message";
- ResponseMessageSet: Boolean;
+ LastHttpRequestMessage: Codeunit "Http Request Message";
+ SingleHttpResponseMessage: Codeunit "Http Response Message";
+ HttpRequestUris: List of [Text];
+ HttpRequestMethods: List of [Text];
+ QueuedStatusCodes: List of [Integer];
+ QueuedBodies: List of [Text];
+ CurrentResponseIndex: Integer;
+ SingleResponseSet: Boolean;
SendError: Text;
procedure Send(HttpClient: HttpClient; InHttpRequestMessage: Codeunit "Http Request Message"; var OutHttpResponseMessage: Codeunit "Http Response Message") Success: Boolean;
@@ -31,23 +36,83 @@ codeunit 132981 "SharePoint Http Client Handler" implements "Http Client Handler
procedure SetResponse(var NewHttpResponseMessage: Codeunit "Http Response Message")
begin
- this.HttpResponseMessage := NewHttpResponseMessage;
- this.ResponseMessageSet := true;
+ Clear(this.QueuedStatusCodes);
+ Clear(this.QueuedBodies);
+ this.CurrentResponseIndex := 0;
+ Clear(this.HttpRequestUris);
+ Clear(this.HttpRequestMethods);
+ this.SingleHttpResponseMessage := NewHttpResponseMessage;
+ this.SingleResponseSet := true;
end;
procedure GetHttpRequestMessage(var OutHttpRequestMessage: Codeunit "Http Request Message")
begin
- OutHttpRequestMessage := this.HttpRequestMessage;
+ OutHttpRequestMessage := this.LastHttpRequestMessage;
+ end;
+
+ procedure AddResponse(StatusCode: Integer; ResponseBody: Text)
+ begin
+ this.QueuedStatusCodes.Add(StatusCode);
+ this.QueuedBodies.Add(ResponseBody);
+ end;
+
+ procedure AddResponse(var NewHttpResponseMessage: Codeunit "Http Response Message")
+ var
+ ResponseBody: Text;
+ begin
+ ResponseBody := NewHttpResponseMessage.GetContent().AsText();
+ AddResponse(NewHttpResponseMessage.GetHttpStatusCode(), ResponseBody);
+ end;
+
+ procedure GetHttpRequestUri(Index: Integer): Text
+ begin
+ if (Index > 0) and (Index <= this.HttpRequestUris.Count()) then
+ exit(this.HttpRequestUris.Get(Index));
+ end;
+
+ procedure GetHttpRequestMethod(Index: Integer): Text
+ begin
+ if (Index > 0) and (Index <= this.HttpRequestMethods.Count()) then
+ exit(this.HttpRequestMethods.Get(Index));
+ end;
+
+ procedure GetRequestCount(): Integer
+ begin
+ exit(this.HttpRequestUris.Count());
+ end;
+
+ procedure Reset()
+ begin
+ Clear(this.HttpRequestUris);
+ Clear(this.HttpRequestMethods);
+ Clear(this.QueuedStatusCodes);
+ Clear(this.QueuedBodies);
+ this.CurrentResponseIndex := 0;
+ this.SingleResponseSet := false;
+ this.SendError := '';
end;
[TryFunction]
local procedure TrySend(InHttpRequestMessage: Codeunit "Http Request Message"; var OutHttpResponseMessage: Codeunit "Http Response Message")
+ var
+ HttpContent: Codeunit "Http Content";
begin
- this.HttpRequestMessage := InHttpRequestMessage;
- if SendError <> '' then
- Error(SendError);
+ this.LastHttpRequestMessage := InHttpRequestMessage;
+ this.HttpRequestUris.Add(InHttpRequestMessage.GetRequestUri());
+ this.HttpRequestMethods.Add(InHttpRequestMessage.GetHttpMethod());
+
+ if this.SendError <> '' then
+ Error(this.SendError);
- if ResponseMessageSet then
- OutHttpResponseMessage := this.HttpResponseMessage;
+ if (this.QueuedBodies.Count() > 0) and (this.CurrentResponseIndex < this.QueuedBodies.Count()) then begin
+ this.CurrentResponseIndex += 1;
+ OutHttpResponseMessage.SetHttpStatusCode(this.QueuedStatusCodes.Get(this.CurrentResponseIndex));
+ HttpContent := HttpContent.Create(this.QueuedBodies.Get(this.CurrentResponseIndex));
+ OutHttpResponseMessage.SetContent(HttpContent);
+ end else
+ if this.SingleResponseSet then
+ OutHttpResponseMessage := this.SingleHttpResponseMessage
+ else
+ Error('No mock response queued. Request count: %1, queue size: %2', this.HttpRequestUris.Count(), this.QueuedBodies.Count());
end;
}
\ No newline at end of file
diff --git a/src/System Application/Test/DisabledTests/SharePointGraphAdvancedTest.json b/src/System Application/Test/DisabledTests/SharePointGraphAdvancedTest.json
deleted file mode 100644
index 63ce5b1732..0000000000
--- a/src/System Application/Test/DisabledTests/SharePointGraphAdvancedTest.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
- {
- "codeunitId": 132985,
- "CodeunitName": "SharePoint Graph Advanced Test",
- "Method": "TestCopyItemByPath"
- }
-]
\ No newline at end of file
diff --git a/src/System Application/Test/SharePoint/src/graph/SharePointGraphAdvancedTest.Codeunit.al b/src/System Application/Test/SharePoint/src/graph/SharePointGraphAdvancedTest.Codeunit.al
index e8f3581e29..27900427fa 100644
--- a/src/System Application/Test/SharePoint/src/graph/SharePointGraphAdvancedTest.Codeunit.al
+++ b/src/System Application/Test/SharePoint/src/graph/SharePointGraphAdvancedTest.Codeunit.al
@@ -611,17 +611,13 @@ codeunit 132985 "SharePoint Graph Advanced Test"
[Test]
procedure TestCopyItemByPath()
var
- HttpContent: Codeunit "Http Content";
- MockHttpContent: Codeunit "Http Content";
- MockHttpResponseMessage: Codeunit "Http Response Message";
SharePointGraphResponse: Codeunit "SharePoint Graph Response";
begin
- // [GIVEN] Mock response for CopyItemByPath
- Initialize();
- MockHttpResponseMessage.SetHttpStatusCode(202);
- MockHttpContent := HttpContent.Create('');
- MockHttpResponseMessage.SetContent(MockHttpContent);
- SharePointGraphTestLibrary.SetMockResponse(MockHttpResponseMessage);
+ // [GIVEN] Multi-response handler: GET (resolve target folder) + GET (resolve source item) + POST (copy)
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(202, '');
// [WHEN] Calling CopyItemByPath
SharePointGraphResponse := SharePointGraphClient.CopyItemByPath('Documents/Original.txt', 'Documents/Archive', 'CopiedFile.txt');
@@ -674,6 +670,298 @@ codeunit 132985 "SharePoint Graph Advanced Test"
LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'MoveItemByPath should succeed');
end;
+ [Test]
+ procedure TestCopyItemByPath_MultiResponse()
+ var
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Multi-response handler with queued responses for CopyItemByPath (resolve target folder, resolve source item, POST copy)
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(202, '');
+
+ // [WHEN] Calling CopyItemByPath
+ SharePointGraphResponse := SharePointGraphClient.CopyItemByPath('Documents/Original.txt', 'Documents/Archive', 'CopiedFile.txt');
+
+ // [THEN] Operation should succeed with 3 HTTP requests (resolve target, resolve source, POST copy)
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'CopyItemByPath should succeed');
+ LibraryAssert.AreEqual(3, SharePointGraphTestLibrary.GetMockRequestCount(), 'Should have made 3 HTTP requests');
+ LibraryAssert.AreEqual('GET', SharePointGraphTestLibrary.GetMockHttpRequestMethod(1), 'First request should be GET (resolve target folder)');
+ LibraryAssert.AreEqual('GET', SharePointGraphTestLibrary.GetMockHttpRequestMethod(2), 'Second request should be GET (resolve source item)');
+ LibraryAssert.AreEqual('POST', SharePointGraphTestLibrary.GetMockHttpRequestMethod(3), 'Third request should be POST (copy action)');
+ end;
+
+ [Test]
+ procedure TestMoveItemByPath_MultiResponse()
+ var
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Multi-response handler with queued responses for MoveItemByPath (resolve source item, PATCH move)
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+
+ // [WHEN] Calling MoveItemByPath
+ SharePointGraphResponse := SharePointGraphClient.MoveItemByPath('Documents/Original.txt', 'Documents/Archive', 'MovedFile.txt');
+
+ // [THEN] Operation should succeed; final call should be PATCH
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'MoveItemByPath should succeed');
+ LibraryAssert.IsTrue(SharePointGraphTestLibrary.GetMockRequestCount() >= 2, 'Should have made at least 2 HTTP requests');
+ LibraryAssert.AreEqual('PATCH', SharePointGraphTestLibrary.GetMockHttpRequestMethod(SharePointGraphTestLibrary.GetMockRequestCount()), 'Last request should be PATCH (move action)');
+ end;
+
+ [Test]
+ procedure TestQueueExhausted()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Multi-response handler with one response queued
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+
+ // [WHEN] First call consumes the only queued response, second call has no response
+ SharePointGraphResponse := SharePointGraphClient.GetDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', TempDriveItem);
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'First call should succeed');
+
+ asserterror SharePointGraphClient.GetDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', TempDriveItem);
+
+ // [THEN] Second call should fail because the queue is exhausted
+ LibraryAssert.ExpectedError('could not be established');
+ end;
+
+ [Test]
+ procedure TestStickyModeStillWorks()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ HttpContent: Codeunit "Http Content";
+ MockHttpContent: Codeunit "Http Content";
+ MockHttpResponseMessage: Codeunit "Http Response Message";
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Sticky (single) response set via SetMockResponse — original API with valid driveItem JSON
+ InitializeMultiResponse();
+ MockHttpResponseMessage.SetHttpStatusCode(200);
+ MockHttpContent := HttpContent.Create(GetDriveItemResponse());
+ MockHttpResponseMessage.SetContent(MockHttpContent);
+ SharePointGraphTestLibrary.SetMockResponse(MockHttpResponseMessage);
+
+ // [WHEN] Making two separate calls — sticky mode returns same response for both
+ SharePointGraphResponse := SharePointGraphClient.GetDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', TempDriveItem);
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'First call should succeed in sticky mode');
+
+ TempDriveItem.DeleteAll();
+ SharePointGraphResponse := SharePointGraphClient.GetDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', TempDriveItem);
+
+ // [THEN] Both calls succeed — sticky mode returns the same response on every Send
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'Second call should also succeed in sticky mode');
+ LibraryAssert.AreEqual(2, SharePointGraphTestLibrary.GetMockRequestCount(), 'Should have made 2 HTTP requests');
+ end;
+
+ [Test]
+ procedure TestUpdateDriveItem()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ UpdateProperties: JsonObject;
+ begin
+ // [GIVEN] Mock response for UpdateDriveItem
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetUpdatedDriveItemResponse());
+
+ // [WHEN] Calling UpdateDriveItem with name and description
+ UpdateProperties.Add('name', 'RenamedReport.docx');
+ UpdateProperties.Add('description', 'Updated description');
+ SharePointGraphResponse := SharePointGraphClient.UpdateDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', UpdateProperties, TempDriveItem);
+
+ // [THEN] Operation should succeed and return updated item
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'UpdateDriveItem should succeed');
+ LibraryAssert.AreEqual(1, SharePointGraphTestLibrary.GetMockRequestCount(), 'Should have made 1 HTTP request');
+ LibraryAssert.IsTrue(SharePointGraphTestLibrary.GetMockHttpRequestUri(1).Contains('/drive/items/01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ'), 'Request URI should target the correct item');
+ LibraryAssert.AreEqual('PATCH', SharePointGraphTestLibrary.GetMockHttpRequestMethod(1), 'Request method should be PATCH');
+ LibraryAssert.AreEqual('RenamedReport.docx', TempDriveItem.Name, 'Item name should be updated');
+ end;
+
+ [Test]
+ procedure TestRenameDriveItem()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Mock response for RenameDriveItem
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetUpdatedDriveItemResponse());
+
+ // [WHEN] Calling RenameDriveItem
+ SharePointGraphResponse := SharePointGraphClient.RenameDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', 'RenamedReport.docx', TempDriveItem);
+
+ // [THEN] Operation should succeed and request should be PATCH with name in body
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'RenameDriveItem should succeed');
+ LibraryAssert.AreEqual(1, SharePointGraphTestLibrary.GetMockRequestCount(), 'Should have made 1 HTTP request');
+ LibraryAssert.IsTrue(SharePointGraphTestLibrary.GetMockHttpRequestUri(1).Contains('/drive/items/01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ'), 'Request URI should target the correct item');
+ LibraryAssert.AreEqual('PATCH', SharePointGraphTestLibrary.GetMockHttpRequestMethod(1), 'Request method should be PATCH');
+ LibraryAssert.AreEqual('RenamedReport.docx', TempDriveItem.Name, 'Item name should be updated');
+ end;
+
+ [Test]
+ procedure TestRenameDriveItem_EmptyNewName()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Initialized client
+ InitializeMultiResponse();
+
+ // [WHEN] Calling RenameDriveItem with empty name
+ SharePointGraphResponse := SharePointGraphClient.RenameDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', '', TempDriveItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'RenameDriveItem should fail with empty name');
+ end;
+
+ [Test]
+ procedure TestUpdateDriveItemByPath()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ UpdateProperties: JsonObject;
+ begin
+ // [GIVEN] Multi-response handler: GET (resolve path) + PATCH (update)
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(200, GetUpdatedDriveItemResponse());
+
+ // [WHEN] Calling UpdateDriveItemByPath
+ UpdateProperties.Add('name', 'RenamedReport.docx');
+ SharePointGraphResponse := SharePointGraphClient.UpdateDriveItemByPath('Documents/Report.docx', UpdateProperties, TempDriveItem);
+
+ // [THEN] Operation should succeed with 2 HTTP requests (GET resolve + PATCH update)
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'UpdateDriveItemByPath should succeed');
+ LibraryAssert.AreEqual(2, SharePointGraphTestLibrary.GetMockRequestCount(), 'Should have made 2 HTTP requests');
+ LibraryAssert.AreEqual('GET', SharePointGraphTestLibrary.GetMockHttpRequestMethod(1), 'First request should be GET (resolve path)');
+ LibraryAssert.AreEqual('PATCH', SharePointGraphTestLibrary.GetMockHttpRequestMethod(2), 'Second request should be PATCH (update)');
+ LibraryAssert.AreEqual('RenamedReport.docx', TempDriveItem.Name, 'Item name should be updated');
+ end;
+
+ [Test]
+ procedure TestRenameDriveItemByPath()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Multi-response handler: GET (resolve path) + PATCH (rename)
+ InitializeMultiResponse();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetDriveItemResponse());
+ SharePointGraphTestLibrary.AddMockResponse(200, GetUpdatedDriveItemResponse());
+
+ // [WHEN] Calling RenameDriveItemByPath
+ SharePointGraphResponse := SharePointGraphClient.RenameDriveItemByPath('Documents/Report.docx', 'RenamedReport.docx', TempDriveItem);
+
+ // [THEN] Operation should succeed with 2 HTTP requests; final should be PATCH
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'RenameDriveItemByPath should succeed');
+ LibraryAssert.AreEqual(2, SharePointGraphTestLibrary.GetMockRequestCount(), 'Should have made 2 HTTP requests');
+ LibraryAssert.AreEqual('PATCH', SharePointGraphTestLibrary.GetMockHttpRequestMethod(2), 'Second request should be PATCH (rename)');
+ LibraryAssert.AreEqual('RenamedReport.docx', TempDriveItem.Name, 'Item name should be updated');
+ end;
+
+ [Test]
+ procedure TestUpdateDriveItem_EmptyItemId()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ UpdateProperties: JsonObject;
+ begin
+ // [GIVEN] Initialized client
+ InitializeMultiResponse();
+
+ // [WHEN] Calling UpdateDriveItem with empty item ID
+ UpdateProperties.Add('name', 'NewName.docx');
+ SharePointGraphResponse := SharePointGraphClient.UpdateDriveItem('', UpdateProperties, TempDriveItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'UpdateDriveItem should fail with empty item ID');
+ end;
+
+ [Test]
+ procedure TestUpdateDriveItem_EmptyBody()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ UpdateProperties: JsonObject;
+ begin
+ // [GIVEN] Initialized client
+ InitializeMultiResponse();
+
+ // [WHEN] Calling UpdateDriveItem with empty properties
+ SharePointGraphResponse := SharePointGraphClient.UpdateDriveItem('01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ', UpdateProperties, TempDriveItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'UpdateDriveItem should fail with empty body');
+ end;
+
+ [Test]
+ procedure TestUpdateDriveItemByPath_EmptyPath()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ UpdateProperties: JsonObject;
+ begin
+ // [GIVEN] Initialized client
+ InitializeMultiResponse();
+
+ // [WHEN] Calling UpdateDriveItemByPath with empty path
+ UpdateProperties.Add('name', 'NewName.docx');
+ SharePointGraphResponse := SharePointGraphClient.UpdateDriveItemByPath('', UpdateProperties, TempDriveItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'UpdateDriveItemByPath should fail with empty path');
+ end;
+
+ [Test]
+ procedure TestRenameDriveItemByPath_EmptyPath()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Initialized client
+ InitializeMultiResponse();
+
+ // [WHEN] Calling RenameDriveItemByPath with empty path
+ SharePointGraphResponse := SharePointGraphClient.RenameDriveItemByPath('', 'NewName.docx', TempDriveItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'RenameDriveItemByPath should fail with empty path');
+ end;
+
+ [Test]
+ procedure TestRenameDriveItemByPath_EmptyName()
+ var
+ TempDriveItem: Record "SharePoint Graph Drive Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Initialized client
+ InitializeMultiResponse();
+
+ // [WHEN] Calling RenameDriveItemByPath with empty name
+ SharePointGraphResponse := SharePointGraphClient.RenameDriveItemByPath('Documents/Report.docx', '', TempDriveItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'RenameDriveItemByPath should fail with empty name');
+ end;
+
+ local procedure InitializeMultiResponse()
+ var
+ MockHttpClientHandler: Interface "Http Client Handler";
+ begin
+ SharePointGraphTestLibrary.ResetMockHandler();
+ MockHttpClientHandler := SharePointGraphTestLibrary.GetMockHandler();
+ SharePointGraphClient.Initialize(SharePointUrlLbl, Enum::"Graph API Version"::"v1.0", SharePointGraphAuthMock, MockHttpClientHandler);
+ SharePointGraphClient.SetSiteIdForTesting('contoso.sharepoint.com,e6991d99-75d5-4be4-4ede-2c82b1d40cd6,1b58abad-4105-4125-a0e0-7a6d39571a5b');
+ SharePointGraphClient.SetDefaultDriveIdForTesting('b!mR2-5tV1S-RO3C82s1DNbdCrWBwFQKFUoOB6bTlXClvD9fcjLXO5TbNk5sDyD7c8');
+ end;
+
local procedure Initialize()
var
MockHttpClientHandler: Interface "Http Client Handler";
@@ -964,4 +1252,27 @@ codeunit 132985 "SharePoint Graph Advanced Test"
ResponseText.Append('}');
exit(ResponseText.ToText());
end;
+
+ local procedure GetUpdatedDriveItemResponse(): Text
+ var
+ ResponseText: TextBuilder;
+ begin
+ ResponseText.Append('{');
+ ResponseText.Append(' "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#driveItems/$entity",');
+ ResponseText.Append(' "id": "01EZJNRYQYENJ6SXVPCNBYA3QZRHKJWLNZ",');
+ ResponseText.Append(' "name": "RenamedReport.docx",');
+ ResponseText.Append(' "description": "Updated description",');
+ ResponseText.Append(' "createdDateTime": "2023-05-10T14:25:37Z",');
+ ResponseText.Append(' "lastModifiedDateTime": "2023-08-01T11:15:42Z",');
+ ResponseText.Append(' "webUrl": "https://contoso.sharepoint.com/sites/test/Shared%20Documents/RenamedReport.docx",');
+ ResponseText.Append(' "file": {');
+ ResponseText.Append(' "mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",');
+ ResponseText.Append(' "hashes": {');
+ ResponseText.Append(' "quickXorHash": "dF5GC7lcTJbHDrcPKJc8rJtEhCo="');
+ ResponseText.Append(' }');
+ ResponseText.Append(' },');
+ ResponseText.Append(' "size": 45321');
+ ResponseText.Append('}');
+ exit(ResponseText.ToText());
+ end;
}
\ No newline at end of file
diff --git a/src/System Application/Test/SharePoint/src/graph/SharePointGraphClientTest.Codeunit.al b/src/System Application/Test/SharePoint/src/graph/SharePointGraphClientTest.Codeunit.al
index 12aa89b04c..93f90a34f8 100644
--- a/src/System Application/Test/SharePoint/src/graph/SharePointGraphClientTest.Codeunit.al
+++ b/src/System Application/Test/SharePoint/src/graph/SharePointGraphClientTest.Codeunit.al
@@ -186,6 +186,167 @@ codeunit 132984 "SharePoint Graph Client Test"
LibraryAssert.AreEqual('3', TempListItem.Id, 'Id should match');
end;
+ [Test]
+ procedure TestGetListItem()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ HttpContent: Codeunit "Http Content";
+ MockHttpContent: Codeunit "Http Content";
+ MockHttpResponseMessage: Codeunit "Http Response Message";
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] Mock response for GetListItem
+ Initialize();
+ MockHttpResponseMessage.SetHttpStatusCode(200);
+ MockHttpContent := HttpContent.Create(GetListItemResponse());
+ MockHttpResponseMessage.SetContent(MockHttpContent);
+ SharePointGraphTestLibrary.SetMockResponse(MockHttpResponseMessage);
+
+ // [WHEN] Calling GetListItem
+ SharePointGraphResponse := SharePointGraphClient.GetListItem('01bjtwww-5j35-426b-a4d5-608f6e2a9f84', '1', TempListItem);
+
+ // [THEN] Operation should succeed and return correct data
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'GetListItem should succeed');
+ LibraryAssert.AreEqual('1', TempListItem.Id, 'Id should match');
+ LibraryAssert.AreEqual('Test Item 1', TempListItem.Title, 'Title should match');
+ LibraryAssert.AreEqual('Item', TempListItem.ContentType, 'ContentType should match');
+ end;
+
+ [Test]
+ procedure TestGetListItem_EmptyListId()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] An initialized client
+ Initialize();
+
+ // [WHEN] Calling GetListItem with empty ListId
+ SharePointGraphResponse := SharePointGraphClient.GetListItem('', '1', TempListItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'GetListItem should fail with empty ListId');
+ end;
+
+ [Test]
+ procedure TestGetListItem_EmptyItemId()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ begin
+ // [GIVEN] An initialized client
+ Initialize();
+
+ // [WHEN] Calling GetListItem with empty ItemId
+ SharePointGraphResponse := SharePointGraphClient.GetListItem('01bjtwww-5j35-426b-a4d5-608f6e2a9f84', '', TempListItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'GetListItem should fail with empty ItemId');
+ end;
+
+ [Test]
+ procedure TestUpdateListItem()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ FieldsJson: JsonObject;
+ begin
+ // [GIVEN] Mock responses for UpdateListItem (PATCH fields + follow-up GET)
+ Initialize();
+ SharePointGraphTestLibrary.ResetMockHandler();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetUpdateListItemFieldsResponse());
+ SharePointGraphTestLibrary.AddMockResponse(200, GetListItemResponse());
+
+ // [WHEN] Calling UpdateListItem
+ FieldsJson.Add('Title', 'Updated Title');
+ FieldsJson.Add('Status', 'Approved');
+ SharePointGraphResponse := SharePointGraphClient.UpdateListItem('01bjtwww-5j35-426b-a4d5-608f6e2a9f84', '1', FieldsJson, TempListItem);
+
+ // [THEN] Operation should succeed and return the full item from the follow-up GET
+ LibraryAssert.IsTrue(SharePointGraphResponse.IsSuccessful(), 'UpdateListItem should succeed');
+ LibraryAssert.AreEqual('1', TempListItem.Id, 'Id should match');
+ LibraryAssert.AreEqual('Test Item 1', TempListItem.Title, 'Title should match from GET response');
+ LibraryAssert.AreEqual(2, SharePointGraphTestLibrary.GetMockRequestCount(), 'Should have made 2 requests (PATCH + GET)');
+ LibraryAssert.IsTrue(SharePointGraphTestLibrary.GetMockHttpRequestMethod(1).Contains('PATCH'), 'First request should be PATCH');
+ LibraryAssert.IsTrue(SharePointGraphTestLibrary.GetMockHttpRequestMethod(2).Contains('GET'), 'Second request should be GET');
+ LibraryAssert.IsTrue(SharePointGraphTestLibrary.GetMockHttpRequestUri(1).Contains('/fields'), 'First request URI should target /fields');
+ end;
+
+ [Test]
+ procedure TestUpdateListItem_EmptyListId()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ FieldsJson: JsonObject;
+ begin
+ // [GIVEN] An initialized client
+ Initialize();
+ FieldsJson.Add('Title', 'Updated');
+
+ // [WHEN] Calling UpdateListItem with empty ListId
+ SharePointGraphResponse := SharePointGraphClient.UpdateListItem('', '1', FieldsJson, TempListItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'UpdateListItem should fail with empty ListId');
+ end;
+
+ [Test]
+ procedure TestUpdateListItem_EmptyItemId()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ FieldsJson: JsonObject;
+ begin
+ // [GIVEN] An initialized client
+ Initialize();
+ FieldsJson.Add('Title', 'Updated');
+
+ // [WHEN] Calling UpdateListItem with empty ItemId
+ SharePointGraphResponse := SharePointGraphClient.UpdateListItem('01bjtwww-5j35-426b-a4d5-608f6e2a9f84', '', FieldsJson, TempListItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'UpdateListItem should fail with empty ItemId');
+ end;
+
+ [Test]
+ procedure TestUpdateListItem_EmptyFields()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ FieldsJson: JsonObject;
+ begin
+ // [GIVEN] An initialized client with empty fields JSON
+ Initialize();
+
+ // [WHEN] Calling UpdateListItem with empty FieldsJsonObject
+ SharePointGraphResponse := SharePointGraphClient.UpdateListItem('01bjtwww-5j35-426b-a4d5-608f6e2a9f84', '1', FieldsJson, TempListItem);
+
+ // [THEN] Operation should fail with validation error
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'UpdateListItem should fail with empty fields');
+ end;
+
+ [Test]
+ procedure TestUpdateListItem_FollowUpGetFails()
+ var
+ TempListItem: Record "SharePoint Graph List Item" temporary;
+ SharePointGraphResponse: Codeunit "SharePoint Graph Response";
+ FieldsJson: JsonObject;
+ begin
+ // [GIVEN] Mock responses: successful PATCH, then a 404 on the follow-up GET
+ Initialize();
+ SharePointGraphTestLibrary.ResetMockHandler();
+ SharePointGraphTestLibrary.AddMockResponse(200, GetUpdateListItemFieldsResponse());
+ SharePointGraphTestLibrary.AddMockResponse(404, GetErrorResponse());
+
+ // [WHEN] Calling UpdateListItem
+ FieldsJson.Add('Title', 'Updated Title');
+ SharePointGraphResponse := SharePointGraphClient.UpdateListItem('01bjtwww-5j35-426b-a4d5-608f6e2a9f84', '1', FieldsJson, TempListItem);
+
+ // [THEN] Operation should fail (the GET failed), but both requests were made
+ LibraryAssert.IsFalse(SharePointGraphResponse.IsSuccessful(), 'UpdateListItem should fail when follow-up GET fails');
+ LibraryAssert.AreEqual(2, SharePointGraphTestLibrary.GetMockRequestCount(), 'Both PATCH and GET requests should have fired');
+ end;
+
[Test]
procedure TestGetDrives()
var
@@ -736,6 +897,41 @@ codeunit 132984 "SharePoint Graph Client Test"
exit(ResponseText.ToText());
end;
+ local procedure GetListItemResponse(): Text
+ var
+ ResponseText: TextBuilder;
+ begin
+ ResponseText.Append('{');
+ ResponseText.Append(' "id": "1",');
+ ResponseText.Append(' "contentType": {');
+ ResponseText.Append(' "id": "0x0100",');
+ ResponseText.Append(' "name": "Item"');
+ ResponseText.Append(' },');
+ ResponseText.Append(' "createdDateTime": "2023-05-15T08:12:39Z",');
+ ResponseText.Append(' "lastModifiedDateTime": "2023-06-20T14:45:12Z",');
+ ResponseText.Append(' "webUrl": "https://contoso.sharepoint.com/sites/test/Lists/Test%20List/1_.000",');
+ ResponseText.Append(' "fields": {');
+ ResponseText.Append(' "Title": "Test Item 1",');
+ ResponseText.Append(' "Description": "This is a test item",');
+ ResponseText.Append(' "Priority": "High"');
+ ResponseText.Append(' }');
+ ResponseText.Append('}');
+ exit(ResponseText.ToText());
+ end;
+
+ local procedure GetUpdateListItemFieldsResponse(): Text
+ var
+ ResponseText: TextBuilder;
+ begin
+ ResponseText.Append('{');
+ ResponseText.Append(' "Title": "Updated Title",');
+ ResponseText.Append(' "Status": "Approved",');
+ ResponseText.Append(' "Description": "This is a test item",');
+ ResponseText.Append(' "Priority": "High"');
+ ResponseText.Append('}');
+ exit(ResponseText.ToText());
+ end;
+
local procedure GetErrorResponse(): Text
var
ResponseText: TextBuilder;