diff --git a/.fern/metadata.json b/.fern/metadata.json index 6d470d4f..01901e98 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -10,10 +10,10 @@ "base-exception-class-name": "CloudPDFException", "base-api-exception-class-name": "CloudPDFApiException" }, - "originGitCommit": "07aa3f26c82243b36a5ec94f7072130c7298d977", + "originGitCommit": "3a88df90980e5c0546a5ebbfd1252d8fca77ff9b", "originGitCommitIsDirty": false, "invokedBy": "ci", - "requestedVersion": "3.0.0-next.17", + "requestedVersion": "3.0.0-next.18", "ciProvider": "github", - "sdkVersion": "3.0.0-next.17" + "sdkVersion": "3.0.0-next.18" } \ No newline at end of file diff --git a/cloudpdf-generation.json b/cloudpdf-generation.json index 895c80f4..d5105713 100644 --- a/cloudpdf-generation.json +++ b/cloudpdf-generation.json @@ -1,12 +1,12 @@ { "language": "csharp", - "canonicalVersion": "3.0.0-next.17", - "sdkVersion": "3.0.0-next.17", + "canonicalVersion": "3.0.0-next.18", + "sdkVersion": "3.0.0-next.18", "source": { "repository": "embedpdf/embed-pdf-viewer", "openapi": "cloudpdf/contract/openapi.json", - "openapiSha256": "8fa53cef2776eb0de9ec50c263aa547b309a04d1a2ecb6ee54b6338d6698dc00", - "gitCommit": "07aa3f26c82243b36a5ec94f7072130c7298d977", + "openapiSha256": "ad2a3baa628061e7b3e8b597cfd15bcda7f103d0f829cb01388a0fed6c4f5873", + "gitCommit": "3a88df90980e5c0546a5ebbfd1252d8fca77ff9b", "gitCommitIsDirty": false }, "fern": { diff --git a/reference.md b/reference.md index 3121487f..a87033d5 100644 --- a/reference.md +++ b/reference.md @@ -1150,6 +1150,67 @@ await client.Documents.DeleteAsync(new DeleteDocumentsRequest { TenantId = "tena + + + + +
client.Documents.UpdateAsync(DocumentsUpdateRequest { ... }) -> WithRawResponseTask<DocumentsUpdate200Response> +
+
+ +#### 📝 Description + +
+
+ +
+
+ +A document that is being deleted answers 404. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Documents.UpdateAsync( + new DocumentsUpdateRequest + { + TenantId = "tenantId", + Id = "id", + Name = "name", + } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `DocumentsUpdateRequest` + +
+
+
+
+ +
@@ -1448,6 +1509,316 @@ await client.Documents.InitAsync( + + + + +## Folders +
client.Folders.ListAsync(ListFoldersRequest { ... }) -> WithRawResponseTask<FoldersList200Response> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Folders.ListAsync(new ListFoldersRequest { TenantId = "tenantId" }); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `ListFoldersRequest` + +
+
+
+
+ + +
+
+
+ +
client.Folders.CreateAsync(FoldersCreateRequest { ... }) -> WithRawResponseTask<FoldersCreate200Response> +
+
+ +#### 📝 Description + +
+
+ +
+
+ +409 Conflict carries `details.reason`: `name-taken` (a sibling has the name, ignoring case; `details.name`) or `too-deep` (folders nest at most 100 levels; `details.maxDepth`). 404 when the parent folder does not exist. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Folders.CreateAsync(new FoldersCreateRequest { TenantId = "tenantId", Name = "name" }); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `FoldersCreateRequest` + +
+
+
+
+ + +
+
+
+ +
client.Folders.GetAsync(GetFoldersRequest { ... }) -> WithRawResponseTask<FoldersGet200Response> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Folders.GetAsync( + new GetFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `GetFoldersRequest` + +
+
+
+
+ + +
+
+
+ +
client.Folders.DeleteAsync(DeleteFoldersRequest { ... }) -> WithRawResponseTask +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Without recursive, a folder with anything inside is refused: 409 Conflict with `details.reason` `not-empty` and what it holds, counted over every level below, in `details.folders` and `details.documents`. With recursive=true, the folder and every folder under it go at once, and every document in them stops opening, leaves every list and stops answering its share links at once; their stored files and links are removed in the background. Uploads into those folders that have not committed cannot commit. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Folders.DeleteAsync( + new DeleteFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `DeleteFoldersRequest` + +
+
+
+
+ + +
+
+
+ +
client.Folders.UpdateAsync(FoldersUpdateRequest { ... }) -> WithRawResponseTask<FoldersUpdate200Response> +
+
+ +#### 📝 Description + +
+
+ +
+
+ +409 Conflict with `details.reason` `name-taken` when a sibling has the name, ignoring case. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Folders.UpdateAsync( + new FoldersUpdateRequest + { + TenantId = "tenantId", + FolderId = "folderId", + Name = "name", + } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `FoldersUpdateRequest` + +
+
+
+
+ + +
+
+
+ +
client.Folders.MoveIntoAsync(FoldersMoveIntoRequest { ... }) -> WithRawResponseTask +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Up to 1,000 ids in total. A folder moves with everything in it. 404 NotFound names the ids that do not exist or are being deleted in `details.documentIds` and `details.folderIds`. 409 Conflict carries `details.reason`: `cycle` (the destination is a moved folder or inside one; `details.folderId`), `too-deep` (the move would nest folders deeper than 100 levels; `details.maxDepth`) or `name-taken` (a moved folder's name is taken in the destination, ignoring case; `details.name`). +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Folders.MoveIntoAsync( + new FoldersMoveIntoRequest { TenantId = "tenantId", FolderId = "folderId" } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `FoldersMoveIntoRequest` + +
+
+
+
+ +
@@ -3119,7 +3490,7 @@ await client.Doc.Signatures.CancelAsync(
-`cms` is the detached CMS over the prepared digest, base64. `expectedVersion` must be what prepare returned. Idempotent by signing id: the same CMS again answers `already-completed`. Every layer of the document then sits over the new version; refetch the manifest after a completion. +`cms` is the detached CMS over the prepared digest, base64. `expectedVersion` must be what prepare returned. Idempotent by signing id: the same CMS again answers `already-completed`. The new version is the layer's own: only this layer moves to it, and the document and every other layer stay as they were. Refetch the manifest after a completion.
@@ -3242,7 +3613,7 @@ await client.Doc.Signatures.AnalysisAsync(
-Multipart: a JSON `body` part (field, subFilter, digest, contentsSize, signer, certify, lock), naming the appearance PDF it may carry as `resources: { appearance: '' }`, and that PDF as the part `resource:`. A certification (`certify.permission`) additionally requires `doc.sign.certify`. The layer is read-only until the signing completes, is cancelled, or expires (15 minutes). A layer behind the document head cannot sign (StaleBase). +Multipart: a JSON `body` part (field, subFilter, digest, contentsSize, signer, certify, lock), naming the appearance PDF it may carry as `resources: { appearance: '' }`, and that PDF as the part `resource:`. A certification (`certify.permission`) additionally requires `doc.sign.certify`. The layer is read-only until the signing completes, is cancelled, or expires (15 minutes). The signature is made over the layer's own base: the upload, or the version its last signature made.
@@ -3299,7 +3670,7 @@ await client.Doc.Signatures.PrepareAsync(
-Every completed signature publishes a new version. Never cached: the list grows. +Every completed signature makes a new version of its layer; another layer's versions are never listed. Never cached: the list grows.
@@ -3314,7 +3685,9 @@ Every completed signature publishes a new version. Never cached: the list grows.
```csharp -await client.Doc.Versions.ListAsync(new ListVersionsRequest { DocId = "docId" }); +await client.Doc.Versions.ListAsync( + new ListVersionsRequest { DocId = "docId", LayerName = "layerName" } +); ```
@@ -3353,7 +3726,7 @@ await client.Doc.Versions.ListAsync(new ListVersionsRequest { DocId = "docId" })
-Exactly one of `since.signature` / `since.revision`; `until=` defaults to the last. The same answer for every layer and every caller. +Exactly one of `since.signature` / `since.revision`; `until=` defaults to the last. The same answer for every caller.
@@ -3369,7 +3742,12 @@ Exactly one of `since.signature` / `since.revision`; `until=` defaults ```csharp await client.Doc.Versions.AnalysisAsync( - new AnalysisVersionsRequest { DocId = "docId", Sha = "sha" } + new AnalysisVersionsRequest + { + DocId = "docId", + LayerName = "layerName", + Sha = "sha", + } ); ``` @@ -3411,7 +3789,12 @@ await client.Doc.Versions.AnalysisAsync( ```csharp await client.Doc.Versions.DownloadAsync( - new DownloadVersionsRequest { DocId = "docId", Sha = "sha" } + new DownloadVersionsRequest + { + DocId = "docId", + LayerName = "layerName", + Sha = "sha", + } ); ``` @@ -3456,6 +3839,7 @@ await client.Doc.Versions.RevisionAsync( new RevisionVersionsRequest { DocId = "docId", + LayerName = "layerName", Sha = "sha", Index = 1, } @@ -3500,7 +3884,12 @@ await client.Doc.Versions.RevisionAsync( ```csharp await client.Doc.Versions.SignaturesAsync( - new SignaturesVersionsRequest { DocId = "docId", Sha = "sha" } + new SignaturesVersionsRequest + { + DocId = "docId", + LayerName = "layerName", + Sha = "sha", + } ); ``` @@ -3559,6 +3948,7 @@ await client.Doc.Versions.SignatureContentsAsync( new SignatureContentsVersionsRequest { DocId = "docId", + LayerName = "layerName", Sha = "sha", FieldKey = "fieldKey", } @@ -3620,6 +4010,7 @@ await client.Doc.Versions.SignatureDigestAsync( new SignatureDigestVersionsRequest { DocId = "docId", + LayerName = "layerName", Sha = "sha", FieldKey = "fieldKey", Algorithm = SignatureDigestVersionsRequestAlgorithm.Sha1, diff --git a/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/AnalysisTest.cs b/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/AnalysisTest.cs index 9f57705c..ae6b034b 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/AnalysisTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/AnalysisTest.cs @@ -104,7 +104,7 @@ public async Task MockServerTest_1() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/v1/docs/docId/versions/analysis/sha") + .WithPath("/v1/docs/docId/layers/layerName/versions/analysis/sha") .UsingGet() ) .RespondWith( @@ -115,7 +115,12 @@ public async Task MockServerTest_1() ); var response = await Client.Doc.Versions.AnalysisAsync( - new AnalysisVersionsRequest { DocId = "docId", Sha = "sha" } + new AnalysisVersionsRequest + { + DocId = "docId", + LayerName = "layerName", + Sha = "sha", + } ); JsonAssert.AreEqual(response, mockResponse); } @@ -192,7 +197,7 @@ public async Task MockServerTest_2() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/v1/docs/docId/versions/analysis/sha") + .WithPath("/v1/docs/docId/layers/layerName/versions/analysis/sha") .UsingGet() ) .RespondWith( @@ -203,7 +208,12 @@ public async Task MockServerTest_2() ); var response = await Client.Doc.Versions.AnalysisAsync( - new AnalysisVersionsRequest { DocId = "docId", Sha = "sha" } + new AnalysisVersionsRequest + { + DocId = "docId", + LayerName = "layerName", + Sha = "sha", + } ); JsonAssert.AreEqual(response, mockResponse); } diff --git a/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/ListTest.cs b/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/ListTest.cs index cabd317b..c42f5af7 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/ListTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/ListTest.cs @@ -14,7 +14,7 @@ public async Task MockServerTest_1() { const string mockResponse = """ { - "head": "head", + "baseSha": "baseSha", "versions": [ { "sha256": "sha256", @@ -42,7 +42,7 @@ public async Task MockServerTest_1() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/v1/docs/docId/versions") + .WithPath("/v1/docs/docId/layers/layerName/versions") .UsingGet() ) .RespondWith( @@ -53,7 +53,7 @@ public async Task MockServerTest_1() ); var response = await Client.Doc.Versions.ListAsync( - new ListVersionsRequest { DocId = "docId" } + new ListVersionsRequest { DocId = "docId", LayerName = "layerName" } ); JsonAssert.AreEqual(response, mockResponse); } @@ -63,7 +63,7 @@ public async Task MockServerTest_2() { const string mockResponse = """ { - "head": "head", + "baseSha": "baseSha", "versions": [ { "sha256": "sha256", @@ -82,7 +82,7 @@ public async Task MockServerTest_2() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/v1/docs/docId/versions") + .WithPath("/v1/docs/docId/layers/layerName/versions") .UsingGet() ) .RespondWith( @@ -93,7 +93,7 @@ public async Task MockServerTest_2() ); var response = await Client.Doc.Versions.ListAsync( - new ListVersionsRequest { DocId = "docId" } + new ListVersionsRequest { DocId = "docId", LayerName = "layerName" } ); JsonAssert.AreEqual(response, mockResponse); } diff --git a/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/SignaturesTest.cs b/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/SignaturesTest.cs index a8db5d3d..fdc8ebd6 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/SignaturesTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Doc/Versions/SignaturesTest.cs @@ -239,7 +239,7 @@ public async Task MockServerTest_1() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/v1/docs/docId/versions/signatures/sha") + .WithPath("/v1/docs/docId/layers/layerName/versions/signatures/sha") .UsingGet() ) .RespondWith( @@ -250,7 +250,12 @@ public async Task MockServerTest_1() ); var response = await Client.Doc.Versions.SignaturesAsync( - new SignaturesVersionsRequest { DocId = "docId", Sha = "sha" } + new SignaturesVersionsRequest + { + DocId = "docId", + LayerName = "layerName", + Sha = "sha", + } ); JsonAssert.AreEqual(response, mockResponse); } @@ -341,7 +346,7 @@ public async Task MockServerTest_2() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/v1/docs/docId/versions/signatures/sha") + .WithPath("/v1/docs/docId/layers/layerName/versions/signatures/sha") .UsingGet() ) .RespondWith( @@ -352,7 +357,12 @@ public async Task MockServerTest_2() ); var response = await Client.Doc.Versions.SignaturesAsync( - new SignaturesVersionsRequest { DocId = "docId", Sha = "sha" } + new SignaturesVersionsRequest + { + DocId = "docId", + LayerName = "layerName", + Sha = "sha", + } ); JsonAssert.AreEqual(response, mockResponse); } diff --git a/src/CloudPDF.Test/Unit/MockServer/Documents/CommitTest.cs b/src/CloudPDF.Test/Unit/MockServer/Documents/CommitTest.cs index bfbf0b76..017ab7c1 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Documents/CommitTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Documents/CommitTest.cs @@ -23,6 +23,8 @@ public async Task MockServerTest_1() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, @@ -83,6 +85,8 @@ public async Task MockServerTest_2() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, diff --git a/src/CloudPDF.Test/Unit/MockServer/Documents/GetTest.cs b/src/CloudPDF.Test/Unit/MockServer/Documents/GetTest.cs index 5d9015e2..234da6ff 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Documents/GetTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Documents/GetTest.cs @@ -17,6 +17,8 @@ public async Task MockServerTest_1() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, @@ -64,6 +66,8 @@ public async Task MockServerTest_2() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, diff --git a/src/CloudPDF.Test/Unit/MockServer/Documents/ImportFromTest.cs b/src/CloudPDF.Test/Unit/MockServer/Documents/ImportFromTest.cs index 998897fc..972c4378 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Documents/ImportFromTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Documents/ImportFromTest.cs @@ -27,6 +27,8 @@ public async Task MockServerTest_1() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, @@ -72,6 +74,8 @@ public async Task MockServerTest_1() ) ), Expected = null, + Name = null, + FolderId = null, Metadata = null, IdempotencyKey = null, DedupMode = null, @@ -100,6 +104,8 @@ public async Task MockServerTest_2() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, diff --git a/src/CloudPDF.Test/Unit/MockServer/Documents/InitTest.cs b/src/CloudPDF.Test/Unit/MockServer/Documents/InitTest.cs index bafd8baf..938e3612 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Documents/InitTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Documents/InitTest.cs @@ -25,6 +25,8 @@ public async Task MockServerTest_1() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, @@ -78,6 +80,8 @@ public async Task MockServerTest_1() TenantId = "tenantId", ContentLength = 1, ContentSha256 = "contentSha256", + Name = null, + FolderId = null, Metadata = null, IdempotencyKey = null, DedupMode = null, @@ -105,6 +109,8 @@ public async Task MockServerTest_2() "document": { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, diff --git a/src/CloudPDF.Test/Unit/MockServer/Documents/ListTest.cs b/src/CloudPDF.Test/Unit/MockServer/Documents/ListTest.cs index 841d2bd3..a84260cf 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Documents/ListTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Documents/ListTest.cs @@ -18,6 +18,8 @@ public async Task MockServerTest_1() { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, @@ -37,6 +39,8 @@ public async Task MockServerTest_1() { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, @@ -87,6 +91,8 @@ public async Task MockServerTest_2() { "id": "id", "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", "state": "pending", "baseSha": "baseSha", "storageSizeBytes": 1.1, diff --git a/src/CloudPDF.Test/Unit/MockServer/Documents/UpdateTest.cs b/src/CloudPDF.Test/Unit/MockServer/Documents/UpdateTest.cs new file mode 100644 index 00000000..feff7cea --- /dev/null +++ b/src/CloudPDF.Test/Unit/MockServer/Documents/UpdateTest.cs @@ -0,0 +1,133 @@ +using CloudPDF; +using CloudPDF.Test.Unit.MockServer; +using CloudPDF.Test.Utils; +using NUnit.Framework; + +namespace CloudPDF.Test.Unit.MockServer.Documents; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class UpdateTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest_1() + { + const string requestJson = """ + { + "name": "x" + } + """; + + const string mockResponse = """ + { + "document": { + "id": "id", + "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", + "state": "pending", + "baseSha": "baseSha", + "storageSizeBytes": 1.1, + "metadata": { + "metadata": { + "key": "value" + } + }, + "idempotencyKey": "idempotencyKey", + "failureReason": "failureReason", + "thumbnailState": "pending", + "thumbnailUrl": "thumbnailUrl", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/documents/id") + .WithHeader("Content-Type", "application/json") + .UsingPatch() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Documents.UpdateAsync( + new DocumentsUpdateRequest + { + TenantId = "tenantId", + Id = "id", + Name = "x", + } + ); + JsonAssert.AreEqual(response, mockResponse); + } + + [NUnit.Framework.Test] + public async Task MockServerTest_2() + { + const string requestJson = """ + { + "name": "name" + } + """; + + const string mockResponse = """ + { + "document": { + "id": "id", + "tenantId": "tenantId", + "name": "name", + "folderId": "folderId", + "state": "pending", + "baseSha": "baseSha", + "storageSizeBytes": 1.1, + "metadata": { + "key": "value" + }, + "idempotencyKey": "idempotencyKey", + "failureReason": "failureReason", + "thumbnailState": "pending", + "thumbnailUrl": "thumbnailUrl", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/documents/id") + .WithHeader("Content-Type", "application/json") + .UsingPatch() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Documents.UpdateAsync( + new DocumentsUpdateRequest + { + TenantId = "tenantId", + Id = "id", + Name = "name", + } + ); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/src/CloudPDF.Test/Unit/MockServer/Folders/CreateTest.cs b/src/CloudPDF.Test/Unit/MockServer/Folders/CreateTest.cs new file mode 100644 index 00000000..16228bda --- /dev/null +++ b/src/CloudPDF.Test/Unit/MockServer/Folders/CreateTest.cs @@ -0,0 +1,106 @@ +using CloudPDF; +using CloudPDF.Test.Unit.MockServer; +using CloudPDF.Test.Utils; +using NUnit.Framework; + +namespace CloudPDF.Test.Unit.MockServer.Folders; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class CreateTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest_1() + { + const string requestJson = """ + { + "name": "x" + } + """; + + const string mockResponse = """ + { + "folder": { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders") + .WithHeader("Content-Type", "application/json") + .UsingPost() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.CreateAsync( + new FoldersCreateRequest + { + TenantId = "tenantId", + Name = "x", + ParentId = null, + } + ); + JsonAssert.AreEqual(response, mockResponse); + } + + [NUnit.Framework.Test] + public async Task MockServerTest_2() + { + const string requestJson = """ + { + "name": "name" + } + """; + + const string mockResponse = """ + { + "folder": { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders") + .WithHeader("Content-Type", "application/json") + .UsingPost() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.CreateAsync( + new FoldersCreateRequest { TenantId = "tenantId", Name = "name" } + ); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/src/CloudPDF.Test/Unit/MockServer/Folders/DeleteTest.cs b/src/CloudPDF.Test/Unit/MockServer/Folders/DeleteTest.cs new file mode 100644 index 00000000..a54c3b28 --- /dev/null +++ b/src/CloudPDF.Test/Unit/MockServer/Folders/DeleteTest.cs @@ -0,0 +1,48 @@ +using CloudPDF; +using CloudPDF.Test.Unit.MockServer; +using NUnit.Framework; + +namespace CloudPDF.Test.Unit.MockServer.Folders; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class DeleteTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public void MockServerTest_1() + { + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId") + .UsingDelete() + ) + .RespondWith(WireMock.ResponseBuilders.Response.Create().WithStatusCode(200)); + + Assert.DoesNotThrowAsync(async () => + await Client.Folders.DeleteAsync( + new DeleteFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } + ) + ); + } + + [NUnit.Framework.Test] + public void MockServerTest_2() + { + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId") + .UsingDelete() + ) + .RespondWith(WireMock.ResponseBuilders.Response.Create().WithStatusCode(200)); + + Assert.DoesNotThrowAsync(async () => + await Client.Folders.DeleteAsync( + new DeleteFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } + ) + ); + } +} diff --git a/src/CloudPDF.Test/Unit/MockServer/Folders/GetTest.cs b/src/CloudPDF.Test/Unit/MockServer/Folders/GetTest.cs new file mode 100644 index 00000000..6abc6c2b --- /dev/null +++ b/src/CloudPDF.Test/Unit/MockServer/Folders/GetTest.cs @@ -0,0 +1,101 @@ +using CloudPDF; +using CloudPDF.Test.Unit.MockServer; +using CloudPDF.Test.Utils; +using NUnit.Framework; + +namespace CloudPDF.Test.Unit.MockServer.Folders; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class GetTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest_1() + { + const string mockResponse = """ + { + "folder": { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + }, + "path": [ + { + "id": "id", + "name": "name" + }, + { + "id": "id", + "name": "name" + } + ] + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId") + .UsingGet() + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.GetAsync( + new GetFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } + ); + JsonAssert.AreEqual(response, mockResponse); + } + + [NUnit.Framework.Test] + public async Task MockServerTest_2() + { + const string mockResponse = """ + { + "folder": { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + }, + "path": [ + { + "id": "id", + "name": "name" + } + ] + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId") + .UsingGet() + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.GetAsync( + new GetFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } + ); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/src/CloudPDF.Test/Unit/MockServer/Folders/ListTest.cs b/src/CloudPDF.Test/Unit/MockServer/Folders/ListTest.cs new file mode 100644 index 00000000..cfb84307 --- /dev/null +++ b/src/CloudPDF.Test/Unit/MockServer/Folders/ListTest.cs @@ -0,0 +1,100 @@ +using CloudPDF; +using CloudPDF.Test.Unit.MockServer; +using CloudPDF.Test.Utils; +using NUnit.Framework; + +namespace CloudPDF.Test.Unit.MockServer.Folders; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class ListTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest_1() + { + const string mockResponse = """ + { + "folders": [ + { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + }, + { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + ], + "nextCursor": "nextCursor" + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders") + .UsingGet() + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.ListAsync( + new ListFoldersRequest { TenantId = "tenantId" } + ); + JsonAssert.AreEqual(response, mockResponse); + } + + [NUnit.Framework.Test] + public async Task MockServerTest_2() + { + const string mockResponse = """ + { + "folders": [ + { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + ], + "nextCursor": "nextCursor" + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders") + .UsingGet() + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.ListAsync( + new ListFoldersRequest { TenantId = "tenantId" } + ); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/src/CloudPDF.Test/Unit/MockServer/Folders/MoveIntoTest.cs b/src/CloudPDF.Test/Unit/MockServer/Folders/MoveIntoTest.cs new file mode 100644 index 00000000..77624505 --- /dev/null +++ b/src/CloudPDF.Test/Unit/MockServer/Folders/MoveIntoTest.cs @@ -0,0 +1,66 @@ +using CloudPDF; +using CloudPDF.Test.Unit.MockServer; +using NUnit.Framework; + +namespace CloudPDF.Test.Unit.MockServer.Folders; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class MoveIntoTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public void MockServerTest_1() + { + const string requestJson = """ + {} + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId/move-into") + .WithHeader("Content-Type", "application/json") + .UsingPost() + .WithBodyAsJson(requestJson) + ) + .RespondWith(WireMock.ResponseBuilders.Response.Create().WithStatusCode(200)); + + Assert.DoesNotThrowAsync(async () => + await Client.Folders.MoveIntoAsync( + new FoldersMoveIntoRequest + { + TenantId = "tenantId", + FolderId = "folderId", + DocumentIds = null, + FolderIds = null, + } + ) + ); + } + + [NUnit.Framework.Test] + public void MockServerTest_2() + { + const string requestJson = """ + {} + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId/move-into") + .WithHeader("Content-Type", "application/json") + .UsingPost() + .WithBodyAsJson(requestJson) + ) + .RespondWith(WireMock.ResponseBuilders.Response.Create().WithStatusCode(200)); + + Assert.DoesNotThrowAsync(async () => + await Client.Folders.MoveIntoAsync( + new FoldersMoveIntoRequest { TenantId = "tenantId", FolderId = "folderId" } + ) + ); + } +} diff --git a/src/CloudPDF.Test/Unit/MockServer/Folders/UpdateTest.cs b/src/CloudPDF.Test/Unit/MockServer/Folders/UpdateTest.cs new file mode 100644 index 00000000..f19a5bb2 --- /dev/null +++ b/src/CloudPDF.Test/Unit/MockServer/Folders/UpdateTest.cs @@ -0,0 +1,111 @@ +using CloudPDF; +using CloudPDF.Test.Unit.MockServer; +using CloudPDF.Test.Utils; +using NUnit.Framework; + +namespace CloudPDF.Test.Unit.MockServer.Folders; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class UpdateTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest_1() + { + const string requestJson = """ + { + "name": "x" + } + """; + + const string mockResponse = """ + { + "folder": { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId") + .WithHeader("Content-Type", "application/json") + .UsingPatch() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.UpdateAsync( + new FoldersUpdateRequest + { + TenantId = "tenantId", + FolderId = "folderId", + Name = "x", + } + ); + JsonAssert.AreEqual(response, mockResponse); + } + + [NUnit.Framework.Test] + public async Task MockServerTest_2() + { + const string requestJson = """ + { + "name": "name" + } + """; + + const string mockResponse = """ + { + "folder": { + "id": "id", + "tenantId": "tenantId", + "parentId": "parentId", + "name": "name", + "createdAt": 1.1, + "updatedAt": 1.1, + "createdBy": "createdBy" + } + } + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/v1/tenants/tenantId/folders/folderId") + .WithHeader("Content-Type", "application/json") + .UsingPatch() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Folders.UpdateAsync( + new FoldersUpdateRequest + { + TenantId = "tenantId", + FolderId = "folderId", + Name = "name", + } + ); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/src/CloudPDF.Test/Unit/MockServer/Shares/ArchiveTest.cs b/src/CloudPDF.Test/Unit/MockServer/Shares/ArchiveTest.cs index c56a7db0..8a0ccbbc 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Shares/ArchiveTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Shares/ArchiveTest.cs @@ -34,6 +34,15 @@ public async Task MockServerTest_1() "purpose": "x", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "x", + "displayName": "x", + "email": "x", + "title": "x", + "organization": "x", + "organizationalUnit": "x", + "groupId": "x" + }, "scope": [ "scope", "scope" @@ -95,6 +104,15 @@ public async Task MockServerTest_2() "purpose": "purpose", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "userId", + "displayName": "displayName", + "email": "email", + "title": "title", + "organization": "organization", + "organizationalUnit": "organizationalUnit", + "groupId": "groupId" + }, "scope": [ "scope" ], diff --git a/src/CloudPDF.Test/Unit/MockServer/Shares/CreateTest.cs b/src/CloudPDF.Test/Unit/MockServer/Shares/CreateTest.cs index 9aaaadec..83f73b9f 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Shares/CreateTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Shares/CreateTest.cs @@ -44,6 +44,15 @@ public async Task MockServerTest_1() "purpose": "x", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "x", + "displayName": "x", + "email": "x", + "title": "x", + "organization": "x", + "organizationalUnit": "x", + "groupId": "x" + }, "scope": [ "scope", "scope" @@ -92,6 +101,7 @@ public async Task MockServerTest_1() KeepVisitorLayers = null, VisitorIdleSeconds = null, VisitorIdentity = null, + Identity = null, Scope = new List() { "scope", "scope" }, Origins = null, Password = null, @@ -130,6 +140,15 @@ public async Task MockServerTest_2() "purpose": "purpose", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "userId", + "displayName": "displayName", + "email": "email", + "title": "title", + "organization": "organization", + "organizationalUnit": "organizationalUnit", + "groupId": "groupId" + }, "scope": [ "scope" ], diff --git a/src/CloudPDF.Test/Unit/MockServer/Shares/GetTest.cs b/src/CloudPDF.Test/Unit/MockServer/Shares/GetTest.cs index aa775808..2f5dbc73 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Shares/GetTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Shares/GetTest.cs @@ -34,6 +34,15 @@ public async Task MockServerTest_1() "purpose": "x", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "x", + "displayName": "x", + "email": "x", + "title": "x", + "organization": "x", + "organizationalUnit": "x", + "groupId": "x" + }, "scope": [ "scope", "scope" @@ -95,6 +104,15 @@ public async Task MockServerTest_2() "purpose": "purpose", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "userId", + "displayName": "displayName", + "email": "email", + "title": "title", + "organization": "organization", + "organizationalUnit": "organizationalUnit", + "groupId": "groupId" + }, "scope": [ "scope" ], diff --git a/src/CloudPDF.Test/Unit/MockServer/Shares/ListTest.cs b/src/CloudPDF.Test/Unit/MockServer/Shares/ListTest.cs index 6372ef0c..dc1ba878 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Shares/ListTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Shares/ListTest.cs @@ -35,6 +35,15 @@ public async Task MockServerTest_1() "purpose": "x", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "x", + "displayName": "x", + "email": "x", + "title": "x", + "organization": "x", + "organizationalUnit": "x", + "groupId": "x" + }, "scope": [ "scope", "scope" @@ -74,6 +83,15 @@ public async Task MockServerTest_1() "purpose": "x", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "x", + "displayName": "x", + "email": "x", + "title": "x", + "organization": "x", + "organizationalUnit": "x", + "groupId": "x" + }, "scope": [ "scope", "scope" @@ -136,6 +154,7 @@ public async Task MockServerTest_2() "fields": {}, "ask": "on-open" }, + "identity": {}, "scope": [ "scope" ], diff --git a/src/CloudPDF.Test/Unit/MockServer/Shares/UpdateTest.cs b/src/CloudPDF.Test/Unit/MockServer/Shares/UpdateTest.cs index 29c7f130..f39e9e25 100644 --- a/src/CloudPDF.Test/Unit/MockServer/Shares/UpdateTest.cs +++ b/src/CloudPDF.Test/Unit/MockServer/Shares/UpdateTest.cs @@ -38,6 +38,15 @@ public async Task MockServerTest_1() "purpose": "x", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "x", + "displayName": "x", + "email": "x", + "title": "x", + "organization": "x", + "organizationalUnit": "x", + "groupId": "x" + }, "scope": [ "scope", "scope" @@ -86,6 +95,7 @@ public async Task MockServerTest_1() KeepVisitorLayers = null, VisitorIdleSeconds = null, VisitorIdentity = null, + Identity = null, Scope = null, Origins = null, Password = null, @@ -120,6 +130,15 @@ public async Task MockServerTest_2() "purpose": "purpose", "privacyUrl": "privacyUrl" }, + "identity": { + "userId": "userId", + "displayName": "displayName", + "email": "email", + "title": "title", + "organization": "organization", + "organizationalUnit": "organizationalUnit", + "groupId": "groupId" + }, "scope": [ "scope" ], diff --git a/src/CloudPDF/CloudPDF.csproj b/src/CloudPDF/CloudPDF.csproj index 22ce4f5f..c39cd78b 100644 --- a/src/CloudPDF/CloudPDF.csproj +++ b/src/CloudPDF/CloudPDF.csproj @@ -11,7 +11,7 @@ enable 12 enable - 3.0.0-next.17 + 3.0.0-next.18 3.0.0.0 3.0.0.0 README.md diff --git a/src/CloudPDF/CloudPDFClient.cs b/src/CloudPDF/CloudPDFClient.cs index e72e0558..574d8501 100644 --- a/src/CloudPDF/CloudPDFClient.cs +++ b/src/CloudPDF/CloudPDFClient.cs @@ -38,6 +38,7 @@ public CloudPDFClient(string token, ClientOptions? clientOptions = null) Shares = new SharesClient(_client); Tenants = new TenantsClient(_client); Documents = new DocumentsClient(_client); + Folders = new FoldersClient(_client); Tokens = new TokensClient(_client); } @@ -51,5 +52,7 @@ public CloudPDFClient(string token, ClientOptions? clientOptions = null) public IDocumentsClient Documents { get; } + public IFoldersClient Folders { get; } + public ITokensClient Tokens { get; } } diff --git a/src/CloudPDF/Core/Public/Version.cs b/src/CloudPDF/Core/Public/Version.cs index 71b8d06b..e36eecc1 100644 --- a/src/CloudPDF/Core/Public/Version.cs +++ b/src/CloudPDF/Core/Public/Version.cs @@ -3,5 +3,5 @@ namespace CloudPDF; [Serializable] internal class Version { - public const string Current = "3.0.0-next.17"; + public const string Current = "3.0.0-next.18"; } diff --git a/src/CloudPDF/Doc/Signatures/ISignaturesClient.cs b/src/CloudPDF/Doc/Signatures/ISignaturesClient.cs index bdd0ee03..2af6e5d7 100644 --- a/src/CloudPDF/Doc/Signatures/ISignaturesClient.cs +++ b/src/CloudPDF/Doc/Signatures/ISignaturesClient.cs @@ -20,7 +20,7 @@ WithRawResponseTask CancelAsync( ); /// - /// `cms` is the detached CMS over the prepared digest, base64. `expectedVersion` must be what prepare returned. Idempotent by signing id: the same CMS again answers `already-completed`. Every layer of the document then sits over the new version; refetch the manifest after a completion. + /// `cms` is the detached CMS over the prepared digest, base64. `expectedVersion` must be what prepare returned. Idempotent by signing id: the same CMS again answers `already-completed`. The new version is the layer's own: only this layer moves to it, and the document and every other layer stay as they were. Refetch the manifest after a completion. /// WithRawResponseTask CompleteAsync( DocSignaturesCompleteRequest request, @@ -38,7 +38,7 @@ WithRawResponseTask AnalysisAsync( ); /// - /// Multipart: a JSON `body` part (field, subFilter, digest, contentsSize, signer, certify, lock), naming the appearance PDF it may carry as `resources: { appearance: '<key>' }`, and that PDF as the part `resource:<key>`. A certification (`certify.permission`) additionally requires `doc.sign.certify`. The layer is read-only until the signing completes, is cancelled, or expires (15 minutes). A layer behind the document head cannot sign (StaleBase). + /// Multipart: a JSON `body` part (field, subFilter, digest, contentsSize, signer, certify, lock), naming the appearance PDF it may carry as `resources: { appearance: '<key>' }`, and that PDF as the part `resource:<key>`. A certification (`certify.permission`) additionally requires `doc.sign.certify`. The layer is read-only until the signing completes, is cancelled, or expires (15 minutes). The signature is made over the layer's own base: the upload, or the version its last signature made. /// WithRawResponseTask PrepareAsync( PrepareSignaturesRequest request, diff --git a/src/CloudPDF/Doc/Signatures/SignaturesClient.cs b/src/CloudPDF/Doc/Signatures/SignaturesClient.cs index ef80e136..714379b8 100644 --- a/src/CloudPDF/Doc/Signatures/SignaturesClient.cs +++ b/src/CloudPDF/Doc/Signatures/SignaturesClient.cs @@ -670,7 +670,7 @@ public WithRawResponseTask CancelAsync( } /// - /// `cms` is the detached CMS over the prepared digest, base64. `expectedVersion` must be what prepare returned. Idempotent by signing id: the same CMS again answers `already-completed`. Every layer of the document then sits over the new version; refetch the manifest after a completion. + /// `cms` is the detached CMS over the prepared digest, base64. `expectedVersion` must be what prepare returned. Idempotent by signing id: the same CMS again answers `already-completed`. The new version is the layer's own: only this layer moves to it, and the document and every other layer stay as they were. Refetch the manifest after a completion. /// /// /// await client.Doc.Signatures.CompleteAsync( @@ -719,7 +719,7 @@ public WithRawResponseTask AnalysisAsync( } /// - /// Multipart: a JSON `body` part (field, subFilter, digest, contentsSize, signer, certify, lock), naming the appearance PDF it may carry as `resources: { appearance: '<key>' }`, and that PDF as the part `resource:<key>`. A certification (`certify.permission`) additionally requires `doc.sign.certify`. The layer is read-only until the signing completes, is cancelled, or expires (15 minutes). A layer behind the document head cannot sign (StaleBase). + /// Multipart: a JSON `body` part (field, subFilter, digest, contentsSize, signer, certify, lock), naming the appearance PDF it may carry as `resources: { appearance: '<key>' }`, and that PDF as the part `resource:<key>`. A certification (`certify.permission`) additionally requires `doc.sign.certify`. The layer is read-only until the signing completes, is cancelled, or expires (15 minutes). The signature is made over the layer's own base: the upload, or the version its last signature made. /// /// /// await client.Doc.Signatures.PrepareAsync( diff --git a/src/CloudPDF/Doc/Versions/IVersionsClient.cs b/src/CloudPDF/Doc/Versions/IVersionsClient.cs index d766fa59..339d87f7 100644 --- a/src/CloudPDF/Doc/Versions/IVersionsClient.cs +++ b/src/CloudPDF/Doc/Versions/IVersionsClient.cs @@ -5,7 +5,7 @@ namespace CloudPDF.Doc; public partial interface IVersionsClient { /// - /// Every completed signature publishes a new version. Never cached: the list grows. + /// Every completed signature makes a new version of its layer; another layer's versions are never listed. Never cached: the list grows. /// WithRawResponseTask ListAsync( ListVersionsRequest request, @@ -14,7 +14,7 @@ WithRawResponseTask ListAsync( ); /// - /// Exactly one of `since.signature` / `since.revision`; `until=<revision>` defaults to the last. The same answer for every layer and every caller. + /// Exactly one of `since.signature` / `since.revision`; `until=<revision>` defaults to the last. The same answer for every caller. /// WithRawResponseTask AnalysisAsync( AnalysisVersionsRequest request, diff --git a/src/CloudPDF/Doc/Versions/Requests/AnalysisVersionsRequest.cs b/src/CloudPDF/Doc/Versions/Requests/AnalysisVersionsRequest.cs index f3f9ad9b..49e302bd 100644 --- a/src/CloudPDF/Doc/Versions/Requests/AnalysisVersionsRequest.cs +++ b/src/CloudPDF/Doc/Versions/Requests/AnalysisVersionsRequest.cs @@ -9,6 +9,9 @@ public record AnalysisVersionsRequest [JsonIgnore] public required string DocId { get; set; } + [JsonIgnore] + public required string LayerName { get; set; } + [JsonIgnore] public required string Sha { get; set; } diff --git a/src/CloudPDF/Doc/Versions/Requests/DownloadVersionsRequest.cs b/src/CloudPDF/Doc/Versions/Requests/DownloadVersionsRequest.cs index 87f8b5f9..601522fd 100644 --- a/src/CloudPDF/Doc/Versions/Requests/DownloadVersionsRequest.cs +++ b/src/CloudPDF/Doc/Versions/Requests/DownloadVersionsRequest.cs @@ -9,6 +9,9 @@ public record DownloadVersionsRequest [JsonIgnore] public required string DocId { get; set; } + [JsonIgnore] + public required string LayerName { get; set; } + [JsonIgnore] public required string Sha { get; set; } diff --git a/src/CloudPDF/Doc/Versions/Requests/ListVersionsRequest.cs b/src/CloudPDF/Doc/Versions/Requests/ListVersionsRequest.cs index fc17e2f6..d4852864 100644 --- a/src/CloudPDF/Doc/Versions/Requests/ListVersionsRequest.cs +++ b/src/CloudPDF/Doc/Versions/Requests/ListVersionsRequest.cs @@ -9,6 +9,9 @@ public record ListVersionsRequest [JsonIgnore] public required string DocId { get; set; } + [JsonIgnore] + public required string LayerName { get; set; } + /// /// Base64-encoded password for an encrypted document. Valid only with the API token (403 anywhere else). An encrypted document answers 422 DocPasswordRequired when the header is absent. Viewer doc JWTs use the SDK password-session flow instead. /// diff --git a/src/CloudPDF/Doc/Versions/Requests/RevisionVersionsRequest.cs b/src/CloudPDF/Doc/Versions/Requests/RevisionVersionsRequest.cs index e08dfb6d..88409f5b 100644 --- a/src/CloudPDF/Doc/Versions/Requests/RevisionVersionsRequest.cs +++ b/src/CloudPDF/Doc/Versions/Requests/RevisionVersionsRequest.cs @@ -9,6 +9,9 @@ public record RevisionVersionsRequest [JsonIgnore] public required string DocId { get; set; } + [JsonIgnore] + public required string LayerName { get; set; } + [JsonIgnore] public required string Sha { get; set; } diff --git a/src/CloudPDF/Doc/Versions/Requests/SignatureContentsVersionsRequest.cs b/src/CloudPDF/Doc/Versions/Requests/SignatureContentsVersionsRequest.cs index 249cec83..6945d09f 100644 --- a/src/CloudPDF/Doc/Versions/Requests/SignatureContentsVersionsRequest.cs +++ b/src/CloudPDF/Doc/Versions/Requests/SignatureContentsVersionsRequest.cs @@ -9,6 +9,9 @@ public record SignatureContentsVersionsRequest [JsonIgnore] public required string DocId { get; set; } + [JsonIgnore] + public required string LayerName { get; set; } + [JsonIgnore] public required string Sha { get; set; } diff --git a/src/CloudPDF/Doc/Versions/Requests/SignatureDigestVersionsRequest.cs b/src/CloudPDF/Doc/Versions/Requests/SignatureDigestVersionsRequest.cs index aed67010..daae157c 100644 --- a/src/CloudPDF/Doc/Versions/Requests/SignatureDigestVersionsRequest.cs +++ b/src/CloudPDF/Doc/Versions/Requests/SignatureDigestVersionsRequest.cs @@ -9,6 +9,9 @@ public record SignatureDigestVersionsRequest [JsonIgnore] public required string DocId { get; set; } + [JsonIgnore] + public required string LayerName { get; set; } + [JsonIgnore] public required string Sha { get; set; } diff --git a/src/CloudPDF/Doc/Versions/Requests/SignaturesVersionsRequest.cs b/src/CloudPDF/Doc/Versions/Requests/SignaturesVersionsRequest.cs index 117480f8..505bf61d 100644 --- a/src/CloudPDF/Doc/Versions/Requests/SignaturesVersionsRequest.cs +++ b/src/CloudPDF/Doc/Versions/Requests/SignaturesVersionsRequest.cs @@ -9,6 +9,9 @@ public record SignaturesVersionsRequest [JsonIgnore] public required string DocId { get; set; } + [JsonIgnore] + public required string LayerName { get; set; } + [JsonIgnore] public required string Sha { get; set; } diff --git a/src/CloudPDF/Doc/Versions/VersionsClient.cs b/src/CloudPDF/Doc/Versions/VersionsClient.cs index 46bd51d9..5d171b88 100644 --- a/src/CloudPDF/Doc/Versions/VersionsClient.cs +++ b/src/CloudPDF/Doc/Versions/VersionsClient.cs @@ -35,8 +35,9 @@ private async Task> ListAsyncCore( { Method = HttpMethod.Get, Path = string.Format( - "v1/docs/{0}/versions", - ValueConvert.ToPathParameterString(request.DocId) + "v1/docs/{0}/layers/{1}/versions", + ValueConvert.ToPathParameterString(request.DocId), + ValueConvert.ToPathParameterString(request.LayerName) ), QueryString = _queryString, Headers = _headers, @@ -147,8 +148,9 @@ private async Task> AnalysisAsyn { Method = HttpMethod.Get, Path = string.Format( - "v1/docs/{0}/versions/analysis/{1}", + "v1/docs/{0}/layers/{1}/versions/analysis/{2}", ValueConvert.ToPathParameterString(request.DocId), + ValueConvert.ToPathParameterString(request.LayerName), ValueConvert.ToPathParameterString(request.Sha) ), QueryString = _queryString, @@ -269,8 +271,9 @@ private async Task> AnalysisAsyn { Method = HttpMethod.Get, Path = string.Format( - "v1/docs/{0}/versions/download/{1}", + "v1/docs/{0}/layers/{1}/versions/download/{2}", ValueConvert.ToPathParameterString(request.DocId), + ValueConvert.ToPathParameterString(request.LayerName), ValueConvert.ToPathParameterString(request.Sha) ), QueryString = _queryString, @@ -356,8 +359,9 @@ private async Task> AnalysisAsyn { Method = HttpMethod.Get, Path = string.Format( - "v1/docs/{0}/versions/revisions/{1}/{2}", + "v1/docs/{0}/layers/{1}/versions/revisions/{2}/{3}", ValueConvert.ToPathParameterString(request.DocId), + ValueConvert.ToPathParameterString(request.LayerName), ValueConvert.ToPathParameterString(request.Sha), ValueConvert.ToPathParameterString(request.Index) ), @@ -444,8 +448,9 @@ private async Task> Signatures { Method = HttpMethod.Get, Path = string.Format( - "v1/docs/{0}/versions/signatures/{1}", + "v1/docs/{0}/layers/{1}/versions/signatures/{2}", ValueConvert.ToPathParameterString(request.DocId), + ValueConvert.ToPathParameterString(request.LayerName), ValueConvert.ToPathParameterString(request.Sha) ), QueryString = _queryString, @@ -554,8 +559,9 @@ private async Task> Signatures { Method = HttpMethod.Get, Path = string.Format( - "v1/docs/{0}/versions/signatures/{1}/{2}/contents", + "v1/docs/{0}/layers/{1}/versions/signatures/{2}/{3}/contents", ValueConvert.ToPathParameterString(request.DocId), + ValueConvert.ToPathParameterString(request.LayerName), ValueConvert.ToPathParameterString(request.Sha), ValueConvert.ToPathParameterString(request.FieldKey) ), @@ -642,8 +648,9 @@ private async Task> Signatures { Method = HttpMethod.Get, Path = string.Format( - "v1/docs/{0}/versions/signatures/{1}/{2}/digest/{3}", + "v1/docs/{0}/layers/{1}/versions/signatures/{2}/{3}/digest/{4}", ValueConvert.ToPathParameterString(request.DocId), + ValueConvert.ToPathParameterString(request.LayerName), ValueConvert.ToPathParameterString(request.Sha), ValueConvert.ToPathParameterString(request.FieldKey), ValueConvert.ToPathParameterString(request.Algorithm) @@ -710,10 +717,12 @@ private async Task> Signatures } /// - /// Every completed signature publishes a new version. Never cached: the list grows. + /// Every completed signature makes a new version of its layer; another layer's versions are never listed. Never cached: the list grows. /// /// - /// await client.Doc.Versions.ListAsync(new ListVersionsRequest { DocId = "docId" }); + /// await client.Doc.Versions.ListAsync( + /// new ListVersionsRequest { DocId = "docId", LayerName = "layerName" } + /// ); /// public WithRawResponseTask ListAsync( ListVersionsRequest request, @@ -727,11 +736,16 @@ public WithRawResponseTask ListAsync( } /// - /// Exactly one of `since.signature` / `since.revision`; `until=<revision>` defaults to the last. The same answer for every layer and every caller. + /// Exactly one of `since.signature` / `since.revision`; `until=<revision>` defaults to the last. The same answer for every caller. /// /// /// await client.Doc.Versions.AnalysisAsync( - /// new AnalysisVersionsRequest { DocId = "docId", Sha = "sha" } + /// new AnalysisVersionsRequest + /// { + /// DocId = "docId", + /// LayerName = "layerName", + /// Sha = "sha", + /// } /// ); /// public WithRawResponseTask AnalysisAsync( @@ -747,7 +761,12 @@ public WithRawResponseTask AnalysisAsync( /// /// await client.Doc.Versions.DownloadAsync( - /// new DownloadVersionsRequest { DocId = "docId", Sha = "sha" } + /// new DownloadVersionsRequest + /// { + /// DocId = "docId", + /// LayerName = "layerName", + /// Sha = "sha", + /// } /// ); /// public WithRawResponseTask DownloadAsync( @@ -766,6 +785,7 @@ public WithRawResponseTask AnalysisAsync( /// new RevisionVersionsRequest /// { /// DocId = "docId", + /// LayerName = "layerName", /// Sha = "sha", /// Index = 1, /// } @@ -784,7 +804,12 @@ public WithRawResponseTask AnalysisAsync( /// /// await client.Doc.Versions.SignaturesAsync( - /// new SignaturesVersionsRequest { DocId = "docId", Sha = "sha" } + /// new SignaturesVersionsRequest + /// { + /// DocId = "docId", + /// LayerName = "layerName", + /// Sha = "sha", + /// } /// ); /// public WithRawResponseTask SignaturesAsync( @@ -806,6 +831,7 @@ public WithRawResponseTask SignaturesAsync( /// new SignatureContentsVersionsRequest /// { /// DocId = "docId", + /// LayerName = "layerName", /// Sha = "sha", /// FieldKey = "fieldKey", /// } @@ -830,6 +856,7 @@ public WithRawResponseTask SignaturesAsync( /// new SignatureDigestVersionsRequest /// { /// DocId = "docId", + /// LayerName = "layerName", /// Sha = "sha", /// FieldKey = "fieldKey", /// Algorithm = SignatureDigestVersionsRequestAlgorithm.Sha1, diff --git a/src/CloudPDF/Documents/DocumentsClient.cs b/src/CloudPDF/Documents/DocumentsClient.cs index ec13898d..b5eac5fc 100644 --- a/src/CloudPDF/Documents/DocumentsClient.cs +++ b/src/CloudPDF/Documents/DocumentsClient.cs @@ -22,10 +22,14 @@ private async Task> ListAsyncCore( CancellationToken cancellationToken = default ) { - var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 3) + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 7) .Add("limit", request.Limit) .Add("cursor", request.Cursor) .Add("state", request.State) + .Add("q", request.Q) + .Add("folderId", request.FolderId) + .Add("sort", request.Sort) + .Add("order", request.Order) .MergeAdditional(options?.AdditionalQueryParameters) .Build(); var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() @@ -337,6 +341,139 @@ private async Task DeleteAsyncCore( } } + private async Task> UpdateAsyncCore( + DocumentsUpdateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 0) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethodExtensions.Patch, + Path = string.Format( + "v1/tenants/{0}/documents/{1}", + ValueConvert.ToPathParameterString(request.TenantId), + ValueConvert.ToPathParameterString(request.Id) + ), + Body = request, + QueryString = _queryString, + Headers = _headers, + ContentType = "application/json", + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new CloudPDFApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + switch (response.StatusCode) + { + case 400: + throw new BadRequestError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 403: + throw new ForbiddenError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 404: + throw new NotFoundError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + catch (JsonException) + { + // unable to map error response, throwing generic error + } + throw new CloudPDFApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + private async Task> CommitAsyncCore( DocumentsCommitRequest request, RequestOptions? options = null, @@ -1044,6 +1181,30 @@ public WithRawResponseTask DeleteAsync( return new WithRawResponseTask(DeleteAsyncCore(request, options, cancellationToken)); } + /// + /// A document that is being deleted answers 404. + /// + /// + /// await client.Documents.UpdateAsync( + /// new DocumentsUpdateRequest + /// { + /// TenantId = "tenantId", + /// Id = "id", + /// Name = "name", + /// } + /// ); + /// + public WithRawResponseTask UpdateAsync( + DocumentsUpdateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + UpdateAsyncCore(request, options, cancellationToken) + ); + } + /// /// await client.Documents.CommitAsync( /// new DocumentsCommitRequest diff --git a/src/CloudPDF/Documents/IDocumentsClient.cs b/src/CloudPDF/Documents/IDocumentsClient.cs index 88f17ee2..f23e41bb 100644 --- a/src/CloudPDF/Documents/IDocumentsClient.cs +++ b/src/CloudPDF/Documents/IDocumentsClient.cs @@ -23,6 +23,15 @@ WithRawResponseTask DeleteAsync( CancellationToken cancellationToken = default ); + /// + /// A document that is being deleted answers 404. + /// + WithRawResponseTask UpdateAsync( + DocumentsUpdateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + WithRawResponseTask CommitAsync( DocumentsCommitRequest request, RequestOptions? options = null, diff --git a/src/CloudPDF/Documents/Requests/DocumentsImportFromRequest.cs b/src/CloudPDF/Documents/Requests/DocumentsImportFromRequest.cs index b827de18..e1126d98 100644 --- a/src/CloudPDF/Documents/Requests/DocumentsImportFromRequest.cs +++ b/src/CloudPDF/Documents/Requests/DocumentsImportFromRequest.cs @@ -21,6 +21,18 @@ public record DocumentsImportFromRequest [JsonPropertyName("expected")] public DocumentsImportFromRequestExpected? Expected { get; set; } + /// + /// What people call the document: shown in dashboards, searched and sorted by. 1 to 255 characters, no control characters, no leading or trailing whitespace. Names need not be unique. + /// + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// + /// A folder id, or root for the top level. + /// + [JsonPropertyName("folderId")] + public string? FolderId { get; set; } + [JsonPropertyName("metadata")] public Dictionary? Metadata { get; set; } diff --git a/src/CloudPDF/Documents/Requests/DocumentsInitRequest.cs b/src/CloudPDF/Documents/Requests/DocumentsInitRequest.cs index b3bd7f6e..30d198c4 100644 --- a/src/CloudPDF/Documents/Requests/DocumentsInitRequest.cs +++ b/src/CloudPDF/Documents/Requests/DocumentsInitRequest.cs @@ -15,6 +15,18 @@ public record DocumentsInitRequest [JsonPropertyName("contentSha256")] public required string ContentSha256 { get; set; } + /// + /// What people call the document: shown in dashboards, searched and sorted by. 1 to 255 characters, no control characters, no leading or trailing whitespace. Names need not be unique. + /// + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// + /// A folder id, or root for the top level. + /// + [JsonPropertyName("folderId")] + public string? FolderId { get; set; } + [JsonPropertyName("metadata")] public Dictionary? Metadata { get; set; } diff --git a/src/CloudPDF/Documents/Requests/DocumentsUpdateRequest.cs b/src/CloudPDF/Documents/Requests/DocumentsUpdateRequest.cs new file mode 100644 index 00000000..47cf291a --- /dev/null +++ b/src/CloudPDF/Documents/Requests/DocumentsUpdateRequest.cs @@ -0,0 +1,26 @@ +using CloudPDF.Core; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record DocumentsUpdateRequest +{ + [JsonIgnore] + public required string TenantId { get; set; } + + [JsonIgnore] + public required string Id { get; set; } + + /// + /// What people call the document: shown in dashboards, searched and sorted by. 1 to 255 characters, no control characters, no leading or trailing whitespace. Names need not be unique. + /// + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Documents/Requests/ListDocumentsRequest.cs b/src/CloudPDF/Documents/Requests/ListDocumentsRequest.cs index f632f51a..89ad01e7 100644 --- a/src/CloudPDF/Documents/Requests/ListDocumentsRequest.cs +++ b/src/CloudPDF/Documents/Requests/ListDocumentsRequest.cs @@ -15,9 +15,36 @@ public record ListDocumentsRequest [JsonIgnore] public string? Cursor { get; set; } + /// + /// Only documents in this state. Without it, every state except deleting. + /// [JsonIgnore] public ListDocumentsRequestState? State { get; set; } + /// + /// Only documents whose name contains this text, ignoring case. + /// + [JsonIgnore] + public string? Q { get; set; } + + /// + /// Only documents directly in this folder (root: the top level). Without it, documents in every folder. + /// + [JsonIgnore] + public string? FolderId { get; set; } + + /// + /// createdAt (default), name (ignoring case), or size (stored bytes; 0 while pending). + /// + [JsonIgnore] + public ListDocumentsRequestSort? Sort { get; set; } + + /// + /// Defaults to the reading order of the sort: A to Z for name, newest and largest first otherwise. + /// + [JsonIgnore] + public ListDocumentsRequestOrder? Order { get; set; } + /// public override string ToString() { diff --git a/src/CloudPDF/Types/TokensIssueRequestTenantScopeItemZero.cs b/src/CloudPDF/Documents/Types/ListDocumentsRequestOrder.cs similarity index 56% rename from src/CloudPDF/Types/TokensIssueRequestTenantScopeItemZero.cs rename to src/CloudPDF/Documents/Types/ListDocumentsRequestOrder.cs index 55360c2a..5848451d 100644 --- a/src/CloudPDF/Types/TokensIssueRequestTenantScopeItemZero.cs +++ b/src/CloudPDF/Documents/Types/ListDocumentsRequestOrder.cs @@ -4,15 +4,15 @@ namespace CloudPDF; -[JsonConverter( - typeof(TokensIssueRequestTenantScopeItemZero.TokensIssueRequestTenantScopeItemZeroSerializer) -)] +[JsonConverter(typeof(ListDocumentsRequestOrder.ListDocumentsRequestOrderSerializer))] [Serializable] -public readonly record struct TokensIssueRequestTenantScopeItemZero : IStringEnum +public readonly record struct ListDocumentsRequestOrder : IStringEnum { - public static readonly TokensIssueRequestTenantScopeItemZero All = new(Values.All); + public static readonly ListDocumentsRequestOrder Asc = new(Values.Asc); - public TokensIssueRequestTenantScopeItemZero(string value) + public static readonly ListDocumentsRequestOrder Desc = new(Values.Desc); + + public ListDocumentsRequestOrder(string value) { Value = value; } @@ -25,9 +25,9 @@ public TokensIssueRequestTenantScopeItemZero(string value) /// /// Create a string enum with the given value. /// - public static TokensIssueRequestTenantScopeItemZero FromCustom(string value) + public static ListDocumentsRequestOrder FromCustom(string value) { - return new TokensIssueRequestTenantScopeItemZero(value); + return new ListDocumentsRequestOrder(value); } public bool Equals(string? other) @@ -43,22 +43,19 @@ public override string ToString() return Value; } - public static bool operator ==(TokensIssueRequestTenantScopeItemZero value1, string value2) => + public static bool operator ==(ListDocumentsRequestOrder value1, string value2) => value1.Value.Equals(value2); - public static bool operator !=(TokensIssueRequestTenantScopeItemZero value1, string value2) => + public static bool operator !=(ListDocumentsRequestOrder value1, string value2) => !value1.Value.Equals(value2); - public static explicit operator string(TokensIssueRequestTenantScopeItemZero value) => - value.Value; + public static explicit operator string(ListDocumentsRequestOrder value) => value.Value; - public static explicit operator TokensIssueRequestTenantScopeItemZero(string value) => - new(value); + public static explicit operator ListDocumentsRequestOrder(string value) => new(value); - internal class TokensIssueRequestTenantScopeItemZeroSerializer - : JsonConverter + internal class ListDocumentsRequestOrderSerializer : JsonConverter { - public override TokensIssueRequestTenantScopeItemZero Read( + public override ListDocumentsRequestOrder Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options @@ -69,19 +66,19 @@ JsonSerializerOptions options ?? throw new global::System.Exception( "The JSON value could not be read as a string." ); - return new TokensIssueRequestTenantScopeItemZero(stringValue); + return new ListDocumentsRequestOrder(stringValue); } public override void Write( Utf8JsonWriter writer, - TokensIssueRequestTenantScopeItemZero value, + ListDocumentsRequestOrder value, JsonSerializerOptions options ) { writer.WriteStringValue(value.Value); } - public override TokensIssueRequestTenantScopeItemZero ReadAsPropertyName( + public override ListDocumentsRequestOrder ReadAsPropertyName( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options @@ -92,12 +89,12 @@ JsonSerializerOptions options ?? throw new global::System.Exception( "The JSON property name could not be read as a string." ); - return new TokensIssueRequestTenantScopeItemZero(stringValue); + return new ListDocumentsRequestOrder(stringValue); } public override void WriteAsPropertyName( Utf8JsonWriter writer, - TokensIssueRequestTenantScopeItemZero value, + ListDocumentsRequestOrder value, JsonSerializerOptions options ) { @@ -111,6 +108,8 @@ JsonSerializerOptions options [Serializable] public static class Values { - public const string All = "*"; + public const string Asc = "asc"; + + public const string Desc = "desc"; } } diff --git a/src/CloudPDF/Documents/Types/ListDocumentsRequestSort.cs b/src/CloudPDF/Documents/Types/ListDocumentsRequestSort.cs new file mode 100644 index 00000000..4968e202 --- /dev/null +++ b/src/CloudPDF/Documents/Types/ListDocumentsRequestSort.cs @@ -0,0 +1,119 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[JsonConverter(typeof(ListDocumentsRequestSort.ListDocumentsRequestSortSerializer))] +[Serializable] +public readonly record struct ListDocumentsRequestSort : IStringEnum +{ + public static readonly ListDocumentsRequestSort CreatedAt = new(Values.CreatedAt); + + public static readonly ListDocumentsRequestSort Name = new(Values.Name); + + public static readonly ListDocumentsRequestSort Size = new(Values.Size); + + public ListDocumentsRequestSort(string value) + { + Value = value; + } + + /// + /// The string value of the enum. + /// + public string Value { get; } + + /// + /// Create a string enum with the given value. + /// + public static ListDocumentsRequestSort FromCustom(string value) + { + return new ListDocumentsRequestSort(value); + } + + public bool Equals(string? other) + { + return Value.Equals(other); + } + + /// + /// Returns the string value of the enum. + /// + public override string ToString() + { + return Value; + } + + public static bool operator ==(ListDocumentsRequestSort value1, string value2) => + value1.Value.Equals(value2); + + public static bool operator !=(ListDocumentsRequestSort value1, string value2) => + !value1.Value.Equals(value2); + + public static explicit operator string(ListDocumentsRequestSort value) => value.Value; + + public static explicit operator ListDocumentsRequestSort(string value) => new(value); + + internal class ListDocumentsRequestSortSerializer : JsonConverter + { + public override ListDocumentsRequestSort Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = + reader.GetString() + ?? throw new global::System.Exception( + "The JSON value could not be read as a string." + ); + return new ListDocumentsRequestSort(stringValue); + } + + public override void Write( + Utf8JsonWriter writer, + ListDocumentsRequestSort value, + JsonSerializerOptions options + ) + { + writer.WriteStringValue(value.Value); + } + + public override ListDocumentsRequestSort ReadAsPropertyName( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = + reader.GetString() + ?? throw new global::System.Exception( + "The JSON property name could not be read as a string." + ); + return new ListDocumentsRequestSort(stringValue); + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + ListDocumentsRequestSort value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.Value); + } + } + + /// + /// Constant strings for enum values + /// + [Serializable] + public static class Values + { + public const string CreatedAt = "createdAt"; + + public const string Name = "name"; + + public const string Size = "size"; + } +} diff --git a/src/CloudPDF/Folders/FoldersClient.cs b/src/CloudPDF/Folders/FoldersClient.cs new file mode 100644 index 00000000..bf72aae8 --- /dev/null +++ b/src/CloudPDF/Folders/FoldersClient.cs @@ -0,0 +1,885 @@ +using CloudPDF.Core; +using global::System.Text.Json; + +namespace CloudPDF; + +public partial class FoldersClient : IFoldersClient +{ + private readonly RawClient _client; + + internal FoldersClient(RawClient client) + { + _client = client; + } + + private async Task> ListAsyncCore( + ListFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 3) + .Add("limit", request.Limit) + .Add("cursor", request.Cursor) + .Add("parentId", request.ParentId) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Get, + Path = string.Format( + "v1/tenants/{0}/folders", + ValueConvert.ToPathParameterString(request.TenantId) + ), + QueryString = _queryString, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new CloudPDFApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + switch (response.StatusCode) + { + case 400: + throw new BadRequestError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 403: + throw new ForbiddenError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 404: + throw new NotFoundError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + catch (JsonException) + { + // unable to map error response, throwing generic error + } + throw new CloudPDFApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + private async Task> CreateAsyncCore( + FoldersCreateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 0) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Post, + Path = string.Format( + "v1/tenants/{0}/folders", + ValueConvert.ToPathParameterString(request.TenantId) + ), + Body = request, + QueryString = _queryString, + Headers = _headers, + ContentType = "application/json", + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new CloudPDFApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + switch (response.StatusCode) + { + case 400: + throw new BadRequestError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 403: + throw new ForbiddenError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 404: + throw new NotFoundError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 409: + throw new ConflictError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + catch (JsonException) + { + // unable to map error response, throwing generic error + } + throw new CloudPDFApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + private async Task> GetAsyncCore( + GetFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 0) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Get, + Path = string.Format( + "v1/tenants/{0}/folders/{1}", + ValueConvert.ToPathParameterString(request.TenantId), + ValueConvert.ToPathParameterString(request.FolderId) + ), + QueryString = _queryString, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new CloudPDFApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + switch (response.StatusCode) + { + case 403: + throw new ForbiddenError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 404: + throw new NotFoundError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + catch (JsonException) + { + // unable to map error response, throwing generic error + } + throw new CloudPDFApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + private async Task DeleteAsyncCore( + DeleteFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 1) + .Add("recursive", request.Recursive) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Delete, + Path = string.Format( + "v1/tenants/{0}/folders/{1}", + ValueConvert.ToPathParameterString(request.TenantId), + ValueConvert.ToPathParameterString(request.FolderId) + ), + QueryString = _queryString, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + return new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }; + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + switch (response.StatusCode) + { + case 403: + throw new ForbiddenError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 404: + throw new NotFoundError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 409: + throw new ConflictError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + catch (JsonException) + { + // unable to map error response, throwing generic error + } + throw new CloudPDFApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + private async Task> UpdateAsyncCore( + FoldersUpdateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 0) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethodExtensions.Patch, + Path = string.Format( + "v1/tenants/{0}/folders/{1}", + ValueConvert.ToPathParameterString(request.TenantId), + ValueConvert.ToPathParameterString(request.FolderId) + ), + Body = request, + QueryString = _queryString, + Headers = _headers, + ContentType = "application/json", + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new CloudPDFApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + switch (response.StatusCode) + { + case 400: + throw new BadRequestError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 403: + throw new ForbiddenError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 404: + throw new NotFoundError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 409: + throw new ConflictError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + catch (JsonException) + { + // unable to map error response, throwing generic error + } + throw new CloudPDFApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + private async Task MoveIntoAsyncCore( + FoldersMoveIntoRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new CloudPDF.Core.QueryStringBuilder.Builder(capacity: 0) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new CloudPDF.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Post, + Path = string.Format( + "v1/tenants/{0}/folders/{1}/move-into", + ValueConvert.ToPathParameterString(request.TenantId), + ValueConvert.ToPathParameterString(request.FolderId) + ), + Body = request, + QueryString = _queryString, + Headers = _headers, + ContentType = "application/json", + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + return new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }; + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + switch (response.StatusCode) + { + case 400: + throw new BadRequestError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 403: + throw new ForbiddenError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 404: + throw new NotFoundError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + case 409: + throw new ConflictError( + JsonUtils.Deserialize(responseBody), + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = + response.Raw.RequestMessage?.RequestUri + ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + catch (JsonException) + { + // unable to map error response, throwing generic error + } + throw new CloudPDFApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new CloudPDF.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + /// + /// await client.Folders.ListAsync(new ListFoldersRequest { TenantId = "tenantId" }); + /// + public WithRawResponseTask ListAsync( + ListFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + ListAsyncCore(request, options, cancellationToken) + ); + } + + /// + /// 409 Conflict carries `details.reason`: `name-taken` (a sibling has the name, ignoring case; `details.name`) or `too-deep` (folders nest at most 100 levels; `details.maxDepth`). 404 when the parent folder does not exist. + /// + /// + /// await client.Folders.CreateAsync(new FoldersCreateRequest { TenantId = "tenantId", Name = "name" }); + /// + public WithRawResponseTask CreateAsync( + FoldersCreateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + CreateAsyncCore(request, options, cancellationToken) + ); + } + + /// + /// await client.Folders.GetAsync( + /// new GetFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } + /// ); + /// + public WithRawResponseTask GetAsync( + GetFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + GetAsyncCore(request, options, cancellationToken) + ); + } + + /// + /// Without recursive, a folder with anything inside is refused: 409 Conflict with `details.reason` `not-empty` and what it holds, counted over every level below, in `details.folders` and `details.documents`. With recursive=true, the folder and every folder under it go at once, and every document in them stops opening, leaves every list and stops answering its share links at once; their stored files and links are removed in the background. Uploads into those folders that have not committed cannot commit. + /// + /// + /// await client.Folders.DeleteAsync( + /// new DeleteFoldersRequest { TenantId = "tenantId", FolderId = "folderId" } + /// ); + /// + public WithRawResponseTask DeleteAsync( + DeleteFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask(DeleteAsyncCore(request, options, cancellationToken)); + } + + /// + /// 409 Conflict with `details.reason` `name-taken` when a sibling has the name, ignoring case. + /// + /// + /// await client.Folders.UpdateAsync( + /// new FoldersUpdateRequest + /// { + /// TenantId = "tenantId", + /// FolderId = "folderId", + /// Name = "name", + /// } + /// ); + /// + public WithRawResponseTask UpdateAsync( + FoldersUpdateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + UpdateAsyncCore(request, options, cancellationToken) + ); + } + + /// + /// Up to 1,000 ids in total. A folder moves with everything in it. 404 NotFound names the ids that do not exist or are being deleted in `details.documentIds` and `details.folderIds`. 409 Conflict carries `details.reason`: `cycle` (the destination is a moved folder or inside one; `details.folderId`), `too-deep` (the move would nest folders deeper than 100 levels; `details.maxDepth`) or `name-taken` (a moved folder's name is taken in the destination, ignoring case; `details.name`). + /// + /// + /// await client.Folders.MoveIntoAsync( + /// new FoldersMoveIntoRequest { TenantId = "tenantId", FolderId = "folderId" } + /// ); + /// + public WithRawResponseTask MoveIntoAsync( + FoldersMoveIntoRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask(MoveIntoAsyncCore(request, options, cancellationToken)); + } +} diff --git a/src/CloudPDF/Folders/IFoldersClient.cs b/src/CloudPDF/Folders/IFoldersClient.cs new file mode 100644 index 00000000..730dec6a --- /dev/null +++ b/src/CloudPDF/Folders/IFoldersClient.cs @@ -0,0 +1,52 @@ +namespace CloudPDF; + +public partial interface IFoldersClient +{ + WithRawResponseTask ListAsync( + ListFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + + /// + /// 409 Conflict carries `details.reason`: `name-taken` (a sibling has the name, ignoring case; `details.name`) or `too-deep` (folders nest at most 100 levels; `details.maxDepth`). 404 when the parent folder does not exist. + /// + WithRawResponseTask CreateAsync( + FoldersCreateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + + WithRawResponseTask GetAsync( + GetFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + + /// + /// Without recursive, a folder with anything inside is refused: 409 Conflict with `details.reason` `not-empty` and what it holds, counted over every level below, in `details.folders` and `details.documents`. With recursive=true, the folder and every folder under it go at once, and every document in them stops opening, leaves every list and stops answering its share links at once; their stored files and links are removed in the background. Uploads into those folders that have not committed cannot commit. + /// + WithRawResponseTask DeleteAsync( + DeleteFoldersRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + + /// + /// 409 Conflict with `details.reason` `name-taken` when a sibling has the name, ignoring case. + /// + WithRawResponseTask UpdateAsync( + FoldersUpdateRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + + /// + /// Up to 1,000 ids in total. A folder moves with everything in it. 404 NotFound names the ids that do not exist or are being deleted in `details.documentIds` and `details.folderIds`. 409 Conflict carries `details.reason`: `cycle` (the destination is a moved folder or inside one; `details.folderId`), `too-deep` (the move would nest folders deeper than 100 levels; `details.maxDepth`) or `name-taken` (a moved folder's name is taken in the destination, ignoring case; `details.name`). + /// + WithRawResponseTask MoveIntoAsync( + FoldersMoveIntoRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/CloudPDF/Folders/Requests/DeleteFoldersRequest.cs b/src/CloudPDF/Folders/Requests/DeleteFoldersRequest.cs new file mode 100644 index 00000000..8311a53f --- /dev/null +++ b/src/CloudPDF/Folders/Requests/DeleteFoldersRequest.cs @@ -0,0 +1,26 @@ +using CloudPDF.Core; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record DeleteFoldersRequest +{ + [JsonIgnore] + public required string TenantId { get; set; } + + [JsonIgnore] + public required string FolderId { get; set; } + + /// + /// true deletes everything in the folder too. Never the default. + /// + [JsonIgnore] + public bool? Recursive { get; set; } + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Folders/Requests/FoldersCreateRequest.cs b/src/CloudPDF/Folders/Requests/FoldersCreateRequest.cs new file mode 100644 index 00000000..33887f11 --- /dev/null +++ b/src/CloudPDF/Folders/Requests/FoldersCreateRequest.cs @@ -0,0 +1,29 @@ +using CloudPDF.Core; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersCreateRequest +{ + [JsonIgnore] + public required string TenantId { get; set; } + + /// + /// What people call the folder: 1 to 255 characters, no control characters, no leading or trailing whitespace, and unique among the folder's siblings, ignoring case. + /// + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// A folder id, or root for the top level. + /// + [JsonPropertyName("parentId")] + public string? ParentId { get; set; } + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Folders/Requests/FoldersMoveIntoRequest.cs b/src/CloudPDF/Folders/Requests/FoldersMoveIntoRequest.cs new file mode 100644 index 00000000..e5b940fc --- /dev/null +++ b/src/CloudPDF/Folders/Requests/FoldersMoveIntoRequest.cs @@ -0,0 +1,29 @@ +using CloudPDF.Core; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersMoveIntoRequest +{ + [JsonIgnore] + public required string TenantId { get; set; } + + /// + /// A folder id, or root for the top level. + /// + [JsonIgnore] + public required string FolderId { get; set; } + + [JsonPropertyName("documentIds")] + public IEnumerable? DocumentIds { get; set; } + + [JsonPropertyName("folderIds")] + public IEnumerable? FolderIds { get; set; } + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Folders/Requests/FoldersUpdateRequest.cs b/src/CloudPDF/Folders/Requests/FoldersUpdateRequest.cs new file mode 100644 index 00000000..07a5ab26 --- /dev/null +++ b/src/CloudPDF/Folders/Requests/FoldersUpdateRequest.cs @@ -0,0 +1,26 @@ +using CloudPDF.Core; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersUpdateRequest +{ + [JsonIgnore] + public required string TenantId { get; set; } + + [JsonIgnore] + public required string FolderId { get; set; } + + /// + /// What people call the folder: 1 to 255 characters, no control characters, no leading or trailing whitespace, and unique among the folder's siblings, ignoring case. + /// + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Folders/Requests/GetFoldersRequest.cs b/src/CloudPDF/Folders/Requests/GetFoldersRequest.cs new file mode 100644 index 00000000..ffcd6149 --- /dev/null +++ b/src/CloudPDF/Folders/Requests/GetFoldersRequest.cs @@ -0,0 +1,20 @@ +using CloudPDF.Core; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record GetFoldersRequest +{ + [JsonIgnore] + public required string TenantId { get; set; } + + [JsonIgnore] + public required string FolderId { get; set; } + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Folders/Requests/ListFoldersRequest.cs b/src/CloudPDF/Folders/Requests/ListFoldersRequest.cs new file mode 100644 index 00000000..d98797a0 --- /dev/null +++ b/src/CloudPDF/Folders/Requests/ListFoldersRequest.cs @@ -0,0 +1,29 @@ +using CloudPDF.Core; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record ListFoldersRequest +{ + [JsonIgnore] + public required string TenantId { get; set; } + + [JsonIgnore] + public int? Limit { get; set; } + + [JsonIgnore] + public string? Cursor { get; set; } + + /// + /// Only the folders directly in this folder (root: the top level). Without it, every folder. + /// + [JsonIgnore] + public string? ParentId { get; set; } + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/ICloudPDFClient.cs b/src/CloudPDF/ICloudPDFClient.cs index ec71076c..525316f1 100644 --- a/src/CloudPDF/ICloudPDFClient.cs +++ b/src/CloudPDF/ICloudPDFClient.cs @@ -7,5 +7,6 @@ public partial interface ICloudPDFClient public ISharesClient Shares { get; } public ITenantsClient Tenants { get; } public IDocumentsClient Documents { get; } + public IFoldersClient Folders { get; } public ITokensClient Tokens { get; } } diff --git a/src/CloudPDF/Shares/Requests/SharesCreateRequest.cs b/src/CloudPDF/Shares/Requests/SharesCreateRequest.cs index 9a99cfff..bde314be 100644 --- a/src/CloudPDF/Shares/Requests/SharesCreateRequest.cs +++ b/src/CloudPDF/Shares/Requests/SharesCreateRequest.cs @@ -27,6 +27,9 @@ public record SharesCreateRequest [JsonPropertyName("visitorIdentity")] public SharesCreateRequestVisitorIdentity? VisitorIdentity { get; set; } + [JsonPropertyName("identity")] + public Identity? Identity { get; set; } + [JsonPropertyName("scope")] public IEnumerable Scope { get; set; } = new List(); diff --git a/src/CloudPDF/Shares/Requests/SharesUpdateRequest.cs b/src/CloudPDF/Shares/Requests/SharesUpdateRequest.cs index 04307e40..481c9950 100644 --- a/src/CloudPDF/Shares/Requests/SharesUpdateRequest.cs +++ b/src/CloudPDF/Shares/Requests/SharesUpdateRequest.cs @@ -27,6 +27,9 @@ public record SharesUpdateRequest [JsonPropertyName("visitorIdentity")] public SharesUpdateRequestVisitorIdentity? VisitorIdentity { get; set; } + [JsonPropertyName("identity")] + public Identity? Identity { get; set; } + [JsonPropertyName("scope")] public IEnumerable? Scope { get; set; } diff --git a/src/CloudPDF/Types/DocVersionsList200Response.cs b/src/CloudPDF/Types/DocVersionsList200Response.cs index 281a53ec..0a65495e 100644 --- a/src/CloudPDF/Types/DocVersionsList200Response.cs +++ b/src/CloudPDF/Types/DocVersionsList200Response.cs @@ -11,8 +11,8 @@ public record DocVersionsList200Response : IJsonOnDeserialized private readonly IDictionary _extensionData = new Dictionary(); - [JsonPropertyName("head")] - public required string Head { get; set; } + [JsonPropertyName("baseSha")] + public required string BaseSha { get; set; } [JsonPropertyName("versions")] public IEnumerable Versions { get; set; } = diff --git a/src/CloudPDF/Types/DocumentsCommit200ResponseDocument.cs b/src/CloudPDF/Types/DocumentsCommit200ResponseDocument.cs index 86dd5c13..27d1a0e8 100644 --- a/src/CloudPDF/Types/DocumentsCommit200ResponseDocument.cs +++ b/src/CloudPDF/Types/DocumentsCommit200ResponseDocument.cs @@ -17,6 +17,15 @@ public record DocumentsCommit200ResponseDocument : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsCommit200ResponseDocumentState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsGet200ResponseDocument.cs b/src/CloudPDF/Types/DocumentsGet200ResponseDocument.cs index d014b8d2..ff6fb59b 100644 --- a/src/CloudPDF/Types/DocumentsGet200ResponseDocument.cs +++ b/src/CloudPDF/Types/DocumentsGet200ResponseDocument.cs @@ -17,6 +17,15 @@ public record DocumentsGet200ResponseDocument : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsGet200ResponseDocumentState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsImportFrom200ResponseDocument.cs b/src/CloudPDF/Types/DocumentsImportFrom200ResponseDocument.cs index a46a68ef..66a5cdd4 100644 --- a/src/CloudPDF/Types/DocumentsImportFrom200ResponseDocument.cs +++ b/src/CloudPDF/Types/DocumentsImportFrom200ResponseDocument.cs @@ -17,6 +17,15 @@ public record DocumentsImportFrom200ResponseDocument : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsImportFrom200ResponseDocumentState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsImportFrom202ResponseDocument.cs b/src/CloudPDF/Types/DocumentsImportFrom202ResponseDocument.cs index c1a5709a..9025676c 100644 --- a/src/CloudPDF/Types/DocumentsImportFrom202ResponseDocument.cs +++ b/src/CloudPDF/Types/DocumentsImportFrom202ResponseDocument.cs @@ -17,6 +17,15 @@ public record DocumentsImportFrom202ResponseDocument : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsImportFrom202ResponseDocumentState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsInit200ResponseCreatedDocument.cs b/src/CloudPDF/Types/DocumentsInit200ResponseCreatedDocument.cs index acb7d62d..b0b7b437 100644 --- a/src/CloudPDF/Types/DocumentsInit200ResponseCreatedDocument.cs +++ b/src/CloudPDF/Types/DocumentsInit200ResponseCreatedDocument.cs @@ -17,6 +17,15 @@ public record DocumentsInit200ResponseCreatedDocument : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsInit200ResponseCreatedDocumentState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsInit200ResponseDedupedDocument.cs b/src/CloudPDF/Types/DocumentsInit200ResponseDedupedDocument.cs index 923ba53f..c110998b 100644 --- a/src/CloudPDF/Types/DocumentsInit200ResponseDedupedDocument.cs +++ b/src/CloudPDF/Types/DocumentsInit200ResponseDedupedDocument.cs @@ -17,6 +17,15 @@ public record DocumentsInit200ResponseDedupedDocument : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsInit200ResponseDedupedDocumentState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsInit200ResponseResumedDocument.cs b/src/CloudPDF/Types/DocumentsInit200ResponseResumedDocument.cs index bfd5603c..8f736efb 100644 --- a/src/CloudPDF/Types/DocumentsInit200ResponseResumedDocument.cs +++ b/src/CloudPDF/Types/DocumentsInit200ResponseResumedDocument.cs @@ -17,6 +17,15 @@ public record DocumentsInit200ResponseResumedDocument : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsInit200ResponseResumedDocumentState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsList200ResponseDocumentsItem.cs b/src/CloudPDF/Types/DocumentsList200ResponseDocumentsItem.cs index 95935c0f..c3e56f68 100644 --- a/src/CloudPDF/Types/DocumentsList200ResponseDocumentsItem.cs +++ b/src/CloudPDF/Types/DocumentsList200ResponseDocumentsItem.cs @@ -17,6 +17,15 @@ public record DocumentsList200ResponseDocumentsItem : IJsonOnDeserialized [JsonPropertyName("tenantId")] public required string TenantId { get; set; } + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + [JsonPropertyName("state")] public required DocumentsList200ResponseDocumentsItemState State { get; set; } diff --git a/src/CloudPDF/Types/DocumentsUpdate200Response.cs b/src/CloudPDF/Types/DocumentsUpdate200Response.cs new file mode 100644 index 00000000..e5cda3d5 --- /dev/null +++ b/src/CloudPDF/Types/DocumentsUpdate200Response.cs @@ -0,0 +1,28 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record DocumentsUpdate200Response : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("document")] + public required DocumentsUpdate200ResponseDocument Document { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/DocumentsUpdate200ResponseDocument.cs b/src/CloudPDF/Types/DocumentsUpdate200ResponseDocument.cs new file mode 100644 index 00000000..2a6089f8 --- /dev/null +++ b/src/CloudPDF/Types/DocumentsUpdate200ResponseDocument.cs @@ -0,0 +1,73 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record DocumentsUpdate200ResponseDocument : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonPropertyName("tenantId")] + public required string TenantId { get; set; } + + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// + /// The folder the document is in, or root. + /// + [JsonPropertyName("folderId")] + public required string FolderId { get; set; } + + [JsonPropertyName("state")] + public required DocumentsUpdate200ResponseDocumentState State { get; set; } + + [JsonPropertyName("baseSha")] + public string? BaseSha { get; set; } + + [JsonPropertyName("storageSizeBytes")] + public double? StorageSizeBytes { get; set; } + + [JsonPropertyName("metadata")] + public Dictionary? Metadata { get; set; } + + [JsonPropertyName("idempotencyKey")] + public string? IdempotencyKey { get; set; } + + [JsonPropertyName("failureReason")] + public string? FailureReason { get; set; } + + [JsonPropertyName("thumbnailState")] + public DocumentsUpdate200ResponseDocumentThumbnailState? ThumbnailState { get; set; } + + [JsonPropertyName("thumbnailUrl")] + public string? ThumbnailUrl { get; set; } + + [JsonPropertyName("createdAt")] + public required double CreatedAt { get; set; } + + [JsonPropertyName("updatedAt")] + public required double UpdatedAt { get; set; } + + [JsonPropertyName("createdBy")] + public string? CreatedBy { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/DocumentsUpdate200ResponseDocumentState.cs b/src/CloudPDF/Types/DocumentsUpdate200ResponseDocumentState.cs new file mode 100644 index 00000000..5e9fdaf7 --- /dev/null +++ b/src/CloudPDF/Types/DocumentsUpdate200ResponseDocumentState.cs @@ -0,0 +1,128 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[JsonConverter( + typeof(DocumentsUpdate200ResponseDocumentState.DocumentsUpdate200ResponseDocumentStateSerializer) +)] +[Serializable] +public readonly record struct DocumentsUpdate200ResponseDocumentState : IStringEnum +{ + public static readonly DocumentsUpdate200ResponseDocumentState Pending = new(Values.Pending); + + public static readonly DocumentsUpdate200ResponseDocumentState Ready = new(Values.Ready); + + public static readonly DocumentsUpdate200ResponseDocumentState Failed = new(Values.Failed); + + public static readonly DocumentsUpdate200ResponseDocumentState Deleting = new(Values.Deleting); + + public DocumentsUpdate200ResponseDocumentState(string value) + { + Value = value; + } + + /// + /// The string value of the enum. + /// + public string Value { get; } + + /// + /// Create a string enum with the given value. + /// + public static DocumentsUpdate200ResponseDocumentState FromCustom(string value) + { + return new DocumentsUpdate200ResponseDocumentState(value); + } + + public bool Equals(string? other) + { + return Value.Equals(other); + } + + /// + /// Returns the string value of the enum. + /// + public override string ToString() + { + return Value; + } + + public static bool operator ==(DocumentsUpdate200ResponseDocumentState value1, string value2) => + value1.Value.Equals(value2); + + public static bool operator !=(DocumentsUpdate200ResponseDocumentState value1, string value2) => + !value1.Value.Equals(value2); + + public static explicit operator string(DocumentsUpdate200ResponseDocumentState value) => + value.Value; + + public static explicit operator DocumentsUpdate200ResponseDocumentState(string value) => + new(value); + + internal class DocumentsUpdate200ResponseDocumentStateSerializer + : JsonConverter + { + public override DocumentsUpdate200ResponseDocumentState Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = + reader.GetString() + ?? throw new global::System.Exception( + "The JSON value could not be read as a string." + ); + return new DocumentsUpdate200ResponseDocumentState(stringValue); + } + + public override void Write( + Utf8JsonWriter writer, + DocumentsUpdate200ResponseDocumentState value, + JsonSerializerOptions options + ) + { + writer.WriteStringValue(value.Value); + } + + public override DocumentsUpdate200ResponseDocumentState ReadAsPropertyName( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = + reader.GetString() + ?? throw new global::System.Exception( + "The JSON property name could not be read as a string." + ); + return new DocumentsUpdate200ResponseDocumentState(stringValue); + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + DocumentsUpdate200ResponseDocumentState value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.Value); + } + } + + /// + /// Constant strings for enum values + /// + [Serializable] + public static class Values + { + public const string Pending = "pending"; + + public const string Ready = "ready"; + + public const string Failed = "failed"; + + public const string Deleting = "deleting"; + } +} diff --git a/src/CloudPDF/Types/DocumentsUpdate200ResponseDocumentThumbnailState.cs b/src/CloudPDF/Types/DocumentsUpdate200ResponseDocumentThumbnailState.cs new file mode 100644 index 00000000..b37cf10a --- /dev/null +++ b/src/CloudPDF/Types/DocumentsUpdate200ResponseDocumentThumbnailState.cs @@ -0,0 +1,142 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[JsonConverter( + typeof(DocumentsUpdate200ResponseDocumentThumbnailState.DocumentsUpdate200ResponseDocumentThumbnailStateSerializer) +)] +[Serializable] +public readonly record struct DocumentsUpdate200ResponseDocumentThumbnailState : IStringEnum +{ + public static readonly DocumentsUpdate200ResponseDocumentThumbnailState Pending = new( + Values.Pending + ); + + public static readonly DocumentsUpdate200ResponseDocumentThumbnailState Ready = new( + Values.Ready + ); + + public static readonly DocumentsUpdate200ResponseDocumentThumbnailState Locked = new( + Values.Locked + ); + + public static readonly DocumentsUpdate200ResponseDocumentThumbnailState Failed = new( + Values.Failed + ); + + public DocumentsUpdate200ResponseDocumentThumbnailState(string value) + { + Value = value; + } + + /// + /// The string value of the enum. + /// + public string Value { get; } + + /// + /// Create a string enum with the given value. + /// + public static DocumentsUpdate200ResponseDocumentThumbnailState FromCustom(string value) + { + return new DocumentsUpdate200ResponseDocumentThumbnailState(value); + } + + public bool Equals(string? other) + { + return Value.Equals(other); + } + + /// + /// Returns the string value of the enum. + /// + public override string ToString() + { + return Value; + } + + public static bool operator ==( + DocumentsUpdate200ResponseDocumentThumbnailState value1, + string value2 + ) => value1.Value.Equals(value2); + + public static bool operator !=( + DocumentsUpdate200ResponseDocumentThumbnailState value1, + string value2 + ) => !value1.Value.Equals(value2); + + public static explicit operator string( + DocumentsUpdate200ResponseDocumentThumbnailState value + ) => value.Value; + + public static explicit operator DocumentsUpdate200ResponseDocumentThumbnailState( + string value + ) => new(value); + + internal class DocumentsUpdate200ResponseDocumentThumbnailStateSerializer + : JsonConverter + { + public override DocumentsUpdate200ResponseDocumentThumbnailState Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = + reader.GetString() + ?? throw new global::System.Exception( + "The JSON value could not be read as a string." + ); + return new DocumentsUpdate200ResponseDocumentThumbnailState(stringValue); + } + + public override void Write( + Utf8JsonWriter writer, + DocumentsUpdate200ResponseDocumentThumbnailState value, + JsonSerializerOptions options + ) + { + writer.WriteStringValue(value.Value); + } + + public override DocumentsUpdate200ResponseDocumentThumbnailState ReadAsPropertyName( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = + reader.GetString() + ?? throw new global::System.Exception( + "The JSON property name could not be read as a string." + ); + return new DocumentsUpdate200ResponseDocumentThumbnailState(stringValue); + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + DocumentsUpdate200ResponseDocumentThumbnailState value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.Value); + } + } + + /// + /// Constant strings for enum values + /// + [Serializable] + public static class Values + { + public const string Pending = "pending"; + + public const string Ready = "ready"; + + public const string Locked = "locked"; + + public const string Failed = "failed"; + } +} diff --git a/src/CloudPDF/Types/EngineErrorPayloadCode.cs b/src/CloudPDF/Types/EngineErrorPayloadCode.cs index 671ba7b1..ede52e1b 100644 --- a/src/CloudPDF/Types/EngineErrorPayloadCode.cs +++ b/src/CloudPDF/Types/EngineErrorPayloadCode.cs @@ -64,8 +64,6 @@ namespace CloudPDF; public static readonly EngineErrorPayloadCode ProtectedDocument = new(Values.ProtectedDocument); - public static readonly EngineErrorPayloadCode StaleBase = new(Values.StaleBase); - public static readonly EngineErrorPayloadCode PayloadTooLarge = new(Values.PayloadTooLarge); public static readonly EngineErrorPayloadCode ObjectNumberUnavailable = new( @@ -228,8 +226,6 @@ public static class Values public const string ProtectedDocument = "ProtectedDocument"; - public const string StaleBase = "StaleBase"; - public const string PayloadTooLarge = "PayloadTooLarge"; public const string ObjectNumberUnavailable = "ObjectNumberUnavailable"; diff --git a/src/CloudPDF/Types/FoldersCreate200Response.cs b/src/CloudPDF/Types/FoldersCreate200Response.cs new file mode 100644 index 00000000..71443630 --- /dev/null +++ b/src/CloudPDF/Types/FoldersCreate200Response.cs @@ -0,0 +1,28 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersCreate200Response : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("folder")] + public required FoldersCreate200ResponseFolder Folder { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersCreate200ResponseFolder.cs b/src/CloudPDF/Types/FoldersCreate200ResponseFolder.cs new file mode 100644 index 00000000..701217dd --- /dev/null +++ b/src/CloudPDF/Types/FoldersCreate200ResponseFolder.cs @@ -0,0 +1,49 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersCreate200ResponseFolder : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonPropertyName("tenantId")] + public required string TenantId { get; set; } + + /// + /// The folder it is in, or root. + /// + [JsonPropertyName("parentId")] + public required string ParentId { get; set; } + + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("createdAt")] + public required double CreatedAt { get; set; } + + [JsonPropertyName("updatedAt")] + public required double UpdatedAt { get; set; } + + [JsonPropertyName("createdBy")] + public string? CreatedBy { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersGet200Response.cs b/src/CloudPDF/Types/FoldersGet200Response.cs new file mode 100644 index 00000000..3815cff0 --- /dev/null +++ b/src/CloudPDF/Types/FoldersGet200Response.cs @@ -0,0 +1,35 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersGet200Response : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("folder")] + public required FoldersGet200ResponseFolder Folder { get; set; } + + /// + /// The folders above this one, from the top level down. Neither root nor the folder itself. + /// + [JsonPropertyName("path")] + public IEnumerable Path { get; set; } = + new List(); + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersGet200ResponseFolder.cs b/src/CloudPDF/Types/FoldersGet200ResponseFolder.cs new file mode 100644 index 00000000..56faa383 --- /dev/null +++ b/src/CloudPDF/Types/FoldersGet200ResponseFolder.cs @@ -0,0 +1,49 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersGet200ResponseFolder : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonPropertyName("tenantId")] + public required string TenantId { get; set; } + + /// + /// The folder it is in, or root. + /// + [JsonPropertyName("parentId")] + public required string ParentId { get; set; } + + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("createdAt")] + public required double CreatedAt { get; set; } + + [JsonPropertyName("updatedAt")] + public required double UpdatedAt { get; set; } + + [JsonPropertyName("createdBy")] + public string? CreatedBy { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersGet200ResponsePathItem.cs b/src/CloudPDF/Types/FoldersGet200ResponsePathItem.cs new file mode 100644 index 00000000..36f2fe9d --- /dev/null +++ b/src/CloudPDF/Types/FoldersGet200ResponsePathItem.cs @@ -0,0 +1,31 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersGet200ResponsePathItem : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersList200Response.cs b/src/CloudPDF/Types/FoldersList200Response.cs new file mode 100644 index 00000000..992b0c34 --- /dev/null +++ b/src/CloudPDF/Types/FoldersList200Response.cs @@ -0,0 +1,32 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersList200Response : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("folders")] + public IEnumerable Folders { get; set; } = + new List(); + + [JsonPropertyName("nextCursor")] + public string? NextCursor { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersList200ResponseFoldersItem.cs b/src/CloudPDF/Types/FoldersList200ResponseFoldersItem.cs new file mode 100644 index 00000000..b9e94d69 --- /dev/null +++ b/src/CloudPDF/Types/FoldersList200ResponseFoldersItem.cs @@ -0,0 +1,49 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersList200ResponseFoldersItem : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonPropertyName("tenantId")] + public required string TenantId { get; set; } + + /// + /// The folder it is in, or root. + /// + [JsonPropertyName("parentId")] + public required string ParentId { get; set; } + + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("createdAt")] + public required double CreatedAt { get; set; } + + [JsonPropertyName("updatedAt")] + public required double UpdatedAt { get; set; } + + [JsonPropertyName("createdBy")] + public string? CreatedBy { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersUpdate200Response.cs b/src/CloudPDF/Types/FoldersUpdate200Response.cs new file mode 100644 index 00000000..6922931f --- /dev/null +++ b/src/CloudPDF/Types/FoldersUpdate200Response.cs @@ -0,0 +1,28 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersUpdate200Response : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("folder")] + public required FoldersUpdate200ResponseFolder Folder { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/FoldersUpdate200ResponseFolder.cs b/src/CloudPDF/Types/FoldersUpdate200ResponseFolder.cs new file mode 100644 index 00000000..baf9dc4e --- /dev/null +++ b/src/CloudPDF/Types/FoldersUpdate200ResponseFolder.cs @@ -0,0 +1,49 @@ +using CloudPDF.Core; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace CloudPDF; + +[Serializable] +public record FoldersUpdate200ResponseFolder : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonPropertyName("tenantId")] + public required string TenantId { get; set; } + + /// + /// The folder it is in, or root. + /// + [JsonPropertyName("parentId")] + public required string ParentId { get; set; } + + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("createdAt")] + public required double CreatedAt { get; set; } + + [JsonPropertyName("updatedAt")] + public required double UpdatedAt { get; set; } + + [JsonPropertyName("createdBy")] + public string? CreatedBy { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/CloudPDF/Types/TokensIssueRequestDocIdentity.cs b/src/CloudPDF/Types/Identity.cs similarity index 94% rename from src/CloudPDF/Types/TokensIssueRequestDocIdentity.cs rename to src/CloudPDF/Types/Identity.cs index 80aa342c..1848d70d 100644 --- a/src/CloudPDF/Types/TokensIssueRequestDocIdentity.cs +++ b/src/CloudPDF/Types/Identity.cs @@ -5,7 +5,7 @@ namespace CloudPDF; [Serializable] -public record TokensIssueRequestDocIdentity : IJsonOnDeserialized +public record Identity : IJsonOnDeserialized { [JsonExtensionData] private readonly IDictionary _extensionData = diff --git a/src/CloudPDF/Types/SharesArchive200ResponseShare.cs b/src/CloudPDF/Types/SharesArchive200ResponseShare.cs index d3fd2d77..9739c9a0 100644 --- a/src/CloudPDF/Types/SharesArchive200ResponseShare.cs +++ b/src/CloudPDF/Types/SharesArchive200ResponseShare.cs @@ -35,6 +35,9 @@ public record SharesArchive200ResponseShare : IJsonOnDeserialized [JsonPropertyName("visitorIdentity")] public SharesArchive200ResponseShareVisitorIdentity? VisitorIdentity { get; set; } + [JsonPropertyName("identity")] + public Identity? Identity { get; set; } + [JsonPropertyName("scope")] public IEnumerable Scope { get; set; } = new List(); diff --git a/src/CloudPDF/Types/SharesCreate200ResponseShare.cs b/src/CloudPDF/Types/SharesCreate200ResponseShare.cs index b4b2d0cd..df4a2c18 100644 --- a/src/CloudPDF/Types/SharesCreate200ResponseShare.cs +++ b/src/CloudPDF/Types/SharesCreate200ResponseShare.cs @@ -35,6 +35,9 @@ public record SharesCreate200ResponseShare : IJsonOnDeserialized [JsonPropertyName("visitorIdentity")] public SharesCreate200ResponseShareVisitorIdentity? VisitorIdentity { get; set; } + [JsonPropertyName("identity")] + public Identity? Identity { get; set; } + [JsonPropertyName("scope")] public IEnumerable Scope { get; set; } = new List(); diff --git a/src/CloudPDF/Types/SharesGet200ResponseShare.cs b/src/CloudPDF/Types/SharesGet200ResponseShare.cs index c18ac3c4..8c4ebe78 100644 --- a/src/CloudPDF/Types/SharesGet200ResponseShare.cs +++ b/src/CloudPDF/Types/SharesGet200ResponseShare.cs @@ -35,6 +35,9 @@ public record SharesGet200ResponseShare : IJsonOnDeserialized [JsonPropertyName("visitorIdentity")] public SharesGet200ResponseShareVisitorIdentity? VisitorIdentity { get; set; } + [JsonPropertyName("identity")] + public Identity? Identity { get; set; } + [JsonPropertyName("scope")] public IEnumerable Scope { get; set; } = new List(); diff --git a/src/CloudPDF/Types/SharesList200ResponseSharesItem.cs b/src/CloudPDF/Types/SharesList200ResponseSharesItem.cs index 4c9f91f0..1bb8d434 100644 --- a/src/CloudPDF/Types/SharesList200ResponseSharesItem.cs +++ b/src/CloudPDF/Types/SharesList200ResponseSharesItem.cs @@ -35,6 +35,9 @@ public record SharesList200ResponseSharesItem : IJsonOnDeserialized [JsonPropertyName("visitorIdentity")] public SharesList200ResponseSharesItemVisitorIdentity? VisitorIdentity { get; set; } + [JsonPropertyName("identity")] + public Identity? Identity { get; set; } + [JsonPropertyName("scope")] public IEnumerable Scope { get; set; } = new List(); diff --git a/src/CloudPDF/Types/SharesUpdate200ResponseShare.cs b/src/CloudPDF/Types/SharesUpdate200ResponseShare.cs index 16813204..88cce5ef 100644 --- a/src/CloudPDF/Types/SharesUpdate200ResponseShare.cs +++ b/src/CloudPDF/Types/SharesUpdate200ResponseShare.cs @@ -35,6 +35,9 @@ public record SharesUpdate200ResponseShare : IJsonOnDeserialized [JsonPropertyName("visitorIdentity")] public SharesUpdate200ResponseShareVisitorIdentity? VisitorIdentity { get; set; } + [JsonPropertyName("identity")] + public Identity? Identity { get; set; } + [JsonPropertyName("scope")] public IEnumerable Scope { get; set; } = new List(); diff --git a/src/CloudPDF/Types/TokensIssueRequestDoc.cs b/src/CloudPDF/Types/TokensIssueRequestDoc.cs index 124c6d98..cffab143 100644 --- a/src/CloudPDF/Types/TokensIssueRequestDoc.cs +++ b/src/CloudPDF/Types/TokensIssueRequestDoc.cs @@ -24,7 +24,7 @@ public record TokensIssueRequestDoc : IJsonOnDeserialized public IEnumerable Scope { get; set; } = new List(); [JsonPropertyName("identity")] - public TokensIssueRequestDocIdentity? Identity { get; set; } + public Identity? Identity { get; set; } [JsonPropertyName("origins")] public IEnumerable? Origins { get; set; } diff --git a/src/CloudPDF/Types/TokensIssueRequestTenant.cs b/src/CloudPDF/Types/TokensIssueRequestTenant.cs index c0ef70ae..dd9457d6 100644 --- a/src/CloudPDF/Types/TokensIssueRequestTenant.cs +++ b/src/CloudPDF/Types/TokensIssueRequestTenant.cs @@ -1,7 +1,6 @@ using CloudPDF.Core; using global::System.Text.Json; using global::System.Text.Json.Serialization; -using OneOf; namespace CloudPDF; @@ -16,12 +15,7 @@ public record TokensIssueRequestTenant : IJsonOnDeserialized public required string Sub { get; set; } [JsonPropertyName("scope")] - public IEnumerable< - OneOf - > Scope { get; set; } = - new List< - OneOf - >(); + public IEnumerable Scope { get; set; } = new List(); [JsonPropertyName("expiresIn")] public required int ExpiresIn { get; set; } diff --git a/src/CloudPDF/Types/TokensIssueRequestTenantScopeItemOne.cs b/src/CloudPDF/Types/TokensIssueRequestTenantScopeItemOne.cs deleted file mode 100644 index edb53b8c..00000000 --- a/src/CloudPDF/Types/TokensIssueRequestTenantScopeItemOne.cs +++ /dev/null @@ -1,142 +0,0 @@ -using CloudPDF.Core; -using global::System.Text.Json; -using global::System.Text.Json.Serialization; - -namespace CloudPDF; - -[JsonConverter( - typeof(TokensIssueRequestTenantScopeItemOne.TokensIssueRequestTenantScopeItemOneSerializer) -)] -[Serializable] -public readonly record struct TokensIssueRequestTenantScopeItemOne : IStringEnum -{ - public static readonly TokensIssueRequestTenantScopeItemOne DocsCreate = new(Values.DocsCreate); - - public static readonly TokensIssueRequestTenantScopeItemOne DocsRead = new(Values.DocsRead); - - public static readonly TokensIssueRequestTenantScopeItemOne DocsDelete = new(Values.DocsDelete); - - public static readonly TokensIssueRequestTenantScopeItemOne TokensIssueDoc = new( - Values.TokensIssueDoc - ); - - public static readonly TokensIssueRequestTenantScopeItemOne TokensRevoke = new( - Values.TokensRevoke - ); - - public static readonly TokensIssueRequestTenantScopeItemOne SharesManage = new( - Values.SharesManage - ); - - public TokensIssueRequestTenantScopeItemOne(string value) - { - Value = value; - } - - /// - /// The string value of the enum. - /// - public string Value { get; } - - /// - /// Create a string enum with the given value. - /// - public static TokensIssueRequestTenantScopeItemOne FromCustom(string value) - { - return new TokensIssueRequestTenantScopeItemOne(value); - } - - public bool Equals(string? other) - { - return Value.Equals(other); - } - - /// - /// Returns the string value of the enum. - /// - public override string ToString() - { - return Value; - } - - public static bool operator ==(TokensIssueRequestTenantScopeItemOne value1, string value2) => - value1.Value.Equals(value2); - - public static bool operator !=(TokensIssueRequestTenantScopeItemOne value1, string value2) => - !value1.Value.Equals(value2); - - public static explicit operator string(TokensIssueRequestTenantScopeItemOne value) => - value.Value; - - public static explicit operator TokensIssueRequestTenantScopeItemOne(string value) => - new(value); - - internal class TokensIssueRequestTenantScopeItemOneSerializer - : JsonConverter - { - public override TokensIssueRequestTenantScopeItemOne Read( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options - ) - { - var stringValue = - reader.GetString() - ?? throw new global::System.Exception( - "The JSON value could not be read as a string." - ); - return new TokensIssueRequestTenantScopeItemOne(stringValue); - } - - public override void Write( - Utf8JsonWriter writer, - TokensIssueRequestTenantScopeItemOne value, - JsonSerializerOptions options - ) - { - writer.WriteStringValue(value.Value); - } - - public override TokensIssueRequestTenantScopeItemOne ReadAsPropertyName( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options - ) - { - var stringValue = - reader.GetString() - ?? throw new global::System.Exception( - "The JSON property name could not be read as a string." - ); - return new TokensIssueRequestTenantScopeItemOne(stringValue); - } - - public override void WriteAsPropertyName( - Utf8JsonWriter writer, - TokensIssueRequestTenantScopeItemOne value, - JsonSerializerOptions options - ) - { - writer.WritePropertyName(value.Value); - } - } - - /// - /// Constant strings for enum values - /// - [Serializable] - public static class Values - { - public const string DocsCreate = "docs.create"; - - public const string DocsRead = "docs.read"; - - public const string DocsDelete = "docs.delete"; - - public const string TokensIssueDoc = "tokens.issue-doc"; - - public const string TokensRevoke = "tokens.revoke"; - - public const string SharesManage = "shares.manage"; - } -}