auth0/resource_auth0_organization.go
package auth0
import (
"fmt"
"log"
"net/http"
"github.com/alexkappa/terraform-provider-auth0/auth0/internal/hash"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"gopkg.in/auth0.v5/management"
)
func newOrganization() *schema.Resource {
return &schema.Resource{
Create: createOrganization,
Read: readOrganization,
Update: updateOrganization,
Delete: deleteOrganization,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of this organization",
},
"display_name": {
Type: schema.TypeString,
Optional: true,
Description: "Friendly name of this organization",
},
"branding": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
MinItems: 1,
Description: "Defines how to style the login pages",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"logo_url": {
Type: schema.TypeString,
Optional: true,
},
"colors": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"metadata": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "Metadata associated with the organization, Maximum of 10 metadata properties allowed",
},
"connections": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"connection_id": {
Type: schema.TypeString,
Required: true,
},
"assign_membership_on_login": {
Type: schema.TypeBool,
Optional: true,
},
},
},
Set: hash.StringKey("connection_id"),
},
},
}
}
func createOrganization(d *schema.ResourceData, m interface{}) error {
o := expandOrganization(d)
api := m.(*management.Management)
if err := api.Organization.Create(o); err != nil {
return err
}
d.SetId(o.GetID())
d.Partial(true)
err := assignOrganizationConnections(d, m)
if err != nil {
return fmt.Errorf("failed assigning organization connections. %w", err)
}
d.Partial(false)
return readOrganization(d, m)
}
func assignOrganizationConnections(d *schema.ResourceData, m interface{}) (err error) {
api := m.(*management.Management)
add, rm := Diff(d, "connections")
add.Elem(func(dd ResourceData) {
c := &management.OrganizationConnection{
ConnectionID: String(dd, "connection_id"),
AssignMembershipOnLogin: Bool(dd, "assign_membership_on_login"),
}
log.Printf("[DEBUG] (+) auth0_organization.%s.connections.%s", d.Id(), c.GetConnectionID())
err = api.Organization.AddConnection(d.Id(), c)
if err != nil {
return
}
})
rm.Elem(func(dd ResourceData) {
// Take connectionID before it changed (i.e. removed). Therefore we use
// GetChange() instead of the typical Get().
connectionID, _ := dd.GetChange("connection_id")
log.Printf("[DEBUG] (-) auth0_organization.%s.connections.%s", d.Id(), connectionID.(string))
err = api.Organization.DeleteConnection(d.Id(), connectionID.(string))
if err != nil {
return
}
})
// Update existing connections if any mutable properties have changed.
Set(d, "connections", HasChange()).Elem(func(dd ResourceData) {
connectionID := dd.Get("connection_id").(string)
c := &management.OrganizationConnection{
AssignMembershipOnLogin: Bool(dd, "assign_membership_on_login"),
}
log.Printf("[DEBUG] (~) auth0_organization.%s.connections.%s", d.Id(), connectionID)
err = api.Organization.UpdateConnection(d.Id(), connectionID, c)
if err != nil {
return
}
})
return nil
}
func readOrganization(d *schema.ResourceData, m interface{}) error {
api := m.(*management.Management)
o, err := api.Organization.Read(d.Id())
if err != nil {
if mErr, ok := err.(management.Error); ok {
if mErr.Status() == http.StatusNotFound {
d.SetId("")
return nil
}
}
return err
}
d.SetId(o.GetID())
d.Set("name", o.Name)
d.Set("display_name", o.DisplayName)
d.Set("branding", flattenOrganizationBranding(o.Branding))
d.Set("metadata", o.Metadata)
l, err := api.Organization.Connections(d.Id())
if err != nil {
return err
}
d.Set("connections", func() (v []interface{}) {
for _, connection := range l.OrganizationConnections {
v = append(v, &map[string]interface{}{
"connection_id": connection.ConnectionID,
"assign_membership_on_login": connection.AssignMembershipOnLogin,
})
}
return
}())
return nil
}
func updateOrganization(d *schema.ResourceData, m interface{}) error {
o := expandOrganization(d)
api := m.(*management.Management)
err := api.Organization.Update(d.Id(), o)
if err != nil {
return err
}
d.Partial(true)
err = assignOrganizationConnections(d, m)
if err != nil {
return fmt.Errorf("failed updating organization connections. %w", err)
}
d.Partial(false)
return readOrganization(d, m)
}
func deleteOrganization(d *schema.ResourceData, m interface{}) error {
api := m.(*management.Management)
err := api.Organization.Delete(d.Id())
if err != nil {
if mErr, ok := err.(management.Error); ok {
if mErr.Status() == http.StatusNotFound {
d.SetId("")
return nil
}
}
}
return err
}
func expandOrganization(d *schema.ResourceData) *management.Organization {
o := &management.Organization{
Name: String(d, "name"),
DisplayName: String(d, "display_name"),
Metadata: Map(d, "metadata"),
}
List(d, "branding").Elem(func(d ResourceData) {
o.Branding = &management.OrganizationBranding{
LogoURL: String(d, "logo_url"),
Colors: Map(d, "colors"),
}
})
return o
}
func flattenOrganizationBranding(b *management.OrganizationBranding) []interface{} {
m := make(map[string]interface{})
if b != nil {
m["logo_url"] = b.LogoURL
m["colors"] = b.Colors
}
return []interface{}{m}
}