Skip to content

Commit

Permalink
feature - Implement Project resource and data source
Browse files Browse the repository at this point in the history
  • Loading branch information
GtheSheep authored Mar 6, 2023
2 parents 457f117 + 83bf4bd commit 7d57983
Show file tree
Hide file tree
Showing 14 changed files with 669 additions and 8 deletions.
29 changes: 29 additions & 0 deletions docs/data-sources/project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "tableau_project Data Source - terraform-provider-tableau"
subcategory: ""
description: |-
Retrieve project details
---

# tableau_project (Data Source)

Retrieve project details



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `id` (String) ID of the project

### Read-Only

- `content_permissions` (String) Permissions for the project content - ManagedByOwner is the default
- `description` (String) Description for the project
- `name` (String) Name for the project
- `parent_project_id` (String) Identifier for the parent project


33 changes: 33 additions & 0 deletions docs/resources/project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "tableau_project Resource - terraform-provider-tableau"
subcategory: ""
description: |-
---

# tableau_project (Resource)





<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `content_permissions` (String) Permissions for the project content - ManagedByOwner is the default
- `name` (String) Display name for project

### Optional

- `description` (String) Description for the project
- `parent_project_id` (String) Identifier for the parent project

### Read-Only

- `id` (String) The ID of this resource.
- `last_updated` (String)


2 changes: 1 addition & 1 deletion examples/resources/group/import.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
terraform import tableau_group.example "abc"
terraform import tableau_group.example "group_id"
1 change: 1 addition & 0 deletions examples/resources/project/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import tableau_project.example "project_id"
6 changes: 6 additions & 0 deletions examples/resources/project/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "tableau_project" "test" {
name = "test"
description = "Moo"
content_permissions = "LockedToProject"
parent_project_id = tableau_project.test_parent.id
}
2 changes: 1 addition & 1 deletion examples/resources/user/import.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
terraform import tableau_user.example "abc"
terraform import tableau_user.example "user_id"
6 changes: 6 additions & 0 deletions tableau/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import (
"strings"
)

type PaginationDetails struct {
PageNumber string `json:"pageNumber"`
PageSize string `json:"pageSize"`
TotalAvailable string `json:"totalAvailable"`
}

func GetPaginationNumbers(paginationDetails PaginationDetails) (int, int, error) {
pageNumber, err := strconv.Atoi(paginationDetails.PageNumber)
if err != nil {
Expand Down
6 changes: 0 additions & 6 deletions tableau/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ type Group struct {
Import *GroupImport `json:"import,omitempty"`
}

type PaginationDetails struct {
PageNumber string `json:"pageNumber"`
PageSize string `json:"pageSize"`
TotalAvailable string `json:"totalAvailable"`
}

type GroupRequest struct {
Group Group `json:"group"`
}
Expand Down
169 changes: 169 additions & 0 deletions tableau/project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package tableau

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
)

type Project struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
ParentProjectID string `json:"parentProjectId,omitempty"`
Description string `json:"description,omitempty"`
ContentPermissions string `json:"contentPermissions,omitempty"`
}

type ProjectRequest struct {
Project Project `json:"project"`
}

type ProjectResponse struct {
Project Project `json:"project"`
}

type ProjectsResponse struct {
Projects []Project `json:"project"`
}

type ProjectListResponse struct {
ProjectsResponse ProjectsResponse `json:"projects"`
Pagination PaginationDetails `json:"pagination"`
}

func (c *Client) GetProject(projectID string) (*Project, error) {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/projects", c.ApiUrl), nil)
if err != nil {
return nil, err
}

body, err := c.doRequest(req)
if err != nil {
return nil, err
}

projectListResponse := ProjectListResponse{}
err = json.Unmarshal(body, &projectListResponse)
if err != nil {
return nil, err
}

// TODO: Generalise pagination handling and use elsewhere
pageNumber, totalPageCount, err := GetPaginationNumbers(projectListResponse.Pagination)
if err != nil {
return nil, err
}
for i, project := range projectListResponse.ProjectsResponse.Projects {
if project.ID == projectID {
return &projectListResponse.ProjectsResponse.Projects[i], nil
}
}

for page := pageNumber + 1; page <= totalPageCount; page++ {
fmt.Printf("Searching page %d", page)
req, err = http.NewRequest("GET", fmt.Sprintf("%s/projects?pageNumber=%s", c.ApiUrl, strconv.Itoa(page)), nil)
if err != nil {
return nil, err
}
body, err = c.doRequest(req)
if err != nil {
return nil, err
}
projectListResponse = ProjectListResponse{}
err = json.Unmarshal(body, &projectListResponse)
if err != nil {
return nil, err
}
}

return nil, fmt.Errorf("Did not find project ID %s", projectID)
}

func (c *Client) CreateProject(name, parentProjectId, description, contentPermissions string) (*Project, error) {

newProject := Project{
Name: name,
ParentProjectID: parentProjectId,
Description: description,
ContentPermissions: contentPermissions,
}
projectRequest := ProjectRequest{
Project: newProject,
}

newProjectJson, err := json.Marshal(projectRequest)
if err != nil {
return nil, err
}

req, err := http.NewRequest("POST", fmt.Sprintf("%s/projects", c.ApiUrl), strings.NewReader(string(newProjectJson)))
if err != nil {
return nil, err
}

body, err := c.doRequest(req)
if err != nil {
return nil, err
}

projectResponse := ProjectResponse{}
err = json.Unmarshal(body, &projectResponse)
if err != nil {
return nil, err
}

return &projectResponse.Project, nil
}

func (c *Client) UpdateProject(projectID, name, parentProjectId, description, contentPermissions string) (*Project, error) {

newProject := Project{
Name: name,
ParentProjectID: parentProjectId,
Description: description,
ContentPermissions: contentPermissions,
}
projectRequest := ProjectRequest{
Project: newProject,
}

newProjectJson, err := json.Marshal(projectRequest)
if err != nil {
return nil, err
}

req, err := http.NewRequest("PUT", fmt.Sprintf("%s/projects/%s", c.ApiUrl, projectID), strings.NewReader(string(newProjectJson)))
if err != nil {
return nil, err
}

body, err := c.doRequest(req)
if err != nil {
return nil, err
}

projectResponse := ProjectResponse{}
err = json.Unmarshal(body, &projectResponse)
if err != nil {
return nil, err
}

return &projectResponse.Project, nil
}

func (c *Client) DeleteProject(projectID string) error {

req, err := http.NewRequest("DELETE", fmt.Sprintf("%s/projects/%s", c.ApiUrl, projectID), nil)
if err != nil {
return err
}

_, err = c.doRequest(req)
if err != nil {
return err
}

return nil
}
97 changes: 97 additions & 0 deletions tableau/project_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package tableau

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var (
_ datasource.DataSource = &projectDataSource{}
_ datasource.DataSourceWithConfigure = &projectDataSource{}
)

func ProjectDataSource() datasource.DataSource {
return &projectDataSource{}
}

type projectDataSource struct {
client *Client
}

type projectDataSourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
ContentPermissions types.String `tfsdk:"content_permissions"`
ParentProjectID types.String `tfsdk:"parent_project_id"`
}

func (d *projectDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_project"
}

func (d *projectDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Retrieve project details",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
Description: "ID of the project",
},
"name": schema.StringAttribute{
Computed: true,
Description: "Name for the project",
},
"description": schema.StringAttribute{
Computed: true,
Description: "Description for the project",
},
"content_permissions": schema.StringAttribute{
Computed: true,
Description: "Permissions for the project content - ManagedByOwner is the default",
},
"parent_project_id": schema.StringAttribute{
Computed: true,
Description: "Identifier for the parent project",
},
},
}
}

func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var state projectDataSourceModel

resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)

project, err := d.client.GetProject(state.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Unable to Read Tableau Project",
err.Error(),
)
return
}

state.ID = types.StringValue(project.ID)
state.Name = types.StringValue(project.Name)
state.Description = types.StringValue(project.Description)
state.ContentPermissions = types.StringValue(project.ContentPermissions)
state.ParentProjectID = types.StringValue(project.ParentProjectID)

diags := resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}

func (d *projectDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

d.client = req.ProviderData.(*Client)
}
Loading

0 comments on commit 7d57983

Please sign in to comment.