Skip to content

Commit 9586620

Browse files
committed
Tokens will refresh and retry after 401, methods for jobs, projects, releases, versions, paths, some refactoring and naming cleanup, new tests
1 parent 14ebe02 commit 9586620

32 files changed

+660
-37
lines changed

Folder.DotSettings.user

-5
This file was deleted.

cloudcms-csharp-driver.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<RootNamespace>CloudCMS</RootNamespace>
77

88
<PackageId>cloudcms</PackageId>
9-
<PackageVersion>1.1.5</PackageVersion>
9+
<PackageVersion>1.1.6</PackageVersion>
1010
<Title>CloudCMS Driver</Title>
1111
<Description>C# .NET driver for CloudCMS</Description>
1212
<Summary>C# .NET driver for CloudCMS</Summary>

src/CloudCMSDriver.cs

+44-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Net.Http.Headers;
77
using System.Threading.Tasks;
88
using System.Collections.Generic;
9+
using System.Net;
910
using Newtonsoft.Json;
1011
using Newtonsoft.Json.Linq;
1112
using CloudCMS;
@@ -105,12 +106,24 @@ public async Task<JObject> PostAsync(string uri, IDictionary<string, string> que
105106
return await RequestAsync(uri, method, queryParams, body);
106107
}
107108

109+
public Task<JObject> PostAsync(string uri, IDictionary<string, string> queryParams, JObject body)
110+
{
111+
HttpContent content = new StringContent(body.ToString());
112+
return PostAsync(uri, queryParams, content);
113+
}
114+
108115
public async Task<JObject> PutAsync(string uri, IDictionary<string, string> queryParams = null, HttpContent body = null)
109116
{
110117
HttpMethod method = HttpMethod.Put;
111118
return await RequestAsync(uri, method, queryParams, body);
112119
}
113120

121+
public Task<JObject> PutAsync(string uri, IDictionary<string, string> queryParams, JObject body)
122+
{
123+
HttpContent content = new StringContent(body.ToString());
124+
return PutAsync(uri, queryParams, content);
125+
}
126+
114127
public async Task<JObject> DeleteAsync(string uri, IDictionary<string, string> queryParams = null)
115128
{
116129
HttpMethod method = HttpMethod.Delete;
@@ -148,6 +161,14 @@ public async Task UploadAsync(string uri, IDictionary<string, string> paramMap,
148161
HttpContent content = GenerateUploadContent(payloads);
149162
await _requestAsync(uri, HttpMethod.Post, paramMap, content);
150163
}
164+
165+
public async Task<IPlatform> ReadCurrentPlatform()
166+
{
167+
string uri = "/";
168+
JObject response = await GetAsync(uri);
169+
IPlatform result = new Platform(this, response);
170+
return result;
171+
}
151172

152173
private HttpContent GenerateUploadContent(byte[] bytes, string mimetype)
153174
{
@@ -179,7 +200,13 @@ public async Task<JObject> RequestAsync(string uri, HttpMethod method, IDictiona
179200
{
180201
HttpResponseMessage response = await _requestAsync(uri, method, queryParams, body);
181202
string responseString = await response.Content.ReadAsStringAsync();
182-
return JObject.Parse(responseString);
203+
JObject result = JObject.Parse(responseString);
204+
205+
if (result.ContainsKey("error"))
206+
{
207+
throw new CloudCMSException("whoa");
208+
}
209+
return result;
183210
}
184211

185212
public async Task<string> RequestStringAsync(string uri, HttpMethod method, IDictionary<string, string> queryParams = null, HttpContent body = null)
@@ -210,6 +237,17 @@ private async Task<HttpResponseMessage> _requestAsync(string uri, HttpMethod met
210237
client.DefaultRequestHeaders.Authorization = auth;
211238

212239
HttpResponseMessage response = await client.SendAsync(request);
240+
if (response.StatusCode == HttpStatusCode.Unauthorized)
241+
{
242+
// Refresh and retry
243+
await RefreshTokenAsync();
244+
auth = new AuthenticationHeaderValue(token.token_type, token.access_token);
245+
client.DefaultRequestHeaders.Authorization = auth;
246+
247+
request = new HttpRequestMessage(method, url);
248+
response = await client.SendAsync(request);
249+
}
250+
213251
if (!response.IsSuccessStatusCode)
214252
{
215253
string responseString = await response.Content.ReadAsStringAsync();
@@ -231,6 +269,11 @@ private string BuildUrl(string uri, IDictionary<string, string> queryParams)
231269
query["full"] = "true";
232270
}
233271

272+
if (query["metadata"] == null)
273+
{
274+
query["metadata"] = "true";
275+
}
276+
234277
// Add all params to query string
235278
if (queryParams != null)
236279
{

src/ICloudCMSDriver.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ public interface ICloudCMSDriver
1212
Task<string> RequestStringAsync(string uri, HttpMethod method, IDictionary<string, string> queryParams = null, HttpContent body = null);
1313
Task<JObject> GetAsync(string uri, IDictionary<string, string> queryParams = null);
1414
Task<JObject> PostAsync(string uri, IDictionary<string, string> queryParams = null, HttpContent body = null);
15+
Task<JObject> PostAsync(string uri, IDictionary<string, string> queryParams, JObject body);
1516
Task<JObject> PutAsync(string uri, IDictionary<string, string> queryParams = null, HttpContent body = null);
17+
Task<JObject> PutAsync(string uri, IDictionary<string, string> queryParams, JObject body);
1618
Task<JObject> DeleteAsync(string uri, IDictionary<string, string> queryParams = null);
1719
Task<Stream> DownloadAsync(string uri);
1820
Task<byte[]> DownloadBytesAsync(string uri);
1921
Task UploadAsync(string uri, byte[] bytes, string mimetype, IDictionary<string, string> paramMap = null);
2022
Task UploadAsync(string uri, Stream stream, string mimetype, IDictionary<string, string> paramMap = null);
2123
Task UploadAsync(string uri, IDictionary<string, string> paramMap, IDictionary<string, AttachmentContent> payloads);
22-
24+
25+
Task<IPlatform> ReadCurrentPlatform();
2326
}
2427
}

src/branches/Branch.cs

+14-2
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public async Task<INode> RootNodeAsync()
212212
return (INode) await ReadNodeAsync("root");
213213
}
214214

215-
public async Task<JObject> GraphqlQuery(string query, string operationName = null, IDictionary<string, string> variables = null)
215+
public async Task<JObject> GraphqlQueryAsync(string query, string operationName = null, IDictionary<string, string> variables = null)
216216
{
217217
string uri = this.URI + "/graphql";
218218

@@ -236,10 +236,22 @@ public async Task<JObject> GraphqlQuery(string query, string operationName = nul
236236
return response;
237237
}
238238

239-
public Task<string> GraphqlSchema()
239+
public Task<string> GraphqlSchemaAsync()
240240
{
241241
string uri = this.URI + "/graphql/schema";
242242
return Driver.RequestStringAsync(uri, HttpMethod.Get);
243243
}
244+
245+
public async Task<IJob> StartResetAsync(string changesetId)
246+
{
247+
string uri = URI + "/reset/start";
248+
IDictionary<string, string> queryParams = new Dictionary<string, string>();
249+
queryParams.Add("id", changesetId);
250+
251+
JObject response = await Driver.PostAsync(uri, queryParams, new JObject());
252+
string jobId = response.GetValue("_doc").ToString();
253+
254+
return await Platform.ReadJobAsync(jobId);
255+
}
244256
}
245257
}

src/branches/IBranch.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ public interface IBranch : IRepositoryDocument
2323

2424
Task<INode> RootNodeAsync();
2525

26-
Task<JObject> GraphqlQuery(string query, string operationName=null, IDictionary<string, string> variables=null);
26+
Task<JObject> GraphqlQueryAsync(string query, string operationName=null, IDictionary<string, string> variables=null);
2727

28-
Task<string> GraphqlSchema();
28+
Task<string> GraphqlSchemaAsync();
29+
30+
Task<IJob> StartResetAsync(string changesetId);
2931
}
3032
}

src/documents/AbstractDocument.cs

-3
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,5 @@ public async Task UpdateAsync()
3737
HttpContent content = new StringContent(Data.ToString());
3838
await Driver.PutAsync(URI, body: content);
3939
}
40-
41-
public abstract string TypeId { get; }
42-
public abstract Reference Ref { get; }
4340
}
4441
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Newtonsoft.Json.Linq;
2+
3+
namespace CloudCMS
4+
{
5+
public abstract class AbstractPlatformDocument : AbstractDocument, IPlatformDocument
6+
{
7+
public IPlatform Platform { get; }
8+
9+
protected AbstractPlatformDocument(IPlatform platform, JObject obj) : base(platform.Driver, obj)
10+
{
11+
Platform = platform;
12+
}
13+
14+
public abstract Reference Ref { get; }
15+
16+
public abstract string TypeId { get; }
17+
}
18+
}

src/documents/IDocument.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace CloudCMS
55
{
6-
public interface IDocument : ITypedID, IReferenceable
6+
public interface IDocument
77
{
88
string Id { get; set; }
99

src/documents/IPlatformDocument.cs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace CloudCMS
2+
{
3+
public interface IPlatformDocument : IDocument, IReferenceable, ITypedID
4+
{
5+
IPlatform Platform { get; }
6+
}
7+
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Collections.Generic;
2+
3+
namespace CloudCMS
4+
{
5+
public static class DictionaryExtensions
6+
{
7+
public static void AddAll<K, V>(this IDictionary<K, V> first, IDictionary<K, V> second)
8+
{
9+
if (second != null)
10+
{
11+
foreach (KeyValuePair<K, V> item in second) {
12+
first[item.Key] = item.Value;
13+
}
14+
}
15+
16+
}
17+
}
18+
}

src/jobs/IJob.cs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Newtonsoft.Json.Linq;
4+
5+
namespace CloudCMS
6+
{
7+
public interface IJob : IDocument
8+
{
9+
string Type { get; }
10+
string State { get; }
11+
Task WaitForCompletion();
12+
Task KillAsync();
13+
14+
}
15+
}

src/jobs/Job.cs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Threading.Tasks;
2+
using Newtonsoft.Json.Linq;
3+
4+
namespace CloudCMS
5+
{
6+
public class Job : AbstractDocument, IJob
7+
{
8+
public Job(ICloudCMSDriver driver, JObject data) : base(driver, data)
9+
{
10+
11+
}
12+
13+
public string Type => Data.GetValue("type").ToString();
14+
public string State => Data.GetValue("state").ToString();
15+
16+
public async Task WaitForCompletion()
17+
{
18+
// Use with caution
19+
while (true)
20+
{
21+
await ReloadAsync();
22+
if ("FINISHED".Equals(State))
23+
{
24+
return;
25+
}
26+
else if ("ERROR".Equals(State))
27+
{
28+
throw new CloudCMSException("Job failed: " + Id);
29+
}
30+
else
31+
{
32+
await Task.Delay(1000);
33+
}
34+
}
35+
}
36+
37+
public async Task KillAsync()
38+
{
39+
string uri = URI + "/kill";
40+
await Driver.PostAsync(uri);
41+
}
42+
43+
public override string URI => "/jobs/" + Id;
44+
}
45+
}

src/nodes/BaseNode.cs

+56
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,62 @@ public async Task RemoveFeatureAsync(string featureId)
118118
await ReloadAsync();
119119
}
120120

121+
public async Task<IBaseNode> ReadVersionAsync(string changesetId, JObject options = null)
122+
{
123+
string uri = URI + "/versions/" + changesetId;
124+
125+
IDictionary<string, string> queryParams = null;
126+
if (options != null)
127+
{
128+
queryParams = options.ToObject<Dictionary<string, string>>();
129+
}
130+
131+
JObject response = await Driver.GetAsync(uri, queryParams);
132+
IBaseNode node = NodeUtil.Node(response, Branch);
133+
134+
return node;
135+
}
136+
137+
public async Task<List<IBaseNode>> ListVersionsAsync(JObject options = null, JObject pagination = null)
138+
{
139+
string uri = URI + "/versions/";
140+
141+
IDictionary<string, string> queryParams = new Dictionary<string, string>();
142+
if (options != null)
143+
{
144+
queryParams.AddAll(options.ToObject<Dictionary<string, string>>());
145+
}
146+
147+
if (pagination != null)
148+
{
149+
queryParams.AddAll(pagination.ToObject<Dictionary<string, string>>());
150+
}
151+
152+
JObject response = await Driver.GetAsync(uri, queryParams);
153+
JArray nodeArray = (JArray) response.SelectToken("rows");
154+
List<IBaseNode> nodes = NodeUtil.NodeList(nodeArray, Branch);
155+
156+
return nodes;
157+
}
158+
159+
public async Task<IBaseNode> RestoreVersionAsync(string changesetId)
160+
{
161+
string uri = URI + "/versions/" + changesetId + "/restore";
162+
JObject response = await Driver.PostAsync(uri, new Dictionary<string, string>(), new JObject());
163+
IBaseNode node = NodeUtil.Node(response, Branch);
164+
165+
return node;
166+
}
167+
168+
public async Task ChangeQNameAsync(QName newQName)
169+
{
170+
string uri = URI + "/change_qname";
171+
IDictionary<string, string> queryParams = new Dictionary<string, string>();
172+
queryParams.Add("qname", newQName.ToString());
173+
174+
await Driver.PostAsync(uri, queryParams, new JObject());
175+
}
176+
121177
public string GetString(string field)
122178
{
123179
return this.Data[field] != null ? (string) this.Data[field] : null;

src/nodes/IBaseNode.cs

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ public interface IBaseNode : IRepositoryDocument, IAttachable
2222
bool HasFeature(string featureId);
2323
Task AddFeatureAsync(string featureId, JObject featureConfig);
2424
Task RemoveFeatureAsync(string featureId);
25+
26+
// Versions
27+
Task<IBaseNode> ReadVersionAsync(string changesetId, JObject options = null);
28+
Task<List<IBaseNode>> ListVersionsAsync(JObject options = null, JObject pagination = null);
29+
Task<IBaseNode> RestoreVersionAsync(string changesetId);
30+
31+
Task ChangeQNameAsync(QName newQName);
2532

2633

2734
string GetString(string field);

src/nodes/INode.cs

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public interface INode : IBaseNode
3737
Task<List<IBaseNode>> ListChildrenAsync(JObject pagination=null);
3838
Task<List<IBaseNode>> ListRelativesAsync(QName type, Direction direction, JObject pagination=null);
3939
Task<List<IBaseNode>> QueryRelativesAsync(QName type, Direction direction, JObject query, JObject pagination=null);
40+
41+
// Paths
42+
43+
Task<string> ResolvePathAsync();
44+
Task<JObject> ResolvePathsAsync();
4045

4146
// Traverse
4247
Task<TraversalResults> TraverseAsync(JObject traverse);

0 commit comments

Comments
 (0)