delphimicrosoft-graph-apionedrive

Get link to file in shared onedrive folder where file isn't directly shared


I'm working on a onedrive integration in my app. The idea is that users that have the onedrive file explorer client installed can drag a file and the app is able to generate a link to the file online.

I've pretty much implemented it but there is one situation that I can't get working.

For regular onedrive files I use:

RESTRequest1.Resource := Format('/me/drive/root:/%s:/createLink', [RelativePath]); 

And for shared files I use

RESTRequest1.Resource := '/me/drive/sharedWithMe';

And then I loop through shared files until I find matching file and then I grab the webUrl from the response.

The problem is this though. There is a folder shared with me and for this folder I added a shortcut to the shared folder in my OneDrive like described here. One of the files in this folder is also shared directly with me, the other one isn't. The file that's shared directly with me I can find using /me/drive/sharedWithMe. But I'm not able to retrieve the file that isn't shared directly with me. It is in the shared folder though so I thought I should be able to.

I tried some different things like looking if I could get the shared folder by calling this: /me/drive/root/children. But this gives me all folders and files except for the shared folder.

Is it possible what I'm trying to do?


Solution

  • I was able to figure something out.

    Like I mentioned in my question I had tried this endpoint: /me/drive/root/children. But this gives me all folders and files except for the shared folder.

    I found something interesting in the response when I tried this endpoint: me/drive/root. The response contained: "folder":{"childCount":7}. 7 is the correct number of files and folders in the root onedrive directory including the shortcut to the shared folder.

    I find it strange that this endpoint shows the correct count, but that the children endpoint does not get the shared folder, but either way because of this I did try to get info on the shared folder directly with this endpoint: /me/drive/root:/NameSharedFolder:/ and that actually worked. Got back something like this:

    {
      "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)/$entity",
      "createdBy": {
        "application": {
          "id": "id",
          "displayName": "SharePoint Online Client Extensibility"
        },
        "user": {
          "email": "email",
          "id": "id",
          "displayName": "displayname"
        }
      },
      "createdDateTime": "2025-02-17T09:26:14Z",
      "eTag": "\"{tag},3\"",
      "id": "id",
      "lastModifiedBy": {
        "user": {
          "email": "email",
          "id": "id",
          "displayName": "displayName"
        }
      },
      "lastModifiedDateTime": "2025-02-17T09:26:15Z",
      "name": "NameSharedFolder",
      "parentReference": {
        "driveType": "business",
        "driveId": "driveID",
        "id": "id",
        "name": "Documents",
        "path": "/drive/root:",
        "siteId": "siteID"
      },
      "cTag": "\"c:{tag},1\"",
      "fileSystemInfo": {
        "createdDateTime": "2025-02-17T09:26:14Z",
        "lastModifiedDateTime": "2025-02-17T09:26:15Z"
      },
      "remoteItem": {
        "folder": {
          "childCount": 2
        },
        "id": "id",
        "parentReference": {
          "driveType": "business",
          "driveId": "driveID"
        },
        "sharepointIds": {
          "listId": "id",
          "listItemUniqueId": "id",
          "siteId": "id",
          "siteUrl": "id",
          "webId": "id",
          "webRelativeListUrl": "Documents"
        },
        "size": 31810
      },
      "size": 0
    }
    

    From this I could get the driveID and folderID (id) and do a request to /drives/{drive-id}/items/{item-id}/children. The response of this request listed the file with webUrl.

    This is the delphi code that gives me the file link:

    
      RESTRequest1.Resource := '/me/drive/root:/' + ExtractFileDir(RelativePath) + ':/';
      RESTRequest1.Method := rmGET;
      RESTRequest1.Params.Clear;
      RESTRequest1.Execute;
    
      if RestRequest1.Response.StatusCode = 200 then
      begin
        var sharedFolder := TJSONObject.ParseJSONValue(RestRequest1.Response.Content) as TJSONObject;
        try
          if sharedFolder.Values['remoteItem'] <> nil then
          begin
            var remoteItem := sharedFolder.Values['remoteItem'] as TJSONObject;
            folderID := remoteItem.GetValue<string>('id');
            driveID := TJSONObject(remoteItem.GetValue('parentReference')).GetValue<string>('driveId');
          end else
          begin
            folderID := sharedFolder.GetValue<string>('id');
            driveID := TJSONObject(sharedFolder.Values['parentReference']).GetValue<string>('driveId');
          end;
        finally
          sharedFolder.Free;
        end;
    
        RESTRequest1.Resource := '/drives/' + driveID + '/items/' + folderID + '/children';
        RESTRequest1.Method := rmGET;
        RESTRequest1.Params.Clear;
        RESTRequest1.Execute;
    
        if RestRequest1.Response.StatusCode = 200 then
        begin
          var sharedFolderItems := TJSONObject.ParseJSONValue(RestRequest1.Response.Content) as TJSONObject;
          try
            var sharedFolderItemsArray := sharedFolderItems.GetValue<TJSONArray>('value');
            var fileName := ExtractFileName(RelativePath);
            for var I := 0 to sharedFolderItemsArray.Count - 1 do
            begin
              var item := sharedFolderItemsArray.Items[I] as TJSONObject;
              if SameText(item.GetValue<string>('name'), fileName) then
              begin
                var webURL := item.GetValue<string>('webUrl'); // Got webURL do something with it...
                Break;
              end;
            end;
          finally
            sharedFolderItems.Free;
          end;
        end;
      end;