diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api.NetCore.csproj b/PlanGrid.Api.NetCore/PlanGrid.Api.NetCore.csproj
new file mode 100644
index 0000000..895c9e0
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api.NetCore.csproj
@@ -0,0 +1,29 @@
+
+
+ net8.0
+ Library
+ PlanGrid.Api
+ PlanGrid.Api
+ false
+ PlanGrid.Api
+ PlanGrid, Inc.
+ PlanGrid.Api.Core
+ Copyright © 2016
+ 1.0.0.0
+ 1.0.0.0
+ True
+ Plangrid.Api.Core
+ PlanGrid.Api.Core
+ C:\Users\bilalyas\Downloads\plangrid-api-net-master
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/AnnotationVisibility.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/AnnotationVisibility.cs
new file mode 100644
index 0000000..0b29cc4
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/AnnotationVisibility.cs
@@ -0,0 +1,19 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System.Runtime.Serialization;
+
+namespace PlanGrid.Api
+{
+ public enum AnnotationVisibility
+ {
+ None,
+
+ [EnumMember(Value = "user")]
+ User,
+
+ [EnumMember(Value = "master")]
+ Master
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/Attachment.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/Attachment.cs
new file mode 100644
index 0000000..1c444b6
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/Attachment.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class Attachment
+ {
+ [JsonProperty("uid")]
+ public string Uid { get; set; }
+
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("folder")]
+ public string Folder { get; set; }
+
+ [JsonProperty("url")]
+ public string Url { get; set; }
+
+ [JsonProperty("created_at")]
+ public DateTime CreatedAt { get; set; }
+
+ [JsonProperty("created_by")]
+ public UserReference CreatedBy { get; set; }
+
+ [JsonProperty("deleted")]
+ public bool IsDeleted { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/AttachmentReference.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/AttachmentReference.cs
new file mode 100644
index 0000000..93a9277
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/AttachmentUpdate.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/AttachmentUpdate.cs
new file mode 100644
index 0000000..98bf623
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/AttachmentUpdate.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class AttachmentUpdate
+ {
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("folder")]
+ public string Folder { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/AttachmentUpload.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/AttachmentUpload.cs
new file mode 100644
index 0000000..31a661d
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs
new file mode 100644
index 0000000..461873f
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using Refit;
+
+namespace PlanGrid.Api
+{
+ public partial class AutoGeneratedIPlanGridApi
+ {
+ public string ApiKey { get; private set; }
+ public RefitSettings Settings { get; private set; }
+ public string Version { get; private set; }
+ public int? MaxRetries { get; private set; }
+
+ public void Initialize(string apiKey, RefitSettings settings, string version, int? maxRetries)
+ {
+ ApiKey = apiKey;
+ Settings = settings;
+ Version = version;
+ MaxRetries = maxRetries;
+
+ foreach (KeyValuePair> methodImpl in methodImpls.ToArray())
+ {
+ methodImpls[methodImpl.Key] = (client, arguments) => methodImpl.Value(client, FixArguments(arguments));
+ }
+ }
+
+ private object[] FixArguments(object[] arguments)
+ {
+ for (int i = 0; i < arguments.Length; i++)
+ {
+ if (arguments[i] is bool)
+ {
+ arguments[i] = (bool)arguments[i] ? "true" : "false";
+ }
+ }
+ return arguments;
+ }
+
+ public void Dispose()
+ {
+ Client.Dispose();
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/AwsPostFormArgument.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/AwsPostFormArgument.cs
new file mode 100644
index 0000000..4062203
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/AwsPostFormArguments.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/AwsPostFormArguments.cs
new file mode 100644
index 0000000..e26b966
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/CollectionReference.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/CollectionReference.cs
new file mode 100644
index 0000000..2f65681
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/CollectionReference.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class CollectionReference
+ {
+ [JsonProperty("total_count")]
+ public int TotalCount { get; set; }
+
+ [JsonProperty("url")]
+ public string Url { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/Comment.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/Comment.cs
new file mode 100644
index 0000000..1570c69
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/Comment.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class Comment
+ {
+ [JsonProperty("uid")]
+ public string Uid { get; set; }
+
+ [JsonProperty("text")]
+ public string Text { get; set; }
+
+ [JsonProperty("created_at")]
+ public DateTime CreatedAt { get; set; }
+
+ [JsonProperty("created_by")]
+ public UserReference CreatedBy { get; set; }
+
+ [JsonProperty("record_type")]
+ public RecordType RecordType { get; set; }
+
+ [JsonProperty("record")]
+ public RecordReference Record { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/Date.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/Date.cs
new file mode 100644
index 0000000..a684b85
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/Date.cs
@@ -0,0 +1,75 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+using System;
+using System.Globalization;
+
+namespace PlanGrid.Api
+{
+ public struct Date
+ {
+ public const string Format = "yyyy-MM-dd";
+
+ private readonly DateTime when;
+
+ public Date(DateTime when)
+ {
+ this.when = when.Date;
+ }
+
+ public Date(int year, int month, int day) : this(new DateTime(year, month, day))
+ {
+ }
+
+ public static implicit operator DateTime(Date date)
+ {
+ return date.when;
+ }
+
+ public static implicit operator Date(DateTime dateTime)
+ {
+ return new Date(dateTime);
+ }
+
+ public override string ToString()
+ {
+ return when.ToString(Format, CultureInfo.InvariantCulture);
+ }
+
+ public static Date Parse(string s)
+ {
+ return DateTime.ParseExact(s, Format, CultureInfo.InvariantCulture);
+ }
+
+ public override int GetHashCode()
+ {
+ return when.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ var other = obj as Date?;
+ return other != null && when.Equals(other.Value.when);
+ }
+
+ public static bool operator ==(Date left, Date right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Date left, Date right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Date left, Date right)
+ {
+ return left.when < right.when;
+ }
+
+ public static bool operator >(Date left, Date right)
+ {
+ return left.when > right.when;
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/FailedRequestException.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/FailedRequestException.cs
new file mode 100644
index 0000000..6af4423
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/FailedRequestException.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Net;
+
+namespace PlanGrid.Api
+{
+ public class FailedRequestException : Exception
+ {
+ public HttpStatusCode StatusCode { get; }
+
+ public FailedRequestException(HttpStatusCode statusCode, string message) : base($"{(int)statusCode} ({statusCode}): {message}")
+ {
+ StatusCode = statusCode;
+ }
+
+ public FailedRequestException(HttpStatusCode statusCode, string message, Exception innerException) : base(message, innerException)
+ {
+ StatusCode = statusCode;
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/FailedRequestResponse.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/FailedRequestResponse.cs
new file mode 100644
index 0000000..0585ff8
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/FailedRequestResponse.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class FailedRequestResponse
+ {
+ [JsonProperty("message")]
+ public string Message { get; set; }
+
+ [JsonProperty("rate_limit")]
+ public RateLimit RateLimit { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/FileUpload.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/FileUpload.cs
new file mode 100644
index 0000000..d0402fe
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/FileUpload.cs
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class FileUpload
+ {
+ [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.NetCore/PlanGrid.Api/FileUploadRequest.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/FileUploadRequest.cs
new file mode 100644
index 0000000..9bd4d5e
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/FileUploadRequest.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class FileUploadRequest
+ {
+ [JsonProperty("uid")]
+ public string Uid { get; set; }
+
+ [JsonProperty("status")]
+ public FileUploadRequestStatus Status { get; set; }
+
+ [JsonProperty("url")]
+ public string Url { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/FileUploadRequestStatus.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/FileUploadRequestStatus.cs
new file mode 100644
index 0000000..cef58e3
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/FileUploadRequestStatus.cs
@@ -0,0 +1,13 @@
+using System.Runtime.Serialization;
+
+namespace PlanGrid.Api
+{
+ public enum FileUploadRequestStatus
+ {
+ [EnumMember(Value = "issued")]
+ Issued,
+
+ [EnumMember(Value = "consumed")]
+ Consumed
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/IMultipartContent.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/IMultipartContent.cs
new file mode 100644
index 0000000..36f84b0
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/IPlanGridApi.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/IPlanGridApi.cs
new file mode 100644
index 0000000..bcf3cc4
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/IPlanGridApi.cs
@@ -0,0 +1,175 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using System.Threading.Tasks;
+using Refit;
+
+namespace PlanGrid.Api
+{
+ public interface IPlanGridApi : IDisposable
+ {
+ [Get("/projects")]
+ Task> GetProjects(int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}")]
+ Task GetProject(string projectUid);
+
+ [Post("/projects")]
+ Task CreateProject([Body]ProjectUpdate project);
+
+ [Patch("/projects/{projectUid}")]
+ Task UpdateProject(string projectUid, [Body]ProjectUpdate project);
+
+ [Get("/projects/{projectUid}/comments")]
+ Task> GetComments(string projectUid, int skip = Page.Skip, int limit = Page.Limit, DateTime? updated_after = null, RecordType[] record_types = null);
+
+ [Get("/projects/{projectUid}/users")]
+ Task> GetUsers(string projectUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/users/{userUid}")]
+ Task GetUser(string projectUid, string userUid);
+
+ [Get("/me")]
+ Task GetUserProfile();
+
+ [Get("/projects/{projectUid}/roles")]
+ Task> GetRoles(string projectUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/roles/{roleUid}")]
+ Task GetRole(string projectUid, string roleUid);
+
+ [Post("/projects/{projectUid}/users/invites")]
+ Task InviteUser(string projectUid, UserInvitation invitation);
+
+ [Delete("/projects/{projectUid}/users/{userUid}")]
+ Task RemoveUser(string projectUid, string userUid);
+
+ [Get("/projects/{projectUid}/issues/{issueUid}")]
+ Task GetIssue(string projectUid, string issueUid);
+
+ [Get("/projects/{projectUid}/issues")]
+ Task> GetIssues(string projectUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/issues/{issueUid}/comments")]
+ Task> GetIssueComments(string projectUid, string issueUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/issues/{issueUid}/photos")]
+ Task> GetIssuePhotos(string projectUid, string issueUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/rfis")]
+ Task> GetRfis(string projectUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/rfis/{rfiUid}")]
+ Task GetRfi(string projectUid, string rfiUid);
+
+ [Get("/projects/{projectUid}/rfis/statuses")]
+ Task> GetRfiStatuses(string projectUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/rfis/{rfiUid}/attachments")]
+ Task> GetRfiAttachments(string projectUid, string rfiUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/rfis/{rfiUid}/comments")]
+ Task> GetRfiComments(string projectUid, string rfiUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/rfis/{rfiUid}/photos")]
+ Task> GetRfiPhotos(string projectUid, string rfiUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/rfis/{rfiUid}/snapshots")]
+ Task> GetRfiSnapshots(string projectUid, string rfiUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Delete("/projects/{projectUid}/rfis/{rfiUid}/snapshots/{snapshotUid}")]
+ Task RemoveSnapshotFromRfi(string projectUid, string rfiUid, string snapshotUid);
+
+ [Delete("/projects/{projectUid}/rfis/{rfiUid}/photos/{photoUid}")]
+ Task RemovePhotoFromRfi(string projectUid, string rfiUid, string photoUid);
+
+ [Delete("/projects/{projectUid}/rfis/{rfiUid}/attachments/{attachmentUid}")]
+ Task RemoveAttachmentFromRfi(string projectUid, string rfiUid, string attachmentUid);
+
+ [Get("/projects/{projectUid}/rfis/{rfiUid}/history")]
+ Task> GetRfiHistory(string projectUid, string rfiUid, int skip = Page.Skip, int limit = Page.Limit);
+
+ [Patch("/projects/{projectUid}/rfis/statuses/{statusUid}")]
+ Task UpdateRfiStatus(string projectUid, string statusUid, [Body]RfiStatusUpdate statusUpdate);
+
+ [Post("/projects/{projectUid}/rfis")]
+ Task CreateRfi(string projectUid, [Body]RfiUpsert rfi);
+
+ [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);
+
+ [Delete("/projects/{projectUid}/attachments/{attachmentUid}")]
+ Task RemoveAttachment(string projectUid, string attachmentUid);
+
+ [Patch("/projects/{projectUid}/attachments/{attachmentUid}")]
+ Task UpdateAttachment(string projectUid, string attachmentUid, [Body] AttachmentUpdate attachment);
+
+ [Get("/projects/{projectUid}/attachments")]
+ Task> GetAttachments(string projectUid, int skip = Page.Skip, int limit = Page.Limit, string folder = null, DateTime? updated_after = null);
+
+ [Get("/projects/{projectUid}/attachments/{attachmentUid}")]
+ Task GetAttachment(string projectUid, string attachmentUid);
+
+ [Post("/projects/{projectUid}/photos/uploads")]
+ Task CreatePhotoUploadRequest(string projectUid, [Body]PhotoUpload 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);
+
+ [Get("/projects/{projectUid}/photos/{photoUid}")]
+ Task GetPhotoInProject(string projectUid, string photoUid);
+
+ [Delete("/projects/{projectUid}/photos/{photoUid}")]
+ Task RemovePhoto(string projectUid, string photoUid);
+
+ [Patch("/projects/{projectUid}/photos/{photoUid}")]
+ Task UpdatePhoto(string projectUid, string photoUid, [Body]PhotoUpdate photo);
+
+ [Get("/projects/{projectUid}/sheets")]
+ Task> GetSheets(string projectUid, int skip = Page.Skip, int limit = Page.Limit, DateTime? updated_after = null, string version_set = null);
+
+ [Get("/projects/{projectUid}/snapshots/{snapshotUid}")]
+ Task GetSnapshot(string projectUid, string snapshotUid);
+
+ [Delete("/projects/{projectUid}/snapshots/{snapshotUid}")]
+ Task RemoveSnapshot(string projectUid, string snapshotUid);
+
+ [Get("/projects/{projectUid}/sheets/{sheetUid}")]
+ Task GetSheet(string projectUid, string sheetUid);
+
+ [Post("/projects/{projectUid}/sheets/uploads")]
+ Task UploadVersion(string projectUid, [Body]UploadVersionRequest request);
+
+ [Post("/projects/{projectUid}/sheets/uploads/{versionUploadUid}/files/{fileUploadRequestUid}")]
+ Task UploadFileToVersion(string projectUid, string versionUploadUid, string fileUploadRequestUid, [Body]UploadFile file);
+
+ [Post("/projects/{projectUid}/sheets/uploads/files/completions/{uploadToken}")]
+ Task CompleteFileUpload(string projectUid, string uploadToken);
+
+ [Post("/projects/{projectUid}/sheets/uploads/{versionUploadUid}/completions")]
+ Task CompleteVersionUpload(string projectUid, string versionUploadUid);
+
+ [Post("/projects/{projectUid}/sheets/packets")]
+ Task CreateSheetPacket(string projectUid, SheetPacketRequest request);
+
+ [Get("/projects/{projectUid}/sheets/packets/{packetUid}")]
+ Task GetSheetPacket(string projectUid, string packetUid);
+
+ [Get("/rate_limits")]
+ Task> GetRateLimits(int skip = Page.Skip, int limit = Page.Limit);
+
+ [Get("/projects/{projectUid}/snapshots")]
+ Task> GetSnapshots(string projectUid, int skip = Page.Skip, int limit = Page.Limit, DateTime? updated_after = null);
+
+ [Get("/projects/{projectUid}/version_sets")]
+ Task> GetVersionSets(string projectUid, int skip = Page.Skip, int limit = Page.Limit);
+ }
+}
\ No newline at end of file
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/Issue.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/Issue.cs
new file mode 100644
index 0000000..3de43f2
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/Issue.cs
@@ -0,0 +1,87 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class Issue : Record
+ {
+ [JsonProperty("number")]
+ public int Number { get; set; }
+
+ [JsonProperty("current_annotation")]
+ public IssueAnnotation CurrentAnnotation { get; set; }
+
+ [JsonProperty("room")]
+ public string Room { get; set; }
+
+ [JsonProperty("description")]
+ public string Description { get; set; }
+
+ [JsonProperty("title")]
+ public string Title { get; set; }
+
+ [JsonProperty("assigned_to")]
+ public UserReference[] AssignedTo { get; set; }
+
+ [JsonProperty("status")]
+ public IssueStatus Status { get; set; }
+
+ [JsonProperty("created_at")]
+ public DateTime CreatedAt { get; set; }
+
+ [JsonProperty("created_by")]
+ public UserReference CreatedBy { get; set; }
+
+ [JsonProperty("updated_at")]
+ public DateTime UpdatedAt { get; set; }
+
+ [JsonProperty("updated_by")]
+ public UserReference UpdatedBy { get; set; }
+
+ [JsonProperty("photos")]
+ public CollectionReference Photos { get; set; }
+
+ [JsonProperty("comments")]
+ public CollectionReference Comments { get; set; }
+
+ [JsonProperty("deleted")]
+ public bool IsDeleted { get; set; }
+
+ [JsonProperty("due_at")]
+ public DateTime? DueAt { get; set; }
+
+ [JsonProperty("has_cost_impact")]
+ public bool HasCostImpact { get; set; }
+
+ ///
+ /// The cost impact in dollars and cents.
+ ///
+ [JsonProperty("cost_impact")]
+ public decimal? CostImpact { get; set; }
+
+ [JsonProperty("currency_code")]
+ public string CurrencyCode { get; set; }
+
+ [JsonProperty("has_schedule_impact")]
+ public bool HasScheduleImpact { get; set; }
+
+ ///
+ /// The schedule impact in seconds.
+ ///
+ [JsonProperty("schedule_impact")]
+ public long? ScheduleImpact { get; set; }
+
+ private const int DayInSeconds = 60 * 60 * 24;
+
+ [JsonIgnore]
+ public int ScheduleImpactDays
+ {
+ get { return (int)(ScheduleImpact / (DayInSeconds)); }
+ set { ScheduleImpact = value * DayInSeconds; }
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/IssueAnnotation.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/IssueAnnotation.cs
new file mode 100644
index 0000000..63fd743
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/IssueAnnotation.cs
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class IssueAnnotation
+ {
+ [JsonProperty("uid")]
+ public string Uid { get; set; }
+
+ [JsonProperty("color")]
+ public string Color { get; set; }
+
+ [JsonProperty("stamp")]
+ public string Stamp { get; set; }
+
+ [JsonProperty("visibility")]
+ public AnnotationVisibility Visibility { get; set; }
+
+ [JsonProperty("deleted")]
+ public bool IsDeleted { get; set; }
+
+ [JsonProperty("sheet")]
+ public RecordReference Sheet { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/IssueAnnotationSheet.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/IssueAnnotationSheet.cs
new file mode 100644
index 0000000..652aa72
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/IssueAnnotationSheet.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class IssueAnnotationSheet
+ {
+ [JsonProperty("uid")]
+ public string Uid { get; set; }
+
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("version_name")]
+ public string VersionName { get; set; }
+
+ [JsonProperty("deleted")]
+ public bool IsDeleted { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/IssueStatus.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/IssueStatus.cs
new file mode 100644
index 0000000..f186598
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/IssueStatus.cs
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System.Runtime.Serialization;
+
+namespace PlanGrid.Api
+{
+ public enum IssueStatus
+ {
+ None,
+
+ [EnumMember(Value = "open")]
+ Open,
+
+ [EnumMember(Value = "in_review")]
+ InReview,
+
+ [EnumMember(Value = "pending")]
+ Pending,
+
+ [EnumMember(Value = "closed")]
+ Closed
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/BaseUrlParameterFormatter.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/BaseUrlParameterFormatter.cs
new file mode 100644
index 0000000..0d0205c
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/BaseUrlParameterFormatter.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using Refit;
+
+namespace PlanGrid.Api.JsonConverters
+{
+ public abstract class BaseUrlParameterFormatter : IUrlParameterFormatter
+ {
+ public abstract bool CanFormat(object argument, ParameterInfo parameter);
+ public abstract string Format(object value, ParameterInfo parameterInfo);
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/CommaSeparatedListUrlParameterFormatter.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/CommaSeparatedListUrlParameterFormatter.cs
new file mode 100644
index 0000000..b1d25b7
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/CommaSeparatedListUrlParameterFormatter.cs
@@ -0,0 +1,19 @@
+using System.Collections;
+using System.Reflection;
+using Refit;
+
+namespace PlanGrid.Api.JsonConverters
+{
+ public class CommaSeparatedListUrlParameterFormatter : BaseUrlParameterFormatter
+ {
+ public override bool CanFormat(object argument, ParameterInfo parameter)
+ {
+ return typeof(IList).IsAssignableFrom(parameter.ParameterType);
+ }
+
+ public override string Format(object value, ParameterInfo parameterInfo)
+ {
+ return string.Join(",", (IEnumerable)value);
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/DateConverter.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/DateConverter.cs
new file mode 100644
index 0000000..af0b5fa
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/DateConverter.cs
@@ -0,0 +1,25 @@
+using System;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api.JsonConverters
+{
+ public class DateConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ var date = (Date?)value;
+ writer.WriteValue(date?.ToString());
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ string s = (string)reader.Value;
+ return s == null ? null : (Date?)Date.Parse(s);
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return typeof(Date).IsAssignableFrom(Nullable.GetUnderlyingType(objectType) ?? objectType);
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/DateUrlParameterFormatter.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/DateUrlParameterFormatter.cs
new file mode 100644
index 0000000..9565c67
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/DateUrlParameterFormatter.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Reflection;
+using Refit;
+
+namespace PlanGrid.Api.JsonConverters
+{
+ public class DateUrlParameterFormatter : BaseUrlParameterFormatter
+ {
+ public override bool CanFormat(object argument, ParameterInfo parameter)
+ {
+ return argument is DateTime;
+ }
+
+ public override string Format(object value, ParameterInfo parameterInfo)
+ {
+ return ((DateTime)value).ToString("yyyy-MM-ddTHH\\:mm\\:ss");
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/PlanGridUrlParameterFormatter.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/PlanGridUrlParameterFormatter.cs
new file mode 100644
index 0000000..0e89f5f
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/JsonConverters/PlanGridUrlParameterFormatter.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Reflection;
+using Refit;
+
+namespace PlanGrid.Api.JsonConverters
+{
+ public class PlanGridUrlParameterFormatter : IUrlParameterFormatter
+ {
+ private DefaultUrlParameterFormatter defaultFormatter = new DefaultUrlParameterFormatter();
+ private List formatters = new List();
+
+ public PlanGridUrlParameterFormatter()
+ {
+ formatters.Add(new DateUrlParameterFormatter());
+ formatters.Add(new CommaSeparatedListUrlParameterFormatter());
+ }
+
+ public string Format(object value, ParameterInfo parameterInfo)
+ {
+ foreach (BaseUrlParameterFormatter formatter in formatters)
+ {
+ if (formatter.CanFormat(value, parameterInfo))
+ {
+ return formatter.Format(value, parameterInfo);
+ }
+ }
+ return defaultFormatter.Format(value, parameterInfo);
+ }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/MultipartUploadException.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/MultipartUploadException.cs
new file mode 100644
index 0000000..5a833fa
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/MultipartUploader.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/MultipartUploader.cs
new file mode 100644
index 0000000..6d13231
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/Page.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/Page.cs
new file mode 100644
index 0000000..fcda052
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/Page.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public static class Page
+ {
+ public const int Skip = 0;
+ public const int Limit = 50;
+ }
+
+ public class Page
+ {
+ [JsonProperty("total_count")]
+ public int TotalCount { get; set; }
+
+ [JsonProperty("next_page_url")]
+ public string NextPageUrl { get; set; }
+
+ [JsonProperty("data")]
+ public T[] Data { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/Photo.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/Photo.cs
new file mode 100644
index 0000000..3cd774d
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/Photo.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class Photo
+ {
+ [JsonProperty("uid")]
+ public string Uid { get; set; }
+
+ [JsonProperty("title")]
+ public string Title { get; set; }
+
+ [JsonProperty("url")]
+ public string Url { get; set; }
+
+ [JsonProperty("created_at")]
+ public DateTime CreatedAt { get; set; }
+
+ [JsonProperty("created_by")]
+ public UserReference CreatedBy { get; set; }
+
+ [JsonProperty("deleted")]
+ public bool IsDeleted { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/PhotoReference.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/PhotoReference.cs
new file mode 100644
index 0000000..4f7f831
--- /dev/null
+++ b/PlanGrid.Api.NetCore/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.NetCore/PlanGrid.Api/PhotoUpdate.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/PhotoUpdate.cs
new file mode 100644
index 0000000..2e1bef8
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/PhotoUpdate.cs
@@ -0,0 +1,13 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class PhotoUpdate
+ {
+ [JsonProperty("title")]
+ public string Title { get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/PhotoUpload.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/PhotoUpload.cs
new file mode 100644
index 0000000..ebab73a
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/PhotoUpload.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace PlanGrid.Api
+{
+ public class PhotoUpload
+ {
+ public const string Jpeg = "image/jpeg";
+ public const string Png = "image/png";
+
+ [JsonProperty("content_type")]
+ public string ContentType { get; set; }
+
+ [JsonProperty("title")]
+ public string Title{ get; set; }
+ }
+}
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGrid.Api.projitems b/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGrid.Api.projitems
new file mode 100644
index 0000000..0cd3314
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGrid.Api.projitems
@@ -0,0 +1,80 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ 42b50126-061c-41dc-8544-b1698a30891e
+
+
+ PlanGrid.Api
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGrid.Api.shproj b/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGrid.Api.shproj
new file mode 100644
index 0000000..8c0c6ef
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGrid.Api.shproj
@@ -0,0 +1,13 @@
+
+
+
+ 42b50126-061c-41dc-8544-b1698a30891e
+ 14.0
+
+
+
+
+
+
+
+
diff --git a/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGridApiExtensions.cs b/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGridApiExtensions.cs
new file mode 100644
index 0000000..3a6f8a3
--- /dev/null
+++ b/PlanGrid.Api.NetCore/PlanGrid.Api/PlanGridApiExtensions.cs
@@ -0,0 +1,145 @@
+//
+// Copyright (c) 2016 PlanGrid, Inc. All rights reserved.
+//
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Refit;
+
+namespace PlanGrid.Api
+{
+ public static class PlanGridApiExtensions
+ {
+ public static async Task Resolve(this IPlanGridApi api, RecordReference reference) where T : Record
+ {
+ var generatedApi = (AutoGeneratedIPlanGridApi)api;
+ RefitSettings settings = generatedApi.Settings;
+ HttpClient client = generatedApi.Client;
+
+ HttpResponseMessage response = await client.GetAsync(reference.Url);
+ response.EnsureSuccessStatusCode();
+ string content = await response.Content.ReadAsStringAsync();
+ var result = JsonConvert.DeserializeObject(content, settings.JsonSerializerSettings);
+ return result;
+ }
+
+ public static async Task> Resolve(this IPlanGridApi api, CollectionReference reference)
+ {
+ var generatedApi = (AutoGeneratedIPlanGridApi)api;
+ RefitSettings settings = generatedApi.Settings;
+ HttpClient client = generatedApi.Client;
+
+ HttpResponseMessage response = await client.GetAsync(reference.Url);
+ response.EnsureSuccessStatusCode();
+ string content = await response.Content.ReadAsStringAsync();
+ 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))
+ {
+ FileUpload request = await api.CreateAttachmentUploadRequest(projectUid, new AttachmentUpload { ContentType = contentType, Name = name, Folder = folder });
+ return await api.Upload(request, payload, cancellationToken);
+ }
+
+ public static Task UploadPngPhoto(this IPlanGridApi api, string projectUid, string title, Stream payload, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return api.UploadPhoto(projectUid, PhotoUpload.Png, title, payload, cancellationToken);
+ }
+
+ public static Task UploadJpegPhoto(this IPlanGridApi api, string projectUid, string title, Stream payload, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return api.UploadPhoto(projectUid, PhotoUpload.Jpeg, title, payload, cancellationToken);
+ }
+
+ public static async Task UploadPhoto(this IPlanGridApi api, string projectUid, string contentType, string title, Stream payload, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ FileUpload request = await api.CreatePhotoUploadRequest(projectUid, new PhotoUpload { ContentType = contentType, Title = title });
+ return await api.Upload(request, payload, cancellationToken);
+ }
+
+ public static async Task Post(this IPlanGridApi api, string url, object request)
+ {
+ var generatedApi = (AutoGeneratedIPlanGridApi)api;
+ JsonSerializerSettings settings = generatedApi.Settings.JsonSerializerSettings;
+
+ var client = new HttpClient(new PlanGridHttpHandler(generatedApi.ApiKey, generatedApi.Settings, generatedApi.Version, generatedApi.MaxRetries));
+ string requestJson = JsonConvert.SerializeObject(request, settings);
+ HttpResponseMessage response = await client.PostAsync(url, new StringContent(requestJson, Encoding.UTF8, "application/json"));
+ string responseJson = await response.Content.ReadAsStringAsync();
+ var result = JsonConvert.DeserializeObject(responseJson, settings);
+ return result;
+ }
+
+ public static async Task Get(this IPlanGridApi api, string url)
+ {
+ var generatedApi = (AutoGeneratedIPlanGridApi)api;
+ JsonSerializerSettings settings = generatedApi.Settings.JsonSerializerSettings;
+
+ var client = new HttpClient(new PlanGridHttpHandler(generatedApi.ApiKey, generatedApi.Settings, generatedApi.Version, generatedApi.MaxRetries));
+ HttpResponseMessage response = await client.GetAsync(url);
+ string responseJson = await response.Content.ReadAsStringAsync();
+ var result = JsonConvert.DeserializeObject(responseJson, settings);
+ return result;
+ }
+
+ public static async Task Upload(this IPlanGridApi api, FileUpload fileUpload, Stream payload, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var values = new List();
+ foreach (AwsPostFormArgument item in fileUpload.AwsPostFormArguments.Fields)
+ {
+ values.Add(new StringMultipartContent(item.Name, item.Value));
+ }
+
+ var generatedApi = (AutoGeneratedIPlanGridApi)api;
+ RefitSettings settings = generatedApi.Settings;
+
+ values.Add(new StreamMultipartContent("file", "data", fileUpload.AwsPostFormArguments.Fields.Single(x => x.Name == "Content-Type").Value, payload));
+ HttpResponseMessage response = await MultipartUploader.Upload(fileUpload.AwsPostFormArguments.Action, cancellationToken, values.ToArray());
+ if (typeof(T) != typeof(object))
+ {
+ string responseText = await response.Content.ReadAsStringAsync();
+ return JsonConvert.DeserializeObject(responseText, settings.JsonSerializerSettings);
+ }
+ else
+ {
+ return default(T);
+ }
+ }
+
+ public static async Task UploadVersion(this IPlanGridApi api, string projectUid, string versionName, params VirtualFile[] files)
+ {
+ VersionUpload versionUpload = await api.UploadVersion(projectUid, new UploadVersionRequest
+ {
+ NumberOfFiles = files.Length,
+ VersionName = versionName
+ });
+
+ var tasks = new List();
+ foreach (var item in versionUpload.FileUploadRequests.Zip(files, (x, y) => new { File = y, Request = x }))
+ {
+ tasks.Add(api.RequestFileUpload(item.Request, item.File));
+ }
+ await Task.WhenAll(tasks);
+
+ await api.CompleteVersionUpload(projectUid, versionUpload.Uid);
+ }
+
+ private static async Task RequestFileUpload(this IPlanGridApi api, FileUploadRequest request, VirtualFile file)
+ {
+ FileUpload fileUpload = await api.Post(request.Url, new UploadFile { FileName = file.FileName });
+ await api.Upload