diff --git a/.gitignore b/.gitignore index 7338427..835bb66 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,8 @@ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff: +.idea +.idea/ .idea/**/workspace.xml .idea/**/tasks.xml .idea/dictionaries @@ -65,3 +67,5 @@ crashlytics.properties crashlytics-build.properties fabric.properties .idea/ + +*.cmd \ No newline at end of file diff --git a/dm/bucket.go b/dm/bucket.go index 5d5c627..be02103 100644 --- a/dm/bucket.go +++ b/dm/bucket.go @@ -8,7 +8,7 @@ import ( "net/http" "strconv" - "github.com/apprentice3d/forge-api-go-client/oauth" + "forge-api-go-client/oauth" ) // BucketAPI holds the necessary data for making Bucket related calls to Forge Data Management service diff --git a/dm/bucket_test.go b/dm/bucket_test.go index 6cb05eb..d4a9c6c 100644 --- a/dm/bucket_test.go +++ b/dm/bucket_test.go @@ -2,7 +2,7 @@ package dm_test import ( "fmt" - "github.com/apprentice3d/forge-api-go-client/dm" + "forge-api-go-client/dm" "log" "os" "testing" diff --git a/dm/hubs.go b/dm/hubs.go index 97b5cb7..3b9a3e5 100644 --- a/dm/hubs.go +++ b/dm/hubs.go @@ -1,47 +1,204 @@ package dm -// -//type Hubs struct { -// Data []Content `json:"data,omitempty"` -// JsonApi JsonAPI `json:"jsonapi,omitempty"` -// Links Link `json:"links,omitempty"` -//} -// -//type JsonAPI struct { -// Version string `json:"version,omitempty"` -//} -// -//type Link struct { -// Self struct { -// Href string `json:"href,omitempty"` -// } `json:"self,omitempty"` -//} -// -//type Content struct { -// Relationships struct { -// Projects Project `json:"projects,omitempty"` -// } `json:"relationships,omitempty"` -// Attributes Attribute `json:"attributes,omitempty"` -// Type string `json:"type,omitempty"` -// Id string `json:"id,omitempty"` -// Links Link `json:"links,omitempty"` -//} -// -//type Project struct { -// Links struct { -// Related struct { -// Href string `json:"href,omitempty"` -// } `json:"related,omitempty"` -// } `json:"links,omitempty"` -//} -// -//type Attribute struct { -// Name string `json:"name,omitempty"` -// Extension struct { -// Data map[string]interface{} `json:"data,omitempty"` -// Version string `json:"version,omitempty"` -// Type string `json:"type,omitempty"` -// Schema struct { -// Href string `json:"href,omitempty"` -// } `json:"schema,omitempty"` -// } `json:"extension,omitempty"` -//} + +import ( + "encoding/json" + "errors" + "fmt" + "forge-api-go-client/oauth" + "io/ioutil" + "net/http" + "strconv" +) + +type HubsAPI struct { + oauth.TwoLeggedAuth + HubsAPIPath string +} + +func NewHubsAPIWithCredentials(ClientID, ClientSecret string) HubsAPI { + return HubsAPI{ + TwoLeggedAuth: oauth.NewTwoLeggedClient(ClientID, ClientSecret), + HubsAPIPath: "/project/v1/hubs", + } +} + +type Hubs struct { + Data []Content `json:"data,omitempty"` + JsonApi JsonAPI `json:"jsonapi,omitempty"` + Links Link `json:"links,omitempty"` +} + +type JsonAPI struct { + Version string `json:"version,omitempty"` +} + +type Link struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` +} + +type Content struct { + Relationships struct { + Projects Project `json:"projects,omitempty"` + } `json:"relationships,omitempty"` + Attributes Attribute `json:"attributes,omitempty"` + Type string `json:"type,omitempty"` + Id string `json:"id,omitempty"` + Links Link `json:"links,omitempty"` +} + +type Project struct { + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` +} + +type Attribute struct { + Name string `json:"name,omitempty"` + Extension struct { + Data map[string]interface{} `json:"data,omitempty"` + Version string `json:"version,omitempty"` + Type string `json:"type,omitempty"` + Schema struct { + Href string `json:"href,omitempty"` + } `json:"schema,omitempty"` + } `json:"extension,omitempty"` +} + +type Projects struct { + Jsonapi struct { + Version string `json:"version,omitempty"` + } `json:"jsonapi,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Data []struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + Attributes struct { + Name string `json:"name,omitempty"` + Extension struct { + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + Schema struct { + Href string `json:"href,omitempty"` + } `json:"schema,omitempty"` + Data struct { + } `json:"data,omitempty"` + } `json:"extension,omitempty"` + } `json:"attributes,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Relationships struct { + Hub struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"hub,omitempty"` + RootFolder struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Meta struct { + Link struct { + Href string `json:"href,omitempty"` + } `json:"link,omitempty"` + } `json:"meta,omitempty"` + } `json:"rootFolder,omitempty"` + } `json:"relationships,omitempty"` + } `json:"data,omitempty"` +} + + +func (api *HubsAPI) GetHubs() (result Hubs, err error){ + bearer, err := api.Authenticate("data:read") + if err != nil { + return Hubs{}, err + } + + path := api.Host + api.HubsAPIPath + result, err = listHubs(path, bearer.AccessToken) + return result, err +} + +func listHubs(path string, token string) (result Hubs, err error) { + task := http.Client{} + + req, err := http.NewRequest("GET", path, nil) + if err != nil { + return Hubs{}, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + + response, err := task.Do(req) + if err != nil { + return Hubs{}, err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + content, _ := ioutil.ReadAll(response.Body) + err = errors.New("[" + strconv.Itoa(response.StatusCode) + "] " + string(content)) + return Hubs{}, err + } + + decoder := json.NewDecoder(response.Body) + err = decoder.Decode(&result) + return result, nil +} + +func (api *HubsAPI) GetHubProjects(hubId string) (result Projects, err error){ + bearer, err := api.Authenticate("data:read") + if err != nil { + return Projects{}, err + } + + path := fmt.Sprintf("%s/%s/%s/projects", api.Host, api.HubsAPIPath, hubId) + result, err = getHubProjects(path, bearer.AccessToken) + return result, err +} + +func getHubProjects(path string, token string) (result Projects, err error) { + task := http.Client{} + + req, err := http.NewRequest("GET", path, nil) + if err != nil { + return Projects{}, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + + response, err := task.Do(req) + if err != nil { + return Projects{}, err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + content, _ := ioutil.ReadAll(response.Body) + err = errors.New("[" + strconv.Itoa(response.StatusCode) + "] " + string(content)) + return Projects{}, err + } + + decoder := json.NewDecoder(response.Body) + err = decoder.Decode(&result) + return result, nil +} diff --git a/dm/hubs_test.go b/dm/hubs_test.go new file mode 100644 index 0000000..3baeee1 --- /dev/null +++ b/dm/hubs_test.go @@ -0,0 +1,37 @@ +package dm_test + +import ( + "fmt" + "forge-api-go-client/dm" + "os" + "testing" +) + +func TestHubsAPI_ListHubs(t *testing.T) { + clientID := os.Getenv("FORGE_CLIENT_ID") + clientSecret := os.Getenv("FORGE_CLIENT_SECRET") + + fmt.Printf("Using envs: %s\n%s\n", clientID, clientSecret) + + hubsAPI := dm.NewHubsAPIWithCredentials(clientID, clientSecret) + + t.Run("List Hubs", func(t *testing.T) { + hubs, err := hubsAPI.GetHubs() + if err!=nil{ + t.Fatalf("Failed to list hubs: %s\n", err.Error()) + } + + if len(hubs.Data) == 0 { + t.Fatalf("Failed to list hubs. No hubs retreived.") + } + + projects, err := hubsAPI.GetHubProjects(hubs.Data[0].Id) + if err!=nil{ + t.Fatalf("Failed to list hub '%s' projects: %s\n", hubs.Data[0].Id, err.Error()) + } + + if len(projects.Data) == 0 { + t.Fatalf("Failed to list hub projects. No projects retreived or failed to unmarshal.") + } + }) +} \ No newline at end of file diff --git a/dm/object_test.go b/dm/object_test.go index d048196..6af8e2d 100644 --- a/dm/object_test.go +++ b/dm/object_test.go @@ -4,8 +4,7 @@ import ( "io/ioutil" "os" "testing" - - "github.com/apprentice3d/forge-api-go-client/dm" + "forge-api-go-client/dm" ) func TestBucketAPI_ListObjects(t *testing.T) { diff --git a/dm/projects.go b/dm/projects.go new file mode 100644 index 0000000..462dd8c --- /dev/null +++ b/dm/projects.go @@ -0,0 +1,478 @@ +package dm + +import ( + "encoding/json" + "errors" + "fmt" + "forge-api-go-client/oauth" + "io" + "log" + "net/http" + "strconv" + "time" +) + +type FolderContents struct { + Jsonapi struct { + Version string `json:"version,omitempty"` + } `json:"jsonapi,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Data []struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + Attributes struct { + DisplayName string `json:"displayName,omitempty"` + CreateTime time.Time `json:"createTime,omitempty"` + CreateUserID string `json:"createUserId,omitempty"` + CreateUserName string `json:"createUserName,omitempty"` + LastModifiedTime time.Time `json:"lastModifiedTime,omitempty"` + LastModifiedUserID string `json:"lastModifiedUserId,omitempty"` + LastModifiedUserName string `json:"lastModifiedUserName,omitempty"` + Extension struct { + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + Schema struct { + Href string `json:"href,omitempty"` + } `json:"schema,omitempty"` + Data struct { + } `json:"data,omitempty"` + } `json:"extension,omitempty"` + } `json:"attributes,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Relationships struct { + Tip struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"tip,omitempty"` + Versions struct { + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"versions,omitempty"` + Parent struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"parent,omitempty"` + Refs struct { + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"refs,omitempty"` + } `json:"relationships,omitempty"` + } `json:"data,omitempty"` + Included []struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + Attributes struct { + Name string `json:"name,omitempty"` + DisplayName string `json:"displayName,omitempty"` + CreateTime time.Time `json:"createTime,omitempty"` + CreateUserID string `json:"createUserId,omitempty"` + CreateUserName string `json:"createUserName,omitempty"` + LastModifiedTime time.Time `json:"lastModifiedTime,omitempty"` + LastModifiedUserID string `json:"lastModifiedUserId,omitempty"` + LastModifiedUserName string `json:"lastModifiedUserName,omitempty"` + VersionNumber int `json:"versionNumber,omitempty"` + MimeType string `json:"mimeType,omitempty"` + FileType string `json:"fileType,omitempty"` + StorageSize uint64 `json:"storageSize,omitempty"` + Extension struct { + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + Schema struct { + Href string `json:"href,omitempty"` + } `json:"schema,omitempty"` + Data struct { + } `json:"data,omitempty"` + } `json:"extension,omitempty"` + } `json:"attributes,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Relationships struct { + Item struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"item,omitempty"` + Refs struct { + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"refs,omitempty"` + Derivatives struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Meta struct { + Link struct { + Href string `json:"href,omitempty"` + } `json:"link,omitempty"` + } `json:"meta,omitempty"` + } `json:"derivatives,omitempty"` + Thumbnails struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Meta struct { + Link struct { + Href string `json:"href,omitempty"` + } `json:"link,omitempty"` + } `json:"meta,omitempty"` + } `json:"thumbnails,omitempty"` + Storage struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Meta struct { + Link struct { + Href string `json:"href,omitempty"` + } `json:"link,omitempty"` + } `json:"meta,omitempty"` + } `json:"storage,omitempty"` + } `json:"relationships,omitempty"` + } `json:"included,omitempty"` +} + +type ItemData struct { + Jsonapi struct { + Version string `json:"version,omitempty"` + } `json:"jsonapi,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + Attributes struct { + DisplayName string `json:"displayName,omitempty"` + CreateTime time.Time `json:"createTime,omitempty"` + CreateUserID string `json:"createUserId,omitempty"` + CreateUserName string `json:"createUserName,omitempty"` + LastModifiedTime time.Time `json:"lastModifiedTime,omitempty"` + LastModifiedUserID string `json:"lastModifiedUserId,omitempty"` + LastModifiedUserName string `json:"lastModifiedUserName,omitempty"` + Extension struct { + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + Schema struct { + Href string `json:"href,omitempty"` + } `json:"schema,omitempty"` + Data struct { + } `json:"data,omitempty"` + } `json:"extension,omitempty"` + } `json:"attributes,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Relationships struct { + Tip struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"tip,omitempty"` + Versions struct { + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"versions,omitempty"` + Parent struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"parent,omitempty"` + Refs struct { + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"refs,omitempty"` + } `json:"relationships,omitempty"` + } `json:"data,omitempty"` + Included []struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + Attributes struct { + Name string `json:"name,omitempty"` + DisplayName string `json:"displayName,omitempty"` + CreateTime time.Time `json:"createTime,omitempty"` + CreateUserID string `json:"createUserId,omitempty"` + CreateUserName string `json:"createUserName,omitempty"` + LastModifiedTime time.Time `json:"lastModifiedTime,omitempty"` + LastModifiedUserID string `json:"lastModifiedUserId,omitempty"` + LastModifiedUserName string `json:"lastModifiedUserName,omitempty"` + VersionNumber int `json:"versionNumber,omitempty"` + MimeType string `json:"mimeType,omitempty"` + FileType string `json:"fileType,omitempty"` + StorageSize uint64 `json:"storageSize,omitempty"` + Extension struct { + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + Schema struct { + Href string `json:"href,omitempty"` + } `json:"schema,omitempty"` + Data struct { + } `json:"data,omitempty"` + } `json:"extension,omitempty"` + } `json:"attributes,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"links,omitempty"` + Relationships struct { + Item struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Links struct { + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"item,omitempty"` + Refs struct { + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + Related struct { + Href string `json:"href,omitempty"` + } `json:"related,omitempty"` + } `json:"links,omitempty"` + } `json:"refs,omitempty"` + Derivatives struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Meta struct { + Link struct { + Href string `json:"href,omitempty"` + } `json:"link,omitempty"` + } `json:"meta,omitempty"` + } `json:"derivatives,omitempty"` + Thumbnails struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Meta struct { + Link struct { + Href string `json:"href,omitempty"` + } `json:"link,omitempty"` + } `json:"meta,omitempty"` + } `json:"thumbnails,omitempty"` + Storage struct { + Data struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + } `json:"data,omitempty"` + Meta struct { + Link struct { + Href string `json:"href,omitempty"` + } `json:"link,omitempty"` + } `json:"meta,omitempty"` + } `json:"storage,omitempty"` + } `json:"relationships,omitempty"` + } `json:"included,omitempty"` +} + +type ProjectsAPI struct { + oauth.TwoLeggedAuth + ProjectsAPIPath string +} + +func NewProjectsAPIWithCredentials(ClientID, ClientSecret, ProjectId string) ProjectsAPI { + return ProjectsAPI{ + TwoLeggedAuth: oauth.NewTwoLeggedClient(ClientID, ClientSecret), + ProjectsAPIPath: fmt.Sprintf("/data/v1/projects/%s/", ProjectId), // projects/:project_id/folders/:folder_id/ + } +} + +func (api *ProjectsAPI) GetFolderContents(FolderId string) (result *FolderContents, err error){ + //bearer, err := api.Authenticate("data:read") + bearer, err := api.AuthenticateIfNecessary("data:read") + if err != nil { + return nil, err + } + + path := fmt.Sprintf("%s%sfolders/%s", api.Host, api.ProjectsAPIPath, FolderId) + result, err = getFolderContents(path, bearer.AccessToken) + return result, err +} + +func getFolderContents(path string, token string) (result *FolderContents, err error) { + task := http.Client{} + + req, err := http.NewRequest("GET", path+"/contents", nil) + + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + + response, err := task.Do(req) + if err != nil { + return nil, err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + err = errors.New(strconv.Itoa(response.StatusCode)) + return nil, err + } + + decoder := json.NewDecoder(response.Body) + err = decoder.Decode(&result) + return result, nil +} + +func (api *ProjectsAPI) GetItemData(itemId string) (result *ItemData, err error){ + //bearer, err := api.Authenticate("data:read") + bearer, err := api.AuthenticateIfNecessary("data:read") + if err != nil { + return nil, err + } + + path := fmt.Sprintf("%s%sitems/%s", api.Host, api.ProjectsAPIPath, itemId) + result, err = getItemData(path, bearer.AccessToken) + return result, err +} + +func getItemData(path string, token string) (result *ItemData, err error) { + task := http.Client{} + + req, err := http.NewRequest("GET", path, nil) + + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + + response, err := task.Do(req) + if err != nil { + log.Printf("Error at request: %v", err.Error()) + return nil, err + } + + if response.StatusCode != http.StatusOK { + err = errors.New(strconv.Itoa(response.StatusCode)) + log.Printf("Error at request: %v", err.Error()) + return nil, err + } + + defer response.Body.Close() + decoder := json.NewDecoder(response.Body) + err = decoder.Decode(&result) + return result, nil +} + +func (api *ProjectsAPI) GetItemReader(itemStorageLink string) (result *io.ReadCloser, err error) { + bearer, err := api.AuthenticateIfNecessary("data:read") + if err != nil { + return nil, err + } + + result, err = getItemReader(itemStorageLink, bearer.AccessToken) + return result, err +} + +func getItemReader(link string, token string) (*io.ReadCloser, error) { + task := http.Client{} + + req, err := http.NewRequest("GET", link, nil) + + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + + response, err := task.Do(req) + if err != nil { + log.Printf("Error at request: %v", err.Error()) + return nil, err + } + + if response.StatusCode != http.StatusOK { + err = errors.New(strconv.Itoa(response.StatusCode)) + log.Printf("Error at request: %v", err.Error()) + return nil, err + } + + return &response.Body, nil +} \ No newline at end of file diff --git a/dm/projects_test.go b/dm/projects_test.go new file mode 100644 index 0000000..0409e91 --- /dev/null +++ b/dm/projects_test.go @@ -0,0 +1,50 @@ +package dm + +import ( + "fmt" + "os" + "testing" +) + +func TestProjectsAPI_GetFolderContents(t *testing.T) { + clientID := os.Getenv("FORGE_CLIENT_ID") + clientSecret := os.Getenv("FORGE_CLIENT_SECRET") + + fmt.Printf("Using envs: %s\n%s\n", clientID, clientSecret) + + t.Run("List Hubs", func(t *testing.T) { + hubsAPI := NewHubsAPIWithCredentials(clientID, clientSecret) + hubs, err := hubsAPI.GetHubs() + if err!=nil{ + t.Fatalf("Failed to list hubs: %s\n", err.Error()) + } + + if len(hubs.Data) == 0 { + t.Fatalf("Failed to list hubs. No hubs retreived.") + } + + projects, err := hubsAPI.GetHubProjects(hubs.Data[0].Id) + if err!=nil{ + t.Fatalf("Failed to list hub '%s' projects: %s\n", hubs.Data[0].Id, err.Error()) + } + + if len(projects.Data) == 0 { + t.Fatalf("Failed to list hub projects. No projects retreived or failed to unmarshal.") + } + + projectsAPI := NewProjectsAPIWithCredentials(clientID, clientSecret, projects.Data[0].ID) + + _,err = projectsAPI.GetFolderContents(projects.Data[0].Relationships.RootFolder.Data.ID) + if err != nil { + t.Fatalf("Failed to get folders: %v", err.Error()) + } + _,err = projectsAPI.GetFolderContents(projects.Data[0].Relationships.RootFolder.Data.ID) + if err != nil { + t.Fatalf("Failed to get folders: %v", err.Error()) + } + _,err = projectsAPI.GetFolderContents(projects.Data[0].Relationships.RootFolder.Data.ID) + if err != nil { + t.Fatalf("Failed to get folders: %v", err.Error()) + } + }) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0edc028 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module forge-api-go-client + +go 1.14 + +replace forge-api-go-client => ./ diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2371161 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/BUCKU/forge-api-go-client v0.1.0 h1:7iMtb0gzMgxPiIfog1L5O8DcVZJvXUmmC8/liSDytyg= +github.com/BUCKU/forge-api-go-client v0.1.0/go.mod h1:5/HRneXXt+Y/sSqrZu/414f6y+O9Tr8Arnfz2D5gP9w= +github.com/apprentice3d/forge-api-go-client v0.1.0 h1:BI6U0GUIbp53r8WMgQ3qt5R6cbUvUfTCjWKFf3KdcvI= +github.com/apprentice3d/forge-api-go-client v0.1.0/go.mod h1:zco+aF8YQfGGXy2anwF73XS9u0THEFgW57i4I3bF9ic= diff --git a/oauth/informational_test.go b/oauth/informational_test.go index deef933..00eb283 100644 --- a/oauth/informational_test.go +++ b/oauth/informational_test.go @@ -2,7 +2,7 @@ package oauth_test import ( "fmt" - "github.com/apprentice3d/forge-api-go-client/oauth" + "forge-api-go-client/oauth" ) //TODO: enable it after having set up a pipeline for auto-creating a 3-legged oauth token diff --git a/oauth/three_legged_test.go b/oauth/three_legged_test.go index 2c5084d..971b8d6 100644 --- a/oauth/three_legged_test.go +++ b/oauth/three_legged_test.go @@ -1,7 +1,7 @@ package oauth_test import ( - "github.com/apprentice3d/forge-api-go-client/oauth" + "forge-api-go-client/oauth" "os" "testing" ) diff --git a/oauth/two_legged.go b/oauth/two_legged.go index 07755a3..fcb0c5d 100644 --- a/oauth/two_legged.go +++ b/oauth/two_legged.go @@ -5,14 +5,18 @@ import ( "encoding/json" "errors" "io/ioutil" + "log" "net/http" "net/url" "strconv" + "time" ) // TwoLeggedAuth struct holds data necessary for making requests in 2-legged context type TwoLeggedAuth struct { AuthData + token Bearer + expires time.Time } // TwoLeggedAuthenticator interface defines the method necessary to qualify as 2-legged authenticator @@ -29,11 +33,30 @@ func NewTwoLeggedClient(clientID, clientSecret string) TwoLeggedAuth { "https://developer.api.autodesk.com", "/authentication/v1", }, + Bearer{}, + time.Time{}, } } +func (a *TwoLeggedAuth) AuthenticateIfNecessary(scope string) (bearer Bearer, err error){ + if a.token.AccessToken != "" { + now := time.Now() + + if now.After(a.expires){ + log.Printf("Authenticate cause expired") + return a.Authenticate(scope) + } else { + //log.Printf("Return exist auth token") + return a.token, nil + } + } else { + log.Printf("Authenticate cause no token") + return a.Authenticate(scope) + } + +} // Authenticate allows getting a token with a given scope -func (a TwoLeggedAuth) Authenticate(scope string) (bearer Bearer, err error) { +func (a *TwoLeggedAuth) Authenticate(scope string) (bearer Bearer, err error) { task := http.Client{} @@ -68,5 +91,11 @@ func (a TwoLeggedAuth) Authenticate(scope string) (bearer Bearer, err error) { decoder := json.NewDecoder(response.Body) err = decoder.Decode(&bearer) + if err == nil { + a.token = bearer + exp := time.Duration(a.token.ExpiresIn)*time.Second + a.expires = time.Now().Add(exp) + } + return } diff --git a/oauth/two_legged_test.go b/oauth/two_legged_test.go index 3e8bf56..131f42a 100644 --- a/oauth/two_legged_test.go +++ b/oauth/two_legged_test.go @@ -2,7 +2,7 @@ package oauth_test import ( "fmt" - "github.com/apprentice3d/forge-api-go-client/oauth" + "forge-api-go-client/oauth" "log" "os" "testing" diff --git a/recap/recap.go b/recap/recap.go index 927623d..cdf22fd 100644 --- a/recap/recap.go +++ b/recap/recap.go @@ -9,7 +9,7 @@ package recap import ( - "github.com/apprentice3d/forge-api-go-client/oauth" + "github.com/BUCKU/forge-api-go-client/oauth" ) // API struct holds all paths necessary to access ReCap API