# Task OP-12917 - Investigate GRAPH API in regard of checklist

Project: OpenProject
Status: closed
URL: https://community.openproject.org/work_packages/OP-12917

## Details

| Attribute | Value |
| --- | --- |
| Assignee |  |
| Date |  |
| Priority | Medium |
| Target versions | 13.1.0 |
| Category |  |
| Labels |  |

## Description

*   check GRAPH API from microsoft
*   challenge the bullet points on the check list
*   attach result

## Result

### The file storage must have a HTTP API

- it is called the [GRAPH API](https://learn.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0)

### The user must be able to authenticate the requests against the API.

- OAuth2 possible, seems to work with PKCE
- App needs to be registered (see [registration portal](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade))
    - to get client id and secret
- scopes are very verbose, e.g. we have `files.read.all`, `sites.read.all`
  - we need to check, which scopes are needed for all the requests to the API
- Client Authentication: Send client credentials in body 

### The file storage must have uniquely identifiable files across the user context. (Any user must be able to find the file with the same identification data.)

- any file is represented as a `driveItem`
- every user has her own `driveItems`
- when a resource is shared, the non-owners create their own `driveItem` with a different id
- BUT: any user can access a file with the drive-id (the owners id if shared) and the original file id

```shell
# Get a file from file storage by data stored in file link
# drive-id -> origin-drive-id
# item-id -> origin-file-id
GET /drive/:drive-id/items/:item-id
```

- example for a response by own `driveItem` id (`GET /drive/items/:item-id`)

```json
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#drive/items/$entity",
    "@microsoft.graph.downloadUrl": "https://public.db.files.1drv.com/y4mxeVS8q771a2htB5Z3aHAXMiGw7NNg0SWQmKUQooHg3q1UxhxPF3crM6FhrpyEY3-nH_EuWd-4AGMVzfLUrf3Akm3jNt35VJgj-abqc2YbAuxabBlU77Q2UrDg92EiiK6akPYKesDsoEjVpm7u85y3Rn6u2b1sY8kVF9L6kldS5c",
    "createdDateTime": "2023-07-11T14:27:49.023Z",
    "cTag": "aYzozNzExN0U0QTczODZEMTM1ITEyNDQyLjI1Nw",
    "eTag": "aMzcxMTdFNEE3Mzg2RDEzNSExMjQ0Mi41",
    "id": "37117E4A7386D135!12442",
    "lastModifiedDateTime": "2023-07-11T14:56:38.1Z",
    "name": "minecraft.jpg",
    "webUrl": "https://1drv.ms/u/s!AGtRbJQ1MF2ugh4",
    "parentReference": {
        "driveId": "37117e4a7386d135",
        "driveType": "personal"
    },
    "remoteItem": {
        "id": "AE5D3035946C516B!286",
        "lastModifiedDateTime": "2023-07-11T14:56:28.01Z",
        "name": "minecraft.jpg",
        "size": 989752,
        "webUrl": "https://1drv.ms/u/s!AGtRbJQ1MF2ugh4",
        "createdBy": {
            "user": {
                "displayName": "Andreas Pfohl",
                "id": "ae5d3035946c516b"
            }
        },
        "fileSystemInfo": {
            "createdDateTime": "2023-07-11T14:27:01.04Z",
            "lastModifiedDateTime": "2023-07-11T14:27:01.04Z"
        },
        "file": {
            "mimeType": "image/jpeg",
            "hashes": {
                "sha1Hash": "B04425A74698BDFEBA2F33207F6F69A128DB7265"
            }
        },
        "lastModifiedBy": {
            "user": {
                "displayName": "Andreas Pfohl",
                "id": "ae5d3035946c516b"
            }
        },
        "parentReference": {
            "driveId": "ae5d3035946c516b",
            "driveType": "personal"
        },
        "shared": {
            "sharedDateTime": "2023-07-11T14:27:49.023Z",
            "owner": {
                "user": {
                    "displayName": "Andreas Pfohl",
                    "id": "ae5d3035946c516b"
                }
            }
        }
    }
}
```

- under `remoteItem` one can find the original `id` and the `drive-id` at `remoteItem.shared.owner.user.id`


### The file storage must provide a direct link to open the file on the file storage's web interface.

- see example above
- direct open link can be found at `webUrl`

### The file storage must be able to fetch an index for a location, providing all children files and folders on this location.

- Getting the content of a folder: `GET /drive/:drive-id/items/:item-id/children`
- if executed on a file, not a folder, return success with count 0

```json
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#drives('ae5d3035946c516b')/items('AE5D3035946C516B%21288')/children",
    "@odata.count": 1,
    "value": [
        {
            "@microsoft.graph.downloadUrl": "https://public.am.files.1drv.com/y4mS6pRX18eJZt9lfAsDriqsxIIyAE66YE4YyPZcVyeob2hUz2ioa3FvYAiLlAZpNKu7gDor8Q0gT5DQQhwJoGSVZOPg6lrbOFIbPl9CkdfQ_VynSfMh9I2jrw6n4OkenmNOh2aTfjRd9_tOQEc9t7nE-OFVVVmysRp-inWpIBTLB2z7aYdBLY0BLE25_RRWmA9HTlMvb6NcOGOOPL3EdNUMRYBPrS3fwCtgTYQs8W3kbI",
            "createdDateTime": "2023-07-11T15:17:04.867Z",
            "cTag": "aYzpBRTVEMzAzNTk0NkM1MTZCITI4OS4yNTc",
            "eTag": "aQUU1RDMwMzU5NDZDNTE2QiEyODkuNQ",
            "id": "AE5D3035946C516B!289",
            "lastModifiedDateTime": "2023-07-11T15:35:42.58Z",
            "name": "der_laufende.jpeg",
            "size": 13131,
            "webUrl": "https://1drv.ms/i/s!AGtRbJQ1MF2ugiE",
            "reactions": {
                "commentCount": 0
            },
            "createdBy": {
                "application": {
                    "displayName": "OneDrive",
                    "id": "481710a4"
                },
                "user": {
                    "displayName": "Eric Schubert",
                    "id": "37117e4a7386d135"
                }
            },
            "lastModifiedBy": {
                "user": {
                    "displayName": "Eric Schubert",
                    "id": "37117e4a7386d135"
                }
            },
            "parentReference": {
                "driveId": "ae5d3035946c516b",
                "driveType": "personal",
                "id": "AE5D3035946C516B!288",
                "name": "shared_with_eric",
                "path": "/drives/ae5d3035946c516b/items/AE5D3035946C516B!288:"
            },
            "file": {
                "mimeType": "image/jpeg",
                "hashes": {
                    "quickXorHash": "6oXtlk9YAgB8dKbI9BrusgVQGLU=",
                    "sha1Hash": "96BBF5E84B3FF9B42FBE986F1B63F7C62A973DD0",
                    "sha256Hash": "94891E6D7092A1AB652536B5C0E1D0DF575821F3C149E3D010AD037EC0AD3D0E"
                }
            },
            "fileSystemInfo": {
                "createdDateTime": "2023-07-11T15:17:04.866Z",
                "lastModifiedDateTime": "2023-07-11T15:17:04.866Z"
            },
            "image": {
                "height": 353,
                "width": 177
            },
            "photo": {},
            "shared": {
                "scope": "users",
                "owner": {
                    "user": {
                        "displayName": "Andreas Pfohl",
                        "id": "ae5d3035946c516b"
                    }
                }
            }
        }
    ]
}
```

- to get the breadcrumbs, each parent reference has to be followed to the root.

### Optional: The file storage must provide a direct download link for the file.

- see example above
- direct download link can be found at `@microsoft.graph.downloadUrl`

### Optional: The file storage must provide a direct upload link for files to a location on the file storage.

- to make unauthenticated upload request see [resumable uploads](https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0)
