From d3f199cd00e10a89e4c7366a149e07e0e9a0023e Mon Sep 17 00:00:00 2001 From: wanli Date: Mon, 14 Nov 2022 09:41:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5forge=E6=9C=83=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=88=B0=E7=9A=84api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ModelDerivativeController.cs | 55 +++++++ .../ApiControllers/OAuthController.cs | 67 ++++++++ .../ApiControllers/OSSController.cs | 148 ++++++++++++++++++ FrontendWebApi/Properties/launchSettings.json | 24 +-- 4 files changed, 284 insertions(+), 10 deletions(-) create mode 100644 FrontendWebApi/ApiControllers/ModelDerivativeController.cs create mode 100644 FrontendWebApi/ApiControllers/OAuthController.cs create mode 100644 FrontendWebApi/ApiControllers/OSSController.cs diff --git a/FrontendWebApi/ApiControllers/ModelDerivativeController.cs b/FrontendWebApi/ApiControllers/ModelDerivativeController.cs new file mode 100644 index 0000000..dc32d77 --- /dev/null +++ b/FrontendWebApi/ApiControllers/ModelDerivativeController.cs @@ -0,0 +1,55 @@ +using Autodesk.Forge.Model; +using Autodesk.Forge; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace FrontendWebApi.ApiControllers +{ + public class ModelDerivativeController : ControllerBase //MyBaseApiController//Controller + { + /// + /// Start the translation job for a give bucketKey/objectName + /// + /// + /// + [HttpPost] + [Route("api/forge/modelderivative/jobs")] + public async Task TranslateObject([FromBody] TranslateObjectModel objModel) + { + dynamic oauth = await OAuthController.GetInternalAsync(); + + // prepare the payload + List outputs = new List() + { + new JobPayloadItem( + JobPayloadItem.TypeEnum.Svf, + new List() + { + JobPayloadItem.ViewsEnum._2d, + JobPayloadItem.ViewsEnum._3d + }) + }; + JobPayload job; + job = new JobPayload(new JobPayloadInput(objModel.objectName), new JobPayloadOutput(outputs)); + + // start the translation + DerivativesApi derivative = new DerivativesApi(); + derivative.Configuration.AccessToken = oauth.access_token; + dynamic jobPosted = await derivative.TranslateAsync(job); + return jobPosted; + } + + /// + /// Model for TranslateObject method + /// + public class TranslateObjectModel + { + public string bucketKey { get; set; } + public string objectName { get; set; } + } + } +} diff --git a/FrontendWebApi/ApiControllers/OAuthController.cs b/FrontendWebApi/ApiControllers/OAuthController.cs new file mode 100644 index 0000000..61b7f1f --- /dev/null +++ b/FrontendWebApi/ApiControllers/OAuthController.cs @@ -0,0 +1,67 @@ +using Autodesk.Forge; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using System; + +namespace FrontendWebApi.ApiControllers +{ + public class OAuthController : ControllerBase //MyBaseApiController//Controller + { + + + private static dynamic InternalToken { get; set; } + private static dynamic PublicToken { get; set; } + + /// + /// Get access token with public (viewables:read) scope + /// + [HttpGet] + [Route("api/forge/oauth/token")] + public async Task GetPublicAsync() + { + if (PublicToken == null || PublicToken.ExpiresAt < DateTime.UtcNow) + { + PublicToken = await Get2LeggedTokenAsync(new Scope[] { Scope.ViewablesRead }); + PublicToken.ExpiresAt = DateTime.UtcNow.AddSeconds(PublicToken.expires_in); + } + return PublicToken; + } + + /// + /// Get access token with internal (write) scope + /// + public static async Task GetInternalAsync() + { + if (InternalToken == null || InternalToken.ExpiresAt < DateTime.UtcNow) + { + InternalToken = await Get2LeggedTokenAsync(new Scope[] { Scope.BucketCreate, Scope.BucketRead, Scope.BucketDelete, Scope.DataRead, Scope.DataWrite, Scope.DataCreate, Scope.CodeAll }); + InternalToken.ExpiresAt = DateTime.UtcNow.AddSeconds(InternalToken.expires_in); + } + + return InternalToken; + } + + /// + /// Get the access token from Autodesk + /// + private static async Task Get2LeggedTokenAsync(Scope[] scopes) + { + TwoLeggedApi oauth = new TwoLeggedApi(); + string grantType = "client_credentials"; + dynamic bearer = await oauth.AuthenticateAsync( + "TA3hqsFfzQbNOUXKpldKUKSew4SJ21w5", + "D002f92d839144f8", + grantType, + scopes); + return bearer; + } + + /// + /// Reads appsettings from web.config + /// + public static string GetAppSetting(string settingKey) + { + return Environment.GetEnvironmentVariable(settingKey).Trim(); + } + } +} diff --git a/FrontendWebApi/ApiControllers/OSSController.cs b/FrontendWebApi/ApiControllers/OSSController.cs new file mode 100644 index 0000000..0dc1458 --- /dev/null +++ b/FrontendWebApi/ApiControllers/OSSController.cs @@ -0,0 +1,148 @@ +using Autodesk.Forge.Model; +using Autodesk.Forge; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using System.IO; + +namespace FrontendWebApi.ApiControllers +{ + public class OSSController : ControllerBase //MyBaseApiController//Controller + { + private IWebHostEnvironment _env; + public OSSController(IWebHostEnvironment env) { _env = env; } + string id = "TA3hqsFfzQbNOUXKpldKUKSew4SJ21w5"; + public string ClientId { get { return id.ToLower(); } } + + /// + /// Return list of buckets (id=#) or list of objects (id=bucketKey) + /// + [HttpGet] + [Route("api/forge/oss/buckets")] + public async Task> GetOSSAsync(string id) + { + IList nodes = new List(); + dynamic oauth = await OAuthController.GetInternalAsync(); + + if (id == "#") // root + { + // in this case, let's return all buckets + BucketsApi appBckets = new BucketsApi(); + appBckets.Configuration.AccessToken = oauth.access_token; + + // to simplify, let's return only the first 100 buckets + dynamic buckets = await appBckets.GetBucketsAsync("US", 100); + foreach (KeyValuePair bucket in new DynamicDictionaryItems(buckets.items)) + { + nodes.Add(new TreeNode(bucket.Value.bucketKey, bucket.Value.bucketKey.Replace(ClientId + "-", string.Empty), "bucket", true)); + } + } + else + { + // as we have the id (bucketKey), let's return all + ObjectsApi objects = new ObjectsApi(); + objects.Configuration.AccessToken = oauth.access_token; + var objectsList = await objects.GetObjectsAsync(id, 100); + foreach (KeyValuePair objInfo in new DynamicDictionaryItems(objectsList.items)) + { + nodes.Add(new TreeNode(Base64Encode((string)objInfo.Value.objectId), + objInfo.Value.objectKey, "object", false)); + } + } + return nodes; + } + + /// + /// Model data for jsTree used on GetOSSAsync + /// + public class TreeNode + { + public TreeNode(string id, string text, string type, bool children) + { + this.id = id; + this.text = text; + this.type = type; + this.children = children; + } + + public string id { get; set; } + public string text { get; set; } + public string type { get; set; } + public bool children { get; set; } + } + + /// + /// Create a new bucket + /// + [HttpPost] + [Route("api/forge/oss/buckets")] + public async Task CreateBucket([FromBody] CreateBucketModel bucket) + { + BucketsApi buckets = new BucketsApi(); + dynamic token = await OAuthController.GetInternalAsync(); + buckets.Configuration.AccessToken = token.access_token; + PostBucketsPayload bucketPayload = new PostBucketsPayload(string.Format("{0}-{1}", ClientId, bucket.bucketKey.ToLower()), null, + PostBucketsPayload.PolicyKeyEnum.Transient); + return await buckets.CreateBucketAsync(bucketPayload, "US"); + } + + /// + /// Input model for CreateBucket method + /// + public class CreateBucketModel + { + public string bucketKey { get; set; } + } + + /// + /// Receive a file from the client and upload to the bucket + /// + /// + [HttpPost] + [Route("api/forge/oss/objects")] + public async Task UploadObject([FromForm] UploadFile input) + { + // save the file on the server + var fileSavePath = Path.Combine(_env.WebRootPath, Path.GetFileName(input.fileToUpload.FileName)); + using (var stream = new FileStream(fileSavePath, FileMode.Create)) + await input.fileToUpload.CopyToAsync(stream); + + + // get the bucket... + dynamic oauth = await OAuthController.GetInternalAsync(); + ObjectsApi objects = new ObjectsApi(); + objects.Configuration.AccessToken = oauth.access_token; + + // upload the file/object, which will create a new object + dynamic uploadedObj; + using (StreamReader streamReader = new StreamReader(fileSavePath)) + { + uploadedObj = await objects.UploadObjectAsync(input.bucketKey, + Path.GetFileName(input.fileToUpload.FileName), (int)streamReader.BaseStream.Length, streamReader.BaseStream, + "application/octet-stream"); + } + + // cleanup + System.IO.File.Delete(fileSavePath); + + return uploadedObj; + } + + public class UploadFile + { + public string bucketKey { get; set; } + public IFormFile fileToUpload { get; set; } + } + + /// + /// Base64 enconde a string + /// + public static string Base64Encode(string plainText) + { + var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); + return System.Convert.ToBase64String(plainTextBytes); + } + } +} diff --git a/FrontendWebApi/Properties/launchSettings.json b/FrontendWebApi/Properties/launchSettings.json index 5c10218..7d29894 100644 --- a/FrontendWebApi/Properties/launchSettings.json +++ b/FrontendWebApi/Properties/launchSettings.json @@ -1,13 +1,4 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:3604", - "sslPort": 0 - } - }, - "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "IIS Express": { "commandName": "IISExpress", @@ -22,9 +13,22 @@ "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", - "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation", + "FORGE_CALLBACK_URL": "http://localhost:3000/api/forge/callback/oauth", + "FORGE_CLIENT_ID": "TA3hqsFfzQbNOUXKpldKUKSew4SJ21w5", + "FORGE_CLIENT_SECRET": "D002f92d839144f8", + "ASPNETCORE_URLS": "http://localhost:5500" }, "applicationUrl": "https://localhost:5001;http://localhost:5000" } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:3604", + "sslPort": 0 + } } } \ No newline at end of file