+
+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.
+
+
+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.
+
+
+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`).
+
-`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.
-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.
-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.
-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 @@
enable12enable
- 3.0.0-next.17
+ 3.0.0-next.183.0.0.03.0.0.0README.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