public bool CommentIssue(oM.Inspection.Issue bhomIssue, string tdrepoIssueId, PushConfig pushConfig = null) { bool success = true; CheckMediaPath(pushConfig); foreach (var mediaPath in bhomIssue.Media) { string mediaFullPath = pushConfig.MediaDirectory + "/" + mediaPath; success &= CommentIssue(bhomIssue.Name, tdrepoIssueId, mediaPath, mediaFullPath); } return(success); }
public bool AttachResources(oM.Inspection.Issue bhomIssue, string tdrepoIssueId, PushConfig pushConfig, bool raiseErrors = true) { bool success = true; if (!bhomIssue.Media?.Any() ?? true) { return(true); } CheckMediaPath(pushConfig); // // - The media needs to be attached as a "Resource" of the issue. // // - This requires a MultipartFormData request. See https://3drepo.github.io/3drepo.io/#api-Issues-attachResource using (HttpClient httpClient = new HttpClient()) { string issueResourceEndpoint = $"{m_host}/{m_teamspace}/{m_modelId}/issues/{tdrepoIssueId}/resources?key={m_userAPIKey}"; foreach (string mediaPath in bhomIssue.Media) { // Remember that BHoMIssues have media attached as a partial file path. string fullMediaPath = System.IO.Path.Combine(pushConfig.MediaDirectory ?? "C:\\temp\\", mediaPath); var f = System.IO.File.OpenRead(fullMediaPath); StreamContent imageContent = new StreamContent(f); MultipartFormDataContent mpcontent = new MultipartFormDataContent(); mpcontent.Add(imageContent, "file", mediaPath); StringContent nameContent = new StringContent(Path.GetFileNameWithoutExtension(mediaPath)); mpcontent.Add(nameContent, "names"); // POST request HttpResponseMessage respMessage = null; try { respMessage = httpClient.PostAsync(issueResourceEndpoint, mpcontent).Result; } catch (AggregateException e) { string errors = $"Error(s) attaching multiple resources (media) for issue `{tdrepoIssueId}` named `{bhomIssue.Name}`:"; foreach (var innerException in e.Flatten().InnerExceptions) { errors += $"\n\t{innerException.Message}\n{innerException.InnerException}"; } if (raiseErrors) { BH.Engine.Reflection.Compute.RecordError(errors); } return(false); } finally { f.Close(); } // Process response string fullResponse = respMessage?.Content.ReadAsStringAsync().Result; if (respMessage != null && !respMessage.IsSuccessStatusCode) { fullResponse = fullResponse.GetResponseBody(); BH.Engine.Reflection.Compute.RecordWarning($"While attaching multiple resources (media) for issue `{tdrepoIssueId}` named `{bhomIssue.Name}`," + $"\nthe server returned a '{respMessage.StatusCode}' error for media `{mediaPath}`:\n ==>" + fullResponse); success = false; } } } return(success); }
/***************************************************/ /**** Public Methods ****/ /***************************************************/ public List <oM.Inspection.Issue> GetIssues(IssueRequest ir, PullConfig pullConfig, bool enableMessages = true, Dictionary <Issue, List <string> > mediaFileNames = null) { List <Issue> allIssues = new List <Issue>(); List <oM.Inspection.Issue> allBHoMIssues = new List <oM.Inspection.Issue>(); string modelId = ir?.ModelId ?? m_modelId; string teamsSpace = ir?.TeamSpace ?? m_teamspace; string userAPIkey = ""; if (!string.IsNullOrWhiteSpace(ir.UserAPIKey)) { userAPIkey = ir.UserAPIKey; } else if (!string.IsNullOrWhiteSpace(m_userAPIKey)) { userAPIkey += m_userAPIKey; } bool singleIssue = !string.IsNullOrWhiteSpace(ir.IssueId); if (singleIssue) { // Get the Issue corresponding to the specified IssueId. if (enableMessages) { BH.Engine.Reflection.Compute.RecordNote($"Getting {nameof(Issue)} with id {ir.IssueId} \nfrom the 3DRepo Model `{modelId}` in the Teamspace `{teamsSpace}`."); } Issue issue = GetIssue(ir.IssueId, teamsSpace, modelId, userAPIkey); allIssues.Add(issue); } else { // If no IssueId is specified, get *all the issues* attached to a specific Revision. // (In 3DRepo, the issues are attached to a specific Model's Revision.) // If no RevisionId is specified in the Request, consider the latest revision (First()). string revisionId = ir.RevisionId ?? GetRevisions(new RevisionRequest(), false).First().Id; if (enableMessages) { BH.Engine.Reflection.Compute.RecordNote($"Getting all of the {nameof(Issue)}s attached to RevisionId {revisionId} \nfrom the 3DRepo Model `{modelId}` in the Teamspace `{teamsSpace}`."); } allIssues = GetAllIssues(teamsSpace, modelId, revisionId, userAPIkey); } if (pullConfig.DownloadResources) { // Attempt the pull of the resources. foreach (Issue issue in allIssues) { // Dictionary whose Key is filename (fullPath), Value is the base64 string representation. Dictionary <string, string> base64resources = new Dictionary <string, string>(); // Get all resources files. https://3drepo.github.io/3drepo.io/#api-Resources-getResource foreach (var resource in issue.Resources) { string endpoint = $"https://api1.www.3drepo.io/api/{teamsSpace}/{modelId}/resources/{resource._id}?key={userAPIkey}"; // GET request HttpResponseMessage respMessage; byte[] fullResponse = null; using (var httpClient = new HttpClient()) { respMessage = httpClient.GetAsync(endpoint).Result; // Process response fullResponse = respMessage.Content.ReadAsByteArrayAsync().Result; string base64 = System.Convert.ToBase64String(fullResponse); base64resources.Add(Path.Combine(pullConfig.ResourceDownloadDirectory, resource.name), base64); } } // Get resources (image) attached in the Comments, if any. (TODO) foreach (var comment in issue?.Comments) { var screenshot = comment.viewpoint?.Screenshot; if (screenshot != null) { base64resources.Add(Path.Combine(pullConfig.ResourceDownloadDirectory, comment.comment), screenshot); } // TODO: Apparently, the actual image is not pulled (`Comments` property is empty) when using the GET Issue endpoint. // There is another endpoint/way to pull the image that was posted in the Comments: // `getViewpoint` endpoint is to be used to get image from the Viewpoint. https://3drepo.github.io/3drepo.io/#api-Viewpoints-findViewpoint } // Save the pulled resource to file. If the base64 string is missing, it will simply create an empty file. base64resources.ToList().ForEach(kv => Compute.WriteToByteArray(kv.Value, kv.Key, false)); // Store the pulled images Filenames in the resources. // This allows to pass this information to the Convert method, see the Pull. if (mediaFileNames != null) { mediaFileNames[issue] = issue.Comments.Select(c => c.comment).ToList(); } } } foreach (Issue issue in allIssues) { List <string> fileNames = new List <string>(); if (issue.Resources != null) { fileNames = issue.Resources.Select(x => x.name).ToList(); } oM.Inspection.Issue bhomIssue = issue.FromTDRepo(fileNames); allBHoMIssues.Add(bhomIssue); } return(allBHoMIssues); }