diff --git a/PlanGrid.Api.Net45/Properties/AssemblyInfo.cs b/PlanGrid.Api.Net45/Properties/AssemblyInfo.cs
index 3bf3066..e19e0f0 100644
--- a/PlanGrid.Api.Net45/Properties/AssemblyInfo.cs
+++ b/PlanGrid.Api.Net45/Properties/AssemblyInfo.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System.Reflection;
@@ -13,7 +13,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("PlanGrid, Inc.")]
[assembly: AssemblyProduct("PlanGrid.Api")]
-[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/PlanGrid.Api.Tests/AttachmentTests.cs b/PlanGrid.Api.Tests/AttachmentTests.cs
new file mode 100644
index 0000000..8f089d6
--- /dev/null
+++ b/PlanGrid.Api.Tests/AttachmentTests.cs
@@ -0,0 +1,74 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace PlanGrid.Api.Tests
+{
+ [TestFixture]
+ public class AttachmentTests
+ {
+ [Test]
+ public async Task UploadAttachment()
+ {
+ IPlanGridApi client = PlanGridClient.Create();
+ AttachmentUploadRequest request = await client.CreateAttachmentUploadRequest(TestData.Project2Uid, new AttachmentUpload
+ {
+ ContentType = AttachmentUpload.Pdf,
+ Name = "test name",
+ Folder = "test folder"
+ });
+
+ Stream payload = typeof(AttachmentTests).Assembly.GetManifestResourceStream("PlanGrid.Api.Tests.TestData.Sample.pdf");
+ Attachment attachment = await client.Upload(request, payload);
+
+ Assert.AreEqual("test name", attachment.Name);
+ Assert.AreEqual("test folder", attachment.Folder);
+ Assert.AreEqual(TestData.ApiTestsUserUid, attachment.CreatedBy.Uid);
+ Assert.AreNotEqual(attachment.CreatedAt, default(DateTime));
+ Assert.AreEqual(request.Uid, attachment.Uid);
+
+ using (var downloader = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, AllowAutoRedirect = true }))
+ {
+ Stream returnedPayload = await downloader.GetStreamAsync(attachment.Url);
+ payload = typeof(AttachmentTests).Assembly.GetManifestResourceStream("PlanGrid.Api.Tests.TestData.Sample.pdf");
+ var payloadBytes = new MemoryStream();
+ await payload.CopyToAsync(payloadBytes);
+ var returnedBytes = new MemoryStream();
+ await returnedPayload.CopyToAsync(returnedBytes);
+ Assert.IsTrue(payloadBytes.ToArray().SequenceEqual(returnedBytes.ToArray()));
+ }
+ }
+
+ [Test]
+ public async Task UploadPdfAttachment()
+ {
+ IPlanGridApi client = PlanGridClient.Create();
+ Stream payload = typeof(AttachmentTests).Assembly.GetManifestResourceStream("PlanGrid.Api.Tests.TestData.Sample.pdf");
+ Attachment attachment = await client.UploadPdfAttachment(TestData.Project2Uid, "test name", payload, "test folder");
+
+ Assert.AreEqual("test name", attachment.Name);
+ Assert.AreEqual("test folder", attachment.Folder);
+ Assert.AreEqual(TestData.ApiTestsUserUid, attachment.CreatedBy.Uid);
+ Assert.AreNotEqual(attachment.CreatedAt, default(DateTime));
+
+ using (var downloader = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, AllowAutoRedirect = true }))
+ {
+ Stream returnedPayload = await downloader.GetStreamAsync(attachment.Url);
+ payload = typeof(AttachmentTests).Assembly.GetManifestResourceStream("PlanGrid.Api.Tests.TestData.Sample.pdf");
+ var payloadBytes = new MemoryStream();
+ await payload.CopyToAsync(payloadBytes);
+ var returnedBytes = new MemoryStream();
+ await returnedPayload.CopyToAsync(returnedBytes);
+ Assert.IsTrue(payloadBytes.ToArray().SequenceEqual(returnedBytes.ToArray()));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/PlanGrid.Api.Tests/IssuesTests.cs b/PlanGrid.Api.Tests/IssuesTests.cs
index 9b08204..3ca290a 100644
--- a/PlanGrid.Api.Tests/IssuesTests.cs
+++ b/PlanGrid.Api.Tests/IssuesTests.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
@@ -21,7 +21,7 @@ public async Task GetIssues()
Issue issue = page.Data[0];
Assert.IsFalse(issue.IsDeleted);
Assert.AreEqual(TestData.ApiTestsUserEmail, issue.AssignedTo.Single().Email);
- Assert.AreEqual(DateTime.Parse("11/16/2015 10:13:49.845"), issue.CreatedAt);
+ Assert.AreEqual(DateTime.Parse("11/16/2015 18:13:49"), issue.CreatedAt);
Assert.AreEqual(TestData.ApiTestsUserEmail, issue.CreatedBy.Email);
Assert.AreEqual("Test Description", issue.Description);
Assert.AreEqual(1, issue.Number);
@@ -29,7 +29,7 @@ public async Task GetIssues()
Assert.AreEqual(IssueStatus.Open, issue.Status);
Assert.AreEqual(TestData.ApiTestsUserEmail, issue.UpdatedBy.Email);
Assert.IsFalse(string.IsNullOrEmpty(issue.Uid));
- Assert.AreEqual(DateTime.Parse("11/16/2015 10:13:50.830"), issue.UpdatedAt);
+ Assert.AreEqual(DateTime.Parse("11/16/2015 18:13:50"), issue.UpdatedAt);
Assert.IsFalse(issue.IsDeleted);
Assert.AreEqual("#FF0000", issue.CurrentAnnotation.Color);
Assert.IsFalse(issue.CurrentAnnotation.IsDeleted);
@@ -44,7 +44,7 @@ public async Task GetIssues()
Page photos = await client.Resolve(issue.Photos);
Assert.AreEqual(1, photos.TotalCount);
Assert.AreEqual(1, issue.Photos.TotalCount);
- Assert.AreEqual(DateTime.Parse("11/16/2015 10:32:43.584"), photos.Data[0].CreatedAt);
+ Assert.AreEqual(DateTime.Parse("11/16/2015 18:32:43"), photos.Data[0].CreatedAt);
Assert.AreEqual(TestData.ApiTestsUserEmail, photos.Data[0].CreatedBy.Email);
Assert.AreEqual("Galaxy", photos.Data[0].Title);
Assert.AreEqual(TestData.PhotoUrl, photos.Data[0].Url);
@@ -54,7 +54,7 @@ public async Task GetIssues()
Page comments = await client.Resolve(issue.Comments);
Assert.AreEqual(1, comments.TotalCount);
Assert.AreEqual(1, issue.Comments.TotalCount);
- Assert.AreEqual(DateTime.Parse("11/16/2015 10:35:21.698"), comments.Data[0].CreatedAt);
+ Assert.AreEqual(DateTime.Parse("11/16/2015 18:35:21.698"), comments.Data[0].CreatedAt);
Assert.AreEqual(TestData.ApiTestsUserEmail, comments.Data[0].CreatedBy.Email);
Assert.AreEqual("Test Comment", comments.Data[0].Text);
Assert.IsFalse(string.IsNullOrEmpty(comments.Data[0].Uid));
@@ -66,7 +66,7 @@ public async Task GetIssueComments()
IPlanGridApi client = PlanGridClient.Create();
Page comments = await client.GetIssueComments(TestData.Project1Uid, TestData.Project1Issue1Uid);
Assert.AreEqual(1, comments.TotalCount);
- Assert.AreEqual(DateTime.Parse("11/16/2015 10:35:21.698"), comments.Data[0].CreatedAt);
+ Assert.AreEqual(DateTime.Parse("11/16/2015 18:35:21.698"), comments.Data[0].CreatedAt);
Assert.AreEqual(TestData.ApiTestsUserEmail, comments.Data[0].CreatedBy.Email);
Assert.AreEqual("Test Comment", comments.Data[0].Text);
Assert.IsFalse(string.IsNullOrEmpty(comments.Data[0].Uid));
@@ -78,7 +78,7 @@ public async Task GetIssuePhotos()
IPlanGridApi client = PlanGridClient.Create();
Page photos = await client.GetIssuePhotos(TestData.Project1Uid, TestData.Project1Issue1Uid);
Assert.AreEqual(1, photos.TotalCount);
- Assert.AreEqual(DateTime.Parse("11/16/2015 10:32:43.584"), photos.Data[0].CreatedAt);
+ Assert.AreEqual(DateTime.Parse("11/16/2015 18:32:43"), photos.Data[0].CreatedAt);
Assert.AreEqual(TestData.ApiTestsUserEmail, photos.Data[0].CreatedBy.Email);
Assert.AreEqual("Galaxy", photos.Data[0].Title);
Assert.AreEqual(TestData.PhotoUrl, photos.Data[0].Url);
diff --git a/PlanGrid.Api.Tests/PlanGrid.Api.Tests.csproj b/PlanGrid.Api.Tests/PlanGrid.Api.Tests.csproj
index 5a37a99..6bdcb51 100644
--- a/PlanGrid.Api.Tests/PlanGrid.Api.Tests.csproj
+++ b/PlanGrid.Api.Tests/PlanGrid.Api.Tests.csproj
@@ -44,6 +44,7 @@
+
@@ -53,8 +54,11 @@
-
+
+ Designer
+
+
diff --git a/PlanGrid.Api.Tests/RfisTests.cs b/PlanGrid.Api.Tests/RfisTests.cs
index 2482911..ca0f8cd 100644
--- a/PlanGrid.Api.Tests/RfisTests.cs
+++ b/PlanGrid.Api.Tests/RfisTests.cs
@@ -1,8 +1,10 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
+using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
@@ -23,10 +25,10 @@ public async Task GetRfis()
Assert.AreEqual("Test Rfi Question", rfi.Question);
Assert.AreEqual("Test Rfi", rfi.Title);
Assert.AreEqual(1, rfi.Number);
- Assert.AreEqual(DateTime.Parse("11/18/2015 11:30:21.000"), rfi.SentDate);
- Assert.AreEqual(DateTime.Parse("11/19/2015 11:30:13.000"), rfi.DueDate);
- Assert.AreEqual(DateTime.Parse("11/17/2015 12:06:47.912"), rfi.UpdatedAt);
- Assert.AreEqual(DateTime.Parse("11/16/2015 13:48:26.641"), rfi.CreatedAt);
+ Assert.AreEqual(DateTime.Parse("11/18/2015 19:30:21.000"), rfi.SentDate);
+ Assert.AreEqual(DateTime.Parse("11/19/2015 19:30:13.000"), rfi.DueDate);
+ Assert.AreEqual(DateTime.Parse("11/17/2015 20:06:47.912"), rfi.UpdatedAt);
+ Assert.AreEqual(DateTime.Parse("11/16/2015 21:48:26.641"), rfi.CreatedAt);
Assert.AreEqual("kirk+apitests@plangrid.com", rfi.AssignedTo[0].Email);
Assert.AreEqual("kirk+apitests@plangrid.com", rfi.UpdatedBy.Email);
Assert.AreEqual("kirk+apitests@plangrid.com", rfi.CreatedBy.Email);
@@ -187,5 +189,63 @@ public async Task UpdateRfi()
Assert.AreEqual(TestData.ApiTestsUserUid, rfi.UpdatedBy.Uid);
Assert.AreNotEqual(rfi.UpdatedAt, default(DateTime));
}
+
+ [Test]
+ public async Task ReferenceAttachment()
+ {
+ IPlanGridApi client = PlanGridClient.Create();
+ var rfiInsert = new RfiUpsert
+ {
+ Question = "test question",
+ Answer = "test answer",
+ AssignedTo = new[] { TestData.ApiTestsUserUid },
+ DueDate = new DateTime(2020, 1, 1),
+ IsLocked = false,
+ SentDate = new DateTime(2019, 1, 1),
+ StatusUid = TestData.Project2DraftRfiStatusUid,
+ Title = "test title"
+ };
+ Rfi rfi = await client.CreateRfi(TestData.Project2Uid, rfiInsert);
+
+ AttachmentUploadRequest request = await client.CreateAttachmentUploadRequest(TestData.Project2Uid, new AttachmentUpload
+ {
+ ContentType = AttachmentUpload.Pdf,
+ Name = "test name",
+ Folder = "test folder"
+ });
+
+ Stream payload = typeof(AttachmentTests).Assembly.GetManifestResourceStream("PlanGrid.Api.Tests.TestData.Sample.pdf");
+ Attachment attachment = await client.Upload(request, payload);
+
+ await client.ReferenceAttachmentFromRfi(TestData.Project2Uid, rfi.Uid, new AttachmentReference { AttachmentUid = attachment.Uid });
+
+ Page attachments = await client.GetRfiAttachments(TestData.Project2Uid, rfi.Uid);
+ Attachment rfiAttachment = attachments.Data.Single();
+ Assert.AreEqual(attachment.Uid, rfiAttachment.Uid);
+ }
+
+ [Test]
+ public async Task ReferencePhoto()
+ {
+ IPlanGridApi client = PlanGridClient.Create();
+ var rfiInsert = new RfiUpsert
+ {
+ Question = "test question",
+ Answer = "test answer",
+ AssignedTo = new[] { TestData.ApiTestsUserUid },
+ DueDate = new DateTime(2020, 1, 1),
+ IsLocked = false,
+ SentDate = new DateTime(2019, 1, 1),
+ StatusUid = TestData.Project2DraftRfiStatusUid,
+ Title = "test title"
+ };
+ Rfi rfi = await client.CreateRfi(TestData.Project2Uid, rfiInsert);
+
+ await client.ReferencePhotoFromRfi(TestData.Project2Uid, rfi.Uid, new PhotoReference { PhotoUid = TestData.Project2PhotoUid });
+
+ Page photos = await client.GetRfiPhotos(TestData.Project2Uid, rfi.Uid);
+ Photo rfiPhoto = photos.Data.Single();
+ Assert.AreEqual(TestData.Project2PhotoUid, rfiPhoto.Uid);
+ }
}
}
\ No newline at end of file
diff --git a/PlanGrid.Api.Tests/RoleTests.cs b/PlanGrid.Api.Tests/RoleTests.cs
index 3e91313..e1e676d 100644
--- a/PlanGrid.Api.Tests/RoleTests.cs
+++ b/PlanGrid.Api.Tests/RoleTests.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System.Threading.Tasks;
diff --git a/PlanGrid.Api.Tests/TestData.cs b/PlanGrid.Api.Tests/TestData.cs
index 83f7394..45c7a45 100644
--- a/PlanGrid.Api.Tests/TestData.cs
+++ b/PlanGrid.Api.Tests/TestData.cs
@@ -1,6 +1,7 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
+
namespace PlanGrid.Api.Tests
{
public static class TestData
@@ -11,6 +12,7 @@ public static class TestData
public const string Project2Uid = "269ad633-0688-395e-5c30-cc685e0ce964";
public const string Project2DraftRfiStatusUid = "00a8b880";
public const string Project2OpenRfiStatusUid = "bcadf1c9";
+ public const string Project2PhotoUid = "6f976878-d243-c787-dfda-0290b7761968";
public const string PhotoUrl = "https://photo-assets-test.plangrid.com/5a16f6d9-8006-ea7d-12ee-76c778b7094f.jpg";
public const string ApiTestsUserEmail = "kirk+apitests@plangrid.com";
public const string ApiTestsUserUid = "5644e9acf0cb79476f1d48ee";
diff --git a/PlanGrid.Api.Tests/TestData/Sample.pdf b/PlanGrid.Api.Tests/TestData/Sample.pdf
new file mode 100644
index 0000000..2a7c699
Binary files /dev/null and b/PlanGrid.Api.Tests/TestData/Sample.pdf differ
diff --git a/PlanGrid.Api.Tests/UserTests.cs b/PlanGrid.Api.Tests/UserTests.cs
index f40bd8e..ca2c3c7 100644
--- a/PlanGrid.Api.Tests/UserTests.cs
+++ b/PlanGrid.Api.Tests/UserTests.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System.Threading.Tasks;
@@ -15,9 +15,9 @@ public async Task GetUsers()
{
IPlanGridApi api = PlanGridClient.Create();
Page users = await api.GetUsers(TestData.Project1Uid);
- Assert.AreEqual(2, users.Data.Length);
+ Assert.AreEqual(3, users.Data.Length);
- User user = users.Data[1];
+ User user = users.Data[2];
Assert.AreEqual(TestData.ApiTestsUserEmail, user.Email);
Assert.IsTrue(!string.IsNullOrEmpty(user.Uid));
diff --git a/PlanGrid.Api/AnnotationVisibility.cs b/PlanGrid.Api/AnnotationVisibility.cs
index aadb2ac..0b29cc4 100644
--- a/PlanGrid.Api/AnnotationVisibility.cs
+++ b/PlanGrid.Api/AnnotationVisibility.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System.Runtime.Serialization;
diff --git a/PlanGrid.Api/Attachment.cs b/PlanGrid.Api/Attachment.cs
index 653226b..1c444b6 100644
--- a/PlanGrid.Api/Attachment.cs
+++ b/PlanGrid.Api/Attachment.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/AttachmentReference.cs b/PlanGrid.Api/AttachmentReference.cs
new file mode 100644
index 0000000..93a9277
--- /dev/null
+++ b/PlanGrid.Api/AttachmentReference.cs
@@ -0,0 +1,10 @@
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class AttachmentReference
+ {
+ [JsonProperty("attachment_uid")]
+ public string AttachmentUid { get; set; }
+ }
+}
diff --git a/PlanGrid.Api/AttachmentUpload.cs b/PlanGrid.Api/AttachmentUpload.cs
new file mode 100644
index 0000000..31a661d
--- /dev/null
+++ b/PlanGrid.Api/AttachmentUpload.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class AttachmentUpload
+ {
+ public const string Pdf = "application/pdf";
+
+ [JsonProperty("content_type")]
+ public string ContentType { get; set; }
+
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("folder")]
+ public string Folder { get; set; }
+ }
+}
diff --git a/PlanGrid.Api/AttachmentUploadRequest.cs b/PlanGrid.Api/AttachmentUploadRequest.cs
new file mode 100644
index 0000000..4027e6a
--- /dev/null
+++ b/PlanGrid.Api/AttachmentUploadRequest.cs
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class AttachmentUploadRequest
+ {
+ [JsonProperty("webhook_url")]
+ public string WebhookUrl { get; set; }
+
+ [JsonProperty("uid")]
+ public string Uid { get; set; }
+
+ [JsonProperty("aws_post_form_arguments")]
+ public AwsPostFormArguments AwsPostFormArguments { get; set; }
+ }
+}
diff --git a/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs b/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs
index 0751f46..8768deb 100644
--- a/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs
+++ b/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/AwsPostFormArgument.cs b/PlanGrid.Api/AwsPostFormArgument.cs
new file mode 100644
index 0000000..4062203
--- /dev/null
+++ b/PlanGrid.Api/AwsPostFormArgument.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class AwsPostFormArgument
+ {
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("value")]
+ public string Value { get; set; }
+ }
+}
diff --git a/PlanGrid.Api/AwsPostFormArguments.cs b/PlanGrid.Api/AwsPostFormArguments.cs
new file mode 100644
index 0000000..e26b966
--- /dev/null
+++ b/PlanGrid.Api/AwsPostFormArguments.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class AwsPostFormArguments
+ {
+ [JsonProperty("action")]
+ public string Action { get; set; }
+
+ [JsonProperty("fields")]
+ public AwsPostFormArgument[] Fields { get; set; }
+ }
+}
diff --git a/PlanGrid.Api/CollectionReference.cs b/PlanGrid.Api/CollectionReference.cs
index 8b366c2..2f65681 100644
--- a/PlanGrid.Api/CollectionReference.cs
+++ b/PlanGrid.Api/CollectionReference.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/Comment.cs b/PlanGrid.Api/Comment.cs
index 2a0eb86..a056a34 100644
--- a/PlanGrid.Api/Comment.cs
+++ b/PlanGrid.Api/Comment.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/IMultipartContent.cs b/PlanGrid.Api/IMultipartContent.cs
new file mode 100644
index 0000000..36f84b0
--- /dev/null
+++ b/PlanGrid.Api/IMultipartContent.cs
@@ -0,0 +1,10 @@
+using System.Net.Http;
+
+namespace PlanGrid.Api
+{
+ public interface IMultipartContent
+ {
+ string Name { get; }
+ void CreateContent(MultipartFormDataContent multipart);
+ }
+}
diff --git a/PlanGrid.Api/IPlanGridApi.cs b/PlanGrid.Api/IPlanGridApi.cs
index 0566489..c2f4852 100644
--- a/PlanGrid.Api/IPlanGridApi.cs
+++ b/PlanGrid.Api/IPlanGridApi.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
@@ -69,5 +69,14 @@ public interface IPlanGridApi : IDisposable
[Patch("/projects/{projectUid}/rfis/{rfiUid}")]
Task UpdateRfi(string projectUid, string rfiUid, [Body]RfiUpsert rfi);
+
+ [Post("/projects/{projectUid}/attachments/uploads")]
+ Task CreateAttachmentUploadRequest(string projectUid, [Body]AttachmentUpload upload);
+
+ [Post("/projects/{projectUid}/rfis/{rfiUid}/attachments")]
+ Task ReferenceAttachmentFromRfi(string projectUid, string rfiUid, [Body]AttachmentReference attachmentReference);
+
+ [Post("/projects/{projectUid}/rfis/{rfiUid}/photos")]
+ Task ReferencePhotoFromRfi(string projectUid, string rfiUid, [Body]PhotoReference photoReference);
}
}
\ No newline at end of file
diff --git a/PlanGrid.Api/Issue.cs b/PlanGrid.Api/Issue.cs
index d5cdf3f..308a4dd 100644
--- a/PlanGrid.Api/Issue.cs
+++ b/PlanGrid.Api/Issue.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/IssueAnnotation.cs b/PlanGrid.Api/IssueAnnotation.cs
index 063f132..c25cfec 100644
--- a/PlanGrid.Api/IssueAnnotation.cs
+++ b/PlanGrid.Api/IssueAnnotation.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/IssueAnnotationSheet.cs b/PlanGrid.Api/IssueAnnotationSheet.cs
index b5de1a0..652aa72 100644
--- a/PlanGrid.Api/IssueAnnotationSheet.cs
+++ b/PlanGrid.Api/IssueAnnotationSheet.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/IssueStatus.cs b/PlanGrid.Api/IssueStatus.cs
index c8ea3eb..f186598 100644
--- a/PlanGrid.Api/IssueStatus.cs
+++ b/PlanGrid.Api/IssueStatus.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System.Runtime.Serialization;
diff --git a/PlanGrid.Api/MultipartUploadException.cs b/PlanGrid.Api/MultipartUploadException.cs
new file mode 100644
index 0000000..5a833fa
--- /dev/null
+++ b/PlanGrid.Api/MultipartUploadException.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+
+namespace PlanGrid.Api
+{
+ public class MultipartUploadException : Exception
+ {
+ public MultipartUploadException()
+ {
+ }
+
+ public MultipartUploadException(string message) : base(message)
+ {
+ }
+
+ public MultipartUploadException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/PlanGrid.Api/MultipartUploader.cs b/PlanGrid.Api/MultipartUploader.cs
new file mode 100644
index 0000000..6d13231
--- /dev/null
+++ b/PlanGrid.Api/MultipartUploader.cs
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace PlanGrid.Api
+{
+ public class MultipartUploader
+ {
+ public static async Task Upload(string url, CancellationToken cancellationToken, params IMultipartContent[] values)
+ {
+ using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, AllowAutoRedirect = true }))
+ {
+ string boundary = "----" + DateTime.Now.Ticks;
+
+ var content = new MultipartFormDataContent(boundary);
+ foreach (IMultipartContent item in values)
+ {
+ item.CreateContent(content);
+ }
+
+ HttpResponseMessage response = await client.PostAsync(new Uri(url), content, cancellationToken);
+ if ((int)response.StatusCode >= 400)
+ {
+ string message = await response.Content.ReadAsStringAsync();
+ throw new MultipartUploadException($"Error uploading attachment to S3: {message}");
+ }
+ return response;
+ }
+ }
+ }
+}
diff --git a/PlanGrid.Api/Page.cs b/PlanGrid.Api/Page.cs
index ef85f06..fcda052 100644
--- a/PlanGrid.Api/Page.cs
+++ b/PlanGrid.Api/Page.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/Photo.cs b/PlanGrid.Api/Photo.cs
index e70f5ca..3cd774d 100644
--- a/PlanGrid.Api/Photo.cs
+++ b/PlanGrid.Api/Photo.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/PhotoReference.cs b/PlanGrid.Api/PhotoReference.cs
new file mode 100644
index 0000000..4f7f831
--- /dev/null
+++ b/PlanGrid.Api/PhotoReference.cs
@@ -0,0 +1,10 @@
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class PhotoReference
+ {
+ [JsonProperty("photo_uid")]
+ public string PhotoUid { get; set; }
+ }
+}
diff --git a/PlanGrid.Api/PlanGrid.Api.projitems b/PlanGrid.Api/PlanGrid.Api.projitems
index 7e5e98b..3412b56 100644
--- a/PlanGrid.Api/PlanGrid.Api.projitems
+++ b/PlanGrid.Api/PlanGrid.Api.projitems
@@ -11,14 +11,23 @@
+
+
+
+
+
+
+
+
+
@@ -34,6 +43,8 @@
+
+
diff --git a/PlanGrid.Api/PlanGridApiExtensions.cs b/PlanGrid.Api/PlanGridApiExtensions.cs
index a226bd9..94c2869 100644
--- a/PlanGrid.Api/PlanGridApiExtensions.cs
+++ b/PlanGrid.Api/PlanGridApiExtensions.cs
@@ -1,8 +1,12 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
using System.Net.Http;
+using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Refit;
@@ -36,5 +40,33 @@ public static async Task> Resolve(this IPlanGridApi api, CollectionRe
var result = JsonConvert.DeserializeObject>(content, settings.JsonSerializerSettings);
return result;
}
+
+ public static Task UploadPdfAttachment(this IPlanGridApi api, string projectUid, string name, Stream payload, string folder = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return api.UploadAttachment(projectUid, AttachmentUpload.Pdf, name, payload, folder, cancellationToken);
+ }
+
+ public static async Task UploadAttachment(this IPlanGridApi api, string projectUid, string contentType, string name, Stream payload, string folder = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ AttachmentUploadRequest request = await api.CreateAttachmentUploadRequest(projectUid, new AttachmentUpload { ContentType = contentType, Name = name, Folder = folder });
+ return await api.Upload(request, payload, cancellationToken);
+ }
+
+ public static async Task Upload(this IPlanGridApi api, AttachmentUploadRequest uploadRequest, Stream payload, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var values = new List();
+ foreach (AwsPostFormArgument item in uploadRequest.AwsPostFormArguments.Fields)
+ {
+ values.Add(new StringMultipartContent(item.Name, item.Value));
+ }
+
+ var generatedApi = (AutoGeneratedIPlanGridApi)api;
+ RefitSettings settings = generatedApi.Settings;
+
+ values.Add(new StreamMultipartContent("file", "data", uploadRequest.AwsPostFormArguments.Fields.Single(x => x.Name == "Content-Type").Value, payload));
+ HttpResponseMessage response = await MultipartUploader.Upload(uploadRequest.AwsPostFormArguments.Action, cancellationToken, values.ToArray());
+ string responseText = await response.Content.ReadAsStringAsync();
+ return JsonConvert.DeserializeObject(responseText, settings.JsonSerializerSettings);
+ }
}
}
diff --git a/PlanGrid.Api/PlanGridClient.cs b/PlanGrid.Api/PlanGridClient.cs
index bb05fff..5f1de63 100644
--- a/PlanGrid.Api/PlanGridClient.cs
+++ b/PlanGrid.Api/PlanGridClient.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/PlanGridHttpHandler.cs b/PlanGrid.Api/PlanGridHttpHandler.cs
index 5c5901a..387508e 100644
--- a/PlanGrid.Api/PlanGridHttpHandler.cs
+++ b/PlanGrid.Api/PlanGridHttpHandler.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/Project.cs b/PlanGrid.Api/Project.cs
index aa017b9..f7ed709 100644
--- a/PlanGrid.Api/Project.cs
+++ b/PlanGrid.Api/Project.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/ProjectUpdate.cs b/PlanGrid.Api/ProjectUpdate.cs
index 16a4dd4..33dd158 100644
--- a/PlanGrid.Api/ProjectUpdate.cs
+++ b/PlanGrid.Api/ProjectUpdate.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/RecordReference.cs b/PlanGrid.Api/RecordReference.cs
index 87e9636..4a08ac0 100644
--- a/PlanGrid.Api/RecordReference.cs
+++ b/PlanGrid.Api/RecordReference.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/Rfi.cs b/PlanGrid.Api/Rfi.cs
index d2d1f9f..1908182 100644
--- a/PlanGrid.Api/Rfi.cs
+++ b/PlanGrid.Api/Rfi.cs
@@ -1,4 +1,8 @@
-using System;
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
using Newtonsoft.Json;
namespace PlanGrid.Api
diff --git a/PlanGrid.Api/RfiStatus.cs b/PlanGrid.Api/RfiStatus.cs
index 12b2370..bd3f75a 100644
--- a/PlanGrid.Api/RfiStatus.cs
+++ b/PlanGrid.Api/RfiStatus.cs
@@ -1,4 +1,8 @@
-using Newtonsoft.Json;
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
namespace PlanGrid.Api
{
diff --git a/PlanGrid.Api/RfiStatusUpdate.cs b/PlanGrid.Api/RfiStatusUpdate.cs
index 1eea9eb..ab94bda 100644
--- a/PlanGrid.Api/RfiStatusUpdate.cs
+++ b/PlanGrid.Api/RfiStatusUpdate.cs
@@ -1,6 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
using Newtonsoft.Json;
namespace PlanGrid.Api
diff --git a/PlanGrid.Api/RfiUpsert.cs b/PlanGrid.Api/RfiUpsert.cs
index 18c5ed9..d151c49 100644
--- a/PlanGrid.Api/RfiUpsert.cs
+++ b/PlanGrid.Api/RfiUpsert.cs
@@ -1,6 +1,8 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
using Newtonsoft.Json;
namespace PlanGrid.Api
@@ -11,7 +13,7 @@ public class RfiUpsert
public string StatusUid { get; set; }
[JsonProperty("locked")]
- public bool IsLocked { get; set; }
+ public bool? IsLocked { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
diff --git a/PlanGrid.Api/Role.cs b/PlanGrid.Api/Role.cs
index cfc08e5..8d9bacf 100644
--- a/PlanGrid.Api/Role.cs
+++ b/PlanGrid.Api/Role.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/Settings.cs b/PlanGrid.Api/Settings.cs
index c2e4d11..7d60c0c 100644
--- a/PlanGrid.Api/Settings.cs
+++ b/PlanGrid.Api/Settings.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System.Configuration;
diff --git a/PlanGrid.Api/Snapshot.cs b/PlanGrid.Api/Snapshot.cs
index 80b21fa..f600936 100644
--- a/PlanGrid.Api/Snapshot.cs
+++ b/PlanGrid.Api/Snapshot.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using System;
diff --git a/PlanGrid.Api/StreamMultipartContent.cs b/PlanGrid.Api/StreamMultipartContent.cs
new file mode 100644
index 0000000..b9e363f
--- /dev/null
+++ b/PlanGrid.Api/StreamMultipartContent.cs
@@ -0,0 +1,29 @@
+using System.IO;
+using System.Net.Http;
+using System.Net.Http.Headers;
+
+namespace PlanGrid.Api
+{
+ public class StreamMultipartContent : IMultipartContent
+ {
+ public string Name { get; }
+ public string FileName { get; }
+ public string ContentType { get; }
+ public Stream Content { get; }
+
+ public StreamMultipartContent(string name, string fileName, string contentType, Stream content)
+ {
+ Name = name;
+ FileName = fileName;
+ ContentType = contentType;
+ Content = content;
+ }
+
+ public void CreateContent(MultipartFormDataContent multipart)
+ {
+ var content = new StreamContent(Content);
+ content.Headers.ContentType = MediaTypeHeaderValue.Parse(ContentType);
+ multipart.Add(content, Name, FileName);
+ }
+ }
+}
diff --git a/PlanGrid.Api/StringMultipartContent.cs b/PlanGrid.Api/StringMultipartContent.cs
new file mode 100644
index 0000000..f71552a
--- /dev/null
+++ b/PlanGrid.Api/StringMultipartContent.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System.Net.Http;
+using System.Net.Http.Headers;
+
+namespace PlanGrid.Api
+{
+ public class StringMultipartContent : IMultipartContent
+ {
+ public string Name { get; }
+ public string Value { get; }
+
+ public StringMultipartContent(string name, string value)
+ {
+ Name = name;
+ Value = value;
+ }
+
+ public void CreateContent(MultipartFormDataContent multipart)
+ {
+ var content = new StringContent(Value);
+ content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain");
+ multipart.Add(content, Name);
+ }
+ }
+}
diff --git a/PlanGrid.Api/User.cs b/PlanGrid.Api/User.cs
index 7e967d8..cc11058 100644
--- a/PlanGrid.Api/User.cs
+++ b/PlanGrid.Api/User.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/UserInvitation.cs b/PlanGrid.Api/UserInvitation.cs
index 913097e..48b81c5 100644
--- a/PlanGrid.Api/UserInvitation.cs
+++ b/PlanGrid.Api/UserInvitation.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;
diff --git a/PlanGrid.Api/UserReference.cs b/PlanGrid.Api/UserReference.cs
index f459a56..f7d05bf 100644
--- a/PlanGrid.Api/UserReference.cs
+++ b/PlanGrid.Api/UserReference.cs
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015 PlanGrid, Inc. All rights reserved.
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
//
using Newtonsoft.Json;