Example #1
0
        public static async Task ProcessFileAsync(string userId, string hubId, string projectId, string folderUrn, string itemUrn, string versionUrn, string fileName, PerformContext console)
        {
            Credentials credentials = await Credentials.FromDatabaseAsync(userId);

            // start the translation
            DerivativesApi derivative = new DerivativesApi();

            derivative.Configuration.AccessToken = credentials.TokenInternal;

            dynamic document = new JObject();

            document.hubId      = hubId.Replace("-", string.Empty); // this is breaking the search...
            document.projectId  = projectId;
            document.folderUrn  = folderUrn;
            document.itemUrn    = itemUrn;
            document.versionUrn = versionUrn;
            document.fileName   = fileName;
            document.metadata   = new JArray();

            string  versionUrn64 = Base64Encode(versionUrn);
            dynamic manifest     = await derivative.GetManifestAsync(versionUrn64);

            if (manifest.status == "inprogress")
            {
                throw new Exception("Translating...");                                  // force run it again
            }
            List <ManifestItem> manifestItems = ParseManifest(manifest.derivatives);

            List <Resource> resouces = new List <Resource>();

            foreach (ManifestItem item in manifestItems)
            {
                if (item.MIME != "application/autodesk-db")
                {
                    continue;
                }

                string file  = "objects_vals.json.gz";    // the only file we need here
                Uri    myUri = new Uri(new Uri(item.Path.BasePath), file);
                resouces.Add(new Resource()
                {
                    FileName   = file,
                    RemotePath = "derivativeservice/v2/derivatives/" + Uri.UnescapeDataString(myUri.AbsoluteUri),
                    LocalPath  = Path.Combine(item.Path.LocalPath, file)
                });
            }

            // this approach uses the Viewer propertyDatabase, which is a non-supported way of accessing the model metadata
            // it will return the non-duplicated list of attributes values (not the attribute type)
            // as we don't want to manipulate it, just search, it doesn't matter if this list changes its format
            IRestClient forgeClient = new RestClient("https://developer.api.autodesk.com/");

            if (resouces.Count != 1 && fileName.ToLower().IndexOf("pdf") == -1)
            {
                throw new Exception(resouces.Count + " objects_vals.json.gz found, will try again");
            }

            if (fileName.ToLower().IndexOf("pdf") != -1)
            {
            }
            else
            {
                RestRequest forgeRequest = new RestRequest(resouces[0].RemotePath, Method.GET);
                forgeRequest.AddHeader("Authorization", "Bearer " + credentials.TokenInternal);
                forgeRequest.AddHeader("Accept-Encoding", "gzip, deflate");
                IRestResponse response = await forgeClient.ExecuteTaskAsync(forgeRequest);

                if (response.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    console.WriteLine(string.Format("Cannot download attributes ({0}), will retry", response.StatusCode));
                    throw new Exception(string.Format("Cannot download attributes: {0}", response.StatusCode));
                }
                using (GZipStream gzip = new GZipStream(new MemoryStream(response.RawBytes), CompressionMode.Decompress))
                    using (var fileStream = new StreamReader(gzip))
                    {
                        dynamic viewProperties = new JObject();
                        viewProperties.viewId     = "viewer";
                        viewProperties.collection = System.Text.RegularExpressions.Regex.Replace(fileStream.ReadToEnd(), @"\n", string.Empty);
                        document.metadata.Add(viewProperties);
                    }


                // as an alternative solution, using supported APIs, one could get the complete metadata JSON
                // but that results in more data that we don't need for search, like attribute names

                /*{
                 *  dynamic metadata = await derivative.GetMetadataAsync(versionUrn64);
                 *  foreach (KeyValuePair<string, dynamic> metadataItem in new DynamicDictionaryItems(metadata.data.metadata))
                 *  {
                 *      dynamic properties = await derivative.GetModelviewPropertiesAsync(versionUrn64, metadataItem.Value.guid);
                 *      if (properties == null)
                 *      {
                 *          console.WriteLine("Model not ready, will retry");
                 *          throw new Exception("Model not ready...");
                 *      }
                 *      console.WriteLine(string.Format("View: {0}", (string)metadataItem.Value.guid));
                 *      JArray collection = JObject.Parse(properties.ToString()).data.collection;
                 *
                 *      if (collection.Count > 0)
                 *      {
                 *          dynamic viewProperties = new JObject();
                 *          viewProperties.viewId = (string)metadataItem.Value.guid;
                 *          viewProperties.collection = collection.ToString(Newtonsoft.Json.Formatting.None);
                 *          document.metadata.Add(viewProperties);
                 *      }
                 *  }
                 * }*/
            }
            string json         = (string)document.ToString(Newtonsoft.Json.Formatting.None);
            string absolutePath = string.Format("/manifest/_doc/{0}", Base64Encode(itemUrn));

            RestClient  elasticSearchclient  = new RestClient(Config.ElasticSearchServer);
            RestRequest elasticSearchRequest = new RestRequest(absolutePath, RestSharp.Method.POST);

            elasticSearchRequest.AddHeader("Content-Type", "application/json");
            elasticSearchRequest.AddParameter("text/json", json, ParameterType.RequestBody);

            if (!string.IsNullOrEmpty(Config.AWSKey) && !string.IsNullOrEmpty(Config.AWSSecret))
            {
                SortedDictionary <string, string> headers = AWS.Signature.SignatureHeader(
                    Amazon.RegionEndpoint.GetBySystemName(Config.AWSRegion),
                    new Uri(Config.ElasticSearchServer).Host,
                    "POST", json, absolutePath);
                foreach (var entry in headers)
                {
                    elasticSearchRequest.AddHeader(entry.Key, entry.Value);
                }
            }

            IRestResponse res = await elasticSearchclient.ExecuteTaskAsync(elasticSearchRequest);

            console.WriteLine(string.Format("Submit to elasticsearch status: {0}", res.StatusCode.ToString()));
        }
 [Route("api/forge/clientid")] // see Web.Config FORGE_CALLBACK_URL variable
 public dynamic GetClientID()
 {
     return(new { id = Credentials.GetAppSetting("FORGE_CLIENT_ID") });
 }
        public async Task <IActionResult> StartWorkitem([FromForm] StartWorkitemInput input)
        {
            Credentials = await Credentials.FromSessionAsync(base.Request.Cookies, Response.Cookies);

            if (Credentials == null)
            {
                return(null);
            }

            // basic input validation
            JObject workItemData        = JObject.Parse(input.data);
            string  inputRvtFileName    = workItemData["inputRvtFileName"].Value <string>();
            string  inputRvtFileUrl     = workItemData["inputRvtFileUrl"].Value <string>();
            string  inputFamilyFileName = workItemData["inputFamilyFileName"].Value <string>();
            string  inputFamilyFileUrl  = workItemData["inputFamilyFileUrl"].Value <string>();
            string  outputFolderUrl     = workItemData["outputFolderUrl"].Value <string>();
            string  roomUniquId         = workItemData["roomUniquId"].Value <string>();
            string  gridTypeId          = workItemData["gridTypeId"].Value <string>();

            string distanceXMinParam    = workItemData["distanceXMinParam"].Value <string>();
            string distanceXMaxParam    = workItemData["distanceXMaxParam"].Value <string>();
            string distanceYMinParam    = workItemData["distanceYMinParam"].Value <string>();
            string distanceYMaxParam    = workItemData["distanceYMaxParam"].Value <string>();
            string distanceWallMinParam = workItemData["distanceWallMinParam"].Value <string>();
            string distanceWallMaxParam = workItemData["distanceWallMaxParam"].Value <string>();

            string browerConnectionId = workItemData["browerConnectionId"].Value <string>();

            string activityName = string.Format("{0}.{1}", NickName, workItemData["activityName"].Value <string>());

            // OAuth token
            dynamic da4rToken = Credentials.DA4RTokenInternal;
            dynamic userToken = Credentials.TokenInternal;

            VersionsApi versionApi = new VersionsApi();

            versionApi.Configuration.AccessToken = Credentials.TokenInternal;

            // Revit file download URL
            string[] revitFileParams         = inputRvtFileUrl.Split('/');
            string   revitFileProjectIdParam = revitFileParams[1];
            string   revitFileVersionIdParam = revitFileParams[2];
            dynamic  revitFileVersion        = await versionApi.GetVersionAsync(revitFileProjectIdParam, revitFileVersionIdParam);

            string[] revitFileVersionStorageParams = ((string)revitFileVersion.data.relationships.storage.data.id).Split('/');
            string[] revitFileBucketKeyParams      = revitFileVersionStorageParams[revitFileVersionStorageParams.Length - 2].Split(':');
            string   revitFileBucketKey            = revitFileBucketKeyParams[revitFileBucketKeyParams.Length - 1];
            string   revitFileObjectName           = revitFileVersionStorageParams[revitFileVersionStorageParams.Length - 1];
            string   revitFileDownloadUrl          = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", revitFileBucketKey, revitFileObjectName);

            // Family file download URL
            string[] familyFileParams         = inputFamilyFileUrl.Split('/');
            string   familyFileProjectIdParam = familyFileParams[1];
            string   familyFileVersionIdParam = familyFileParams[2];
            dynamic  familyFileVersion        = await versionApi.GetVersionAsync(familyFileProjectIdParam, familyFileVersionIdParam);

            string[] familyFileVersionStorageParams = ((string)familyFileVersion.data.relationships.storage.data.id).Split('/');
            string[] familyFileBucketKeyParams      = familyFileVersionStorageParams[familyFileVersionStorageParams.Length - 2].Split(':');
            string   familyFileBucketKey            = familyFileBucketKeyParams[familyFileBucketKeyParams.Length - 1];
            string   familyFileObjectName           = familyFileVersionStorageParams[familyFileVersionStorageParams.Length - 1];
            string   familyFileDownloadUrl          = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", familyFileBucketKey, familyFileObjectName);

            // prepare workitem arguments
            // 1. input file
            XrefTreeArgument inputRevitFileArgument = new XrefTreeArgument()
            {
                Url     = string.Format(revitFileDownloadUrl),
                Verb    = Verb.Get,
                Headers = new Dictionary <string, string>()
                {
                    { "Authorization", "Bearer " + userToken }
                }
            };

            XrefTreeArgument inputFamilyFileArgument = new XrefTreeArgument()
            {
                Url     = string.Format(familyFileDownloadUrl),
                Verb    = Verb.Get,
                Headers = new Dictionary <string, string>()
                {
                    { "Authorization", "Bearer " + userToken }
                }
            };

            // 2. input json
            dynamic inputJson = new JObject();

            inputJson.RoomUniqueId         = roomUniquId;
            inputJson.GridTypeId           = gridTypeId;
            inputJson.FamilyFileName       = inputFamilyFileName;
            inputJson.OutputZipFileName    = "exportedDwgs";
            inputJson.DistanceXMinParam    = distanceXMinParam;
            inputJson.DistanceXMaxParam    = distanceXMaxParam;
            inputJson.DistanceYMinParam    = distanceYMinParam;
            inputJson.DistanceYMaxParam    = distanceYMaxParam;
            inputJson.DistanceWallMinParam = distanceWallMinParam;
            inputJson.DistanceWallMaxParam = distanceWallMaxParam;
            XrefTreeArgument inputJsonArgument = new XrefTreeArgument()
            {
                Url = "data:application/json, " + ((JObject)inputJson).ToString(Formatting.None).Replace("\"", "'")
            };

            // 3. output file
            string[] folderParams = outputFolderUrl.Split('/');

            string outputFolderId  = folderParams[folderParams.Length - 1];
            string outputProjectId = folderParams[folderParams.Length - 3];

            dynamic storageCreatedZip = await this.CreateStorage(outputFolderId, outputProjectId, "exportedDwgs" + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".zip");

            string[] zipFileStorageIdParams = ((string)storageCreatedZip.data.id).Split('/');
            string[] zipFileBucketKeyParams = zipFileStorageIdParams[zipFileStorageIdParams.Length - 2].Split(':');
            string   zipFileBucketKey       = zipFileBucketKeyParams[zipFileBucketKeyParams.Length - 1];
            string   zipFileObjectName      = zipFileStorageIdParams[zipFileStorageIdParams.Length - 1];

            string uploadZipFileUrl = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", zipFileBucketKey, zipFileObjectName);


            XrefTreeArgument outputZipFileArgument = new XrefTreeArgument()
            {
                Url     = uploadZipFileUrl,
                Verb    = Verb.Put,
                Headers = new Dictionary <string, string>()
                {
                    { "Authorization", "Bearer " + userToken }
                }
            };

            // prepare & submit workitem
            string   callbackUrl  = string.Format("{0}/api/forge/callback/designautomation/grid_object_placement?id={1}&zipFileName={2}&zipFileBucketKey={3}&zipFileObjectName={4}&zipStorageId={5}&projectId={6}&folderId={7}", Credentials.GetAppSetting("FORGE_WEBHOOK_URL"), browerConnectionId, "exportedDwgs.zip", zipFileBucketKey, zipFileObjectName, (string)storageCreatedZip.data.id, outputProjectId, outputFolderId);
            WorkItem workItemSpec = new WorkItem()
            {
                ActivityId = activityName,
                Arguments  = new Dictionary <string, IArgument>()
                {
                    { "inputRvtFile", inputRevitFileArgument },
                    { "inputFamilyFile", inputFamilyFileArgument },
                    { "inputJsonFile", inputJsonArgument },
                    { "resultZipFile", outputZipFileArgument },
                    { "onComplete", new XrefTreeArgument {
                          Verb = Verb.Post, Url = callbackUrl
                      } }
                }
            };

            WorkItemStatus workItemStatus = null;

            try
            {
                workItemStatus = await _designAutomation.CreateWorkItemAsync(workItemSpec);
            }
            catch (Exception e)
            {
                string message = e.Message;
            }

            return(Ok(new { WorkItemId = workItemStatus.Id }));
        }
        public async Task <dynamic> UploadObject([FromForm] UploadFile input)
        {
            // get the uploaded file and save on the server
            var fileSavePath = Path.Combine(_env.ContentRootPath, input.fileToUpload.FileName);

            using (var stream = new FileStream(fileSavePath, FileMode.Create))
                await input.fileToUpload.CopyToAsync(stream);

            // user credentials
            Credentials = await Credentials.FromSessionAsync(base.Request.Cookies, Response.Cookies);

            // extract projectId and folderId from folderHref
            string[] hrefParams = input.folderHref.Split("/");
            string   projectId  = hrefParams[hrefParams.Length - 3];
            string   folderId   = hrefParams[hrefParams.Length - 1];

            // prepare storage
            ProjectsApi projectApi = new ProjectsApi();

            projectApi.Configuration.AccessToken = Credentials.TokenInternal;
            StorageRelationshipsTargetData       storageRelData = new StorageRelationshipsTargetData(StorageRelationshipsTargetData.TypeEnum.Folders, folderId);
            CreateStorageDataRelationshipsTarget storageTarget  = new CreateStorageDataRelationshipsTarget(storageRelData);
            CreateStorageDataRelationships       storageRel     = new CreateStorageDataRelationships(storageTarget);
            BaseAttributesExtensionObject        attributes     = new BaseAttributesExtensionObject(string.Empty, string.Empty, new JsonApiLink(string.Empty), null);
            CreateStorageDataAttributes          storageAtt     = new CreateStorageDataAttributes(input.fileToUpload.FileName, attributes);
            CreateStorageData storageData    = new CreateStorageData(CreateStorageData.TypeEnum.Objects, storageAtt, storageRel);
            CreateStorage     storage        = new CreateStorage(new JsonApiVersionJsonapi(JsonApiVersionJsonapi.VersionEnum._0), storageData);
            dynamic           storageCreated = await projectApi.PostStorageAsync(projectId, storage);

            string[] storageIdParams = ((string)storageCreated.data.id).Split('/');
            string[] bucketKeyParams = storageIdParams[storageIdParams.Length - 2].Split(':');
            string   bucketKey       = bucketKeyParams[bucketKeyParams.Length - 1];
            string   objectName      = storageIdParams[storageIdParams.Length - 1];

            // upload the file/object, which will create a new object
            ObjectsApi objects = new ObjectsApi();

            objects.Configuration.AccessToken = Credentials.TokenInternal;

            // get file size
            long fileSize = (new FileInfo(fileSavePath)).Length;

            // decide if upload direct or resumable (by chunks)
            if (fileSize > UPLOAD_CHUNK_SIZE * 1024 * 1024) // upload in chunks
            {
                long chunkSize      = 2 * 1024 * 1024;      // 2 Mb
                long numberOfChunks = (long)Math.Round((double)(fileSize / chunkSize)) + 1;

                long start = 0;
                chunkSize = (numberOfChunks > 1 ? chunkSize : fileSize);
                long   end       = chunkSize;
                string sessionId = Guid.NewGuid().ToString();

                // upload one chunk at a time
                using (BinaryReader reader = new BinaryReader(new FileStream(fileSavePath, FileMode.Open)))
                {
                    for (int chunkIndex = 0; chunkIndex < numberOfChunks; chunkIndex++)
                    {
                        string range = string.Format("bytes {0}-{1}/{2}", start, end, fileSize);

                        long         numberOfBytes = chunkSize + 1;
                        byte[]       fileBytes     = new byte[numberOfBytes];
                        MemoryStream memoryStream  = new MemoryStream(fileBytes);
                        reader.BaseStream.Seek((int)start, SeekOrigin.Begin);
                        int count = reader.Read(fileBytes, 0, (int)numberOfBytes);
                        memoryStream.Write(fileBytes, 0, (int)numberOfBytes);
                        memoryStream.Position = 0;

                        await objects.UploadChunkAsync(bucketKey, objectName, (int)numberOfBytes, range, sessionId, memoryStream);

                        start     = end + 1;
                        chunkSize = ((start + chunkSize > fileSize) ? fileSize - start - 1 : chunkSize);
                        end       = start + chunkSize;
                    }
                }
            }
            else // upload in a single call
            {
                using (StreamReader streamReader = new StreamReader(fileSavePath))
                {
                    await objects.UploadObjectAsync(bucketKey, objectName, (int)streamReader.BaseStream.Length, streamReader.BaseStream, "application/octet-stream");
                }
            }

            // cleanup
            string fileName = input.fileToUpload.FileName;

            System.IO.File.Delete(fileSavePath);

            // check if file already exists...
            FoldersApi folderApi = new FoldersApi();

            folderApi.Configuration.AccessToken = Credentials.TokenInternal;
            var filesInFolder = await folderApi.GetFolderContentsAsync(projectId, folderId);

            string itemId = string.Empty;

            foreach (KeyValuePair <string, dynamic> item in new DynamicDictionaryItems(filesInFolder.data))
            {
                if (item.Value.attributes.displayName == fileName)
                {
                    itemId = item.Value.id; // this means a file with same name is already there, so we'll create a new version
                }
            }
            // now decide whether create a new item or new version
            if (string.IsNullOrWhiteSpace(itemId))
            {
                // create a new item
                BaseAttributesExtensionObject        baseAttribute                   = new BaseAttributesExtensionObject(projectId.StartsWith("a.") ? "items:autodesk.core:File" : "items:autodesk.bim360:File", "1.0");
                CreateItemDataAttributes             createItemAttributes            = new CreateItemDataAttributes(fileName, baseAttribute);
                CreateItemDataRelationshipsTipData   createItemRelationshipsTipData  = new CreateItemDataRelationshipsTipData(CreateItemDataRelationshipsTipData.TypeEnum.Versions, CreateItemDataRelationshipsTipData.IdEnum._1);
                CreateItemDataRelationshipsTip       createItemRelationshipsTip      = new CreateItemDataRelationshipsTip(createItemRelationshipsTipData);
                StorageRelationshipsTargetData       storageTargetData               = new StorageRelationshipsTargetData(StorageRelationshipsTargetData.TypeEnum.Folders, folderId);
                CreateStorageDataRelationshipsTarget createStorageRelationshipTarget = new CreateStorageDataRelationshipsTarget(storageTargetData);
                CreateItemDataRelationships          createItemDataRelationhips      = new CreateItemDataRelationships(createItemRelationshipsTip, createStorageRelationshipTarget);
                CreateItemData createItemData = new CreateItemData(CreateItemData.TypeEnum.Items, createItemAttributes, createItemDataRelationhips);
                BaseAttributesExtensionObject      baseAttExtensionObj = new BaseAttributesExtensionObject(projectId.StartsWith("a.") ? "versions:autodesk.core:File" : "versions:autodesk.bim360:File", "1.0");
                CreateStorageDataAttributes        storageDataAtt      = new CreateStorageDataAttributes(fileName, baseAttExtensionObj);
                CreateItemRelationshipsStorageData createItemRelationshipsStorageData = new CreateItemRelationshipsStorageData(CreateItemRelationshipsStorageData.TypeEnum.Objects, storageCreated.data.id);
                CreateItemRelationshipsStorage     createItemRelationshipsStorage     = new CreateItemRelationshipsStorage(createItemRelationshipsStorageData);
                CreateItemRelationships            createItemRelationship             = new CreateItemRelationships(createItemRelationshipsStorage);
                CreateItemIncluded includedVersion = new CreateItemIncluded(CreateItemIncluded.TypeEnum.Versions, CreateItemIncluded.IdEnum._1, storageDataAtt, createItemRelationship);
                CreateItem         createItem      = new CreateItem(new JsonApiVersionJsonapi(JsonApiVersionJsonapi.VersionEnum._0), createItemData, new List <CreateItemIncluded>()
                {
                    includedVersion
                });

                ItemsApi itemsApi = new ItemsApi();
                itemsApi.Configuration.AccessToken = Credentials.TokenInternal;
                var newItem = await itemsApi.PostItemAsync(projectId, createItem);

                return(newItem);
            }
            else
            {
                // create a new version
                BaseAttributesExtensionObject          attExtensionObj              = new BaseAttributesExtensionObject(projectId.StartsWith("a.") ? "versions:autodesk.core:File" : "versions:autodesk.bim360:File", "1.0");
                CreateStorageDataAttributes            storageDataAtt               = new CreateStorageDataAttributes(fileName, attExtensionObj);
                CreateVersionDataRelationshipsItemData dataRelationshipsItemData    = new CreateVersionDataRelationshipsItemData(CreateVersionDataRelationshipsItemData.TypeEnum.Items, itemId);
                CreateVersionDataRelationshipsItem     dataRelationshipsItem        = new CreateVersionDataRelationshipsItem(dataRelationshipsItemData);
                CreateItemRelationshipsStorageData     itemRelationshipsStorageData = new CreateItemRelationshipsStorageData(CreateItemRelationshipsStorageData.TypeEnum.Objects, storageCreated.data.id);
                CreateItemRelationshipsStorage         itemRelationshipsStorage     = new CreateItemRelationshipsStorage(itemRelationshipsStorageData);
                CreateVersionDataRelationships         dataRelationships            = new CreateVersionDataRelationships(dataRelationshipsItem, itemRelationshipsStorage);
                CreateVersionData versionData    = new CreateVersionData(CreateVersionData.TypeEnum.Versions, storageDataAtt, dataRelationships);
                CreateVersion     newVersionData = new CreateVersion(new JsonApiVersionJsonapi(JsonApiVersionJsonapi.VersionEnum._0), versionData);

                VersionsApi versionsApis = new VersionsApi();
                versionsApis.Configuration.AccessToken = Credentials.TokenInternal;
                dynamic newVersion = await versionsApis.PostVersionAsync(projectId, newVersionData);

                return(newVersion);
            }
        }
Example #5
0
        [Route("api/forge/clientid")] // see Web.Config FORGE_CALLBACK_URL variable
        public static async Task <string> GetClientIdAsync()
        {
            string clientIdKey = await Credentials.GetAppSetting("FORGE_CLIENT_ID");

            return(clientIdKey);
        }