From d77198d7c6a8a633b7a16575d5f625c9f83f223a Mon Sep 17 00:00:00 2001 From: Jose Pereira Date: Mon, 7 Jun 2021 00:39:54 +0100 Subject: [PATCH] Add user directories commands --- cmd/add-user-directories.go | 137 +++++++++++++++++++++++ cmd/delete-user-directory.go | 110 +++++++++++++++++++ cmd/edit-user-directories.go | 147 +++++++++++++++++++++++++ cmd/get-user-directory.go | 159 +++++++++++++++++++++++++++ cmd/list-user-directories.go | 89 +++++++++++++++ cmd/root-settings.go | 6 + swagger.yml | 206 +++++++++++++++++++++++++++++++++++ 7 files changed, 854 insertions(+) create mode 100644 cmd/add-user-directories.go create mode 100644 cmd/delete-user-directory.go create mode 100644 cmd/edit-user-directories.go create mode 100644 cmd/get-user-directory.go create mode 100644 cmd/list-user-directories.go diff --git a/cmd/add-user-directories.go b/cmd/add-user-directories.go new file mode 100644 index 0000000..31ff335 --- /dev/null +++ b/cmd/add-user-directories.go @@ -0,0 +1,137 @@ +// Package cmd implements access-cli commands +package cmd + +/* +Copyright © 2020 Barracuda Networks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/spf13/cobra" + + api "github.com/barracuda-cloudgen-access/access-cli/client/user_directories" + "github.com/barracuda-cloudgen-access/access-cli/models" +) + +// userDirectoriesAddCmd represents the add command +var userDirectoriesAddCmd = &cobra.Command{ + Use: "add", + Aliases: []string{"create", "new"}, + Short: "Add user directories", + PreRunE: func(cmd *cobra.Command, args []string) error { + err := preRunCheckAuth(cmd, args) + if err != nil { + return err + } + + err = preRunFlagChecks(cmd, args) + if err != nil { + return err + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + tw := userDirectoryBuildTableWriter() + createdList := []*models.UserDirectory{} + total := 0 + + err := forAllInput(cmd, args, true, + func(values *inputEntry) (interface{}, error) { // do func + total++ // this is the total of successful+failures, must increment before failure + userdirectory := &api.CreateUserDirectoryParamsBodyUserDirectory{} + + err := placeInputValues(cmd, values, userdirectory, + func(s string) { userdirectory.ShortCode = s }, + func(s string) { userdirectory.Name = s }, + func(s string) { userdirectory.DirectoryType = s }, + func(s string) { userdirectory.Notes = s }) + if err != nil { + return nil, err + } + body := api.CreateUserDirectoryBody{UserDirectory: userdirectory} + params := api.NewCreateUserDirectoryParams() + + setTenant(cmd, params) + params.SetUserDirectory(body) + + resp, err := global.Client.UserDirectories.CreateUserDirectory(params, global.AuthWriter) + if err != nil { + return nil, err + } + return resp.Payload.UserDirectory, nil + }, func(data interface{}) { // printSuccess func + userdirectory := data.(models.UserDirectory) + createdList = append(createdList, &userdirectory) + userDirectoryTableWriterAppend(tw, userdirectory) + }, func(err error, id interface{}) { // doOnError func + createdList = append(createdList, nil) + userDirectoryTableWriterAppendError(tw, err, id) + }) + return printListOutputAndError(cmd, createdList, tw, total, err) + }, +} + +func init() { + settingsUserDirectoryCmd.AddCommand(userDirectoriesAddCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // userDirectoriesAddCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // userDirectoriesAddCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + initOutputFlags(userDirectoriesAddCmd) + initLoopControlFlags(userDirectoriesAddCmd) + initTenantFlags(userDirectoriesAddCmd) + + initInputFlags(userDirectoriesAddCmd, "userdirectory", + inputField{ + Name: "ShortCode", + FlagName: "shortcode", + FlagDescription: "specify a shortcode for the directory", + VarType: "string", + Mandatory: true, + DefaultValue: "", + }, + inputField{ + Name: "Name", + FlagName: "name", + FlagDescription: "specify the name for the directory", + VarType: "string", + Mandatory: true, + DefaultValue: "", + MainField: true, + }, + inputField{ + Name: "Type", + FlagName: "type", + FlagDescription: "specify source for the user directory", + VarType: "string", + Mandatory: true, + DefaultValue: "", + }, + inputField{ + Name: "Notes", + FlagName: "notes", + FlagDescription: "additional notes", + VarType: "string", + Mandatory: false, + DefaultValue: "", + }) +} diff --git a/cmd/delete-user-directory.go b/cmd/delete-user-directory.go new file mode 100644 index 0000000..81cf915 --- /dev/null +++ b/cmd/delete-user-directory.go @@ -0,0 +1,110 @@ +// Package cmd implements access-cli commands +package cmd + +/* +Copyright © 2020 Barracuda Networks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + "strconv" + + "github.com/spf13/cobra" + + api "github.com/barracuda-cloudgen-access/access-cli/client/user_directories" +) + +// userDirectoryDeleteCmd represents the delete command +var userDirectoryDeleteCmd = &cobra.Command{ + Use: "delete [userdirectory ID]", + Aliases: []string{"remove", "rm"}, + Short: "Delete user directories", + PreRunE: func(cmd *cobra.Command, args []string) error { + err := preRunCheckAuth(cmd, args) + if err != nil { + return err + } + + err = preRunFlagChecks(cmd, args) + if err != nil { + return err + } + + if len(args) == 0 && !cmd.Flags().Changed("id") { + return fmt.Errorf("missing proxy ID argument") + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + var id int64 + var err error + if cmd.Flags().Changed("id") { + id, err = cmd.Flags().GetInt64("id") + if err != nil { + return err + } + } else { + id, err = strconv.ParseInt(args[0], 10, 64) + if err != nil { + return err + } + } + + params := api.NewDeleteUserDirectoryParams() + setTenant(cmd, params) + params.SetID(id) + + tw, j := multiOpBuildTableWriter() + _, err = global.Client.UserDirectories.DeleteUserDirectory(params, global.AuthWriter) + + var result interface{} + result = "success" + if err != nil { + result = err + } + multiOpTableWriterAppend(tw, &j, "*", result) + + return printListOutputAndError(cmd, j, tw, 1, err) + }, +} + +func init() { + settingsUserDirectoryCmd.AddCommand(userDirectoryDeleteCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // userDirectoryDeleteCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // userDirectoryDeleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + initInputFlags(userDirectoryDeleteCmd, "userdirectory", + inputField{ + Name: "ID", + FlagName: "id", + FlagDescription: "specify the ID of the user to edit", + VarType: "int", + Mandatory: true, + DefaultValue: 0, + MainField: true, + }) + initOutputFlags(userDirectoryDeleteCmd) + initLoopControlFlags(userDirectoryDeleteCmd) + initTenantFlags(userDirectoryDeleteCmd) +} diff --git a/cmd/edit-user-directories.go b/cmd/edit-user-directories.go new file mode 100644 index 0000000..6403c01 --- /dev/null +++ b/cmd/edit-user-directories.go @@ -0,0 +1,147 @@ +// Package cmd implements access-cli commands +package cmd + +/* +Copyright © 2020 Barracuda Networks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/spf13/cobra" + + api "github.com/barracuda-cloudgen-access/access-cli/client/user_directories" + "github.com/barracuda-cloudgen-access/access-cli/models" +) + +// userDirectoriesEditCmd represents the edit command +var userDirectoriesEditCmd = &cobra.Command{ + Use: "edit", + Short: "Edit user directories", + PreRunE: func(cmd *cobra.Command, args []string) error { + err := preRunCheckAuth(cmd, args) + if err != nil { + return err + } + + err = preRunFlagChecks(cmd, args) + if err != nil { + return err + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + tw := userDirectoryBuildTableWriter() + createdList := []*models.UserDirectory{} + total := 0 + + err := forAllInput(cmd, args, false, + func(values *inputEntry) (interface{}, error) { // do func + total++ // this is the total of successful+failures, must increment before failure + params := api.NewEditUserDirectoryParams() + setTenant(cmd, params) + + userdirectory := &models.UserDirectory{} + + err := placeInputValues(cmd, values, userdirectory, + func(s int) { userdirectory.ID = int64(s) }, + func(s string) { userdirectory.ShortCode = s }, + func(s string) { userdirectory.Name = s }, + func(s string) { userdirectory.DirectoryType = s }, + func(s string) { userdirectory.Notes = s }) + if err != nil { + return nil, err + } + // here, map the ID from the "fake request body" to the correct place + params.SetID(userdirectory.ID) + body := api.EditUserDirectoryBody{UserDirectory: userdirectory} + + params.SetUserDirectory(body) + + resp, err := global.Client.UserDirectories.EditUserDirectory(params, global.AuthWriter) + if err != nil { + return nil, err + } + return resp.Payload.UserDirectory, nil + }, func(data interface{}) { // printSuccess func + userdirectory := data.(models.UserDirectory) + createdList = append(createdList, &userdirectory) + userDirectoryTableWriterAppend(tw, userdirectory) + }, func(err error, id interface{}) { // doOnError func + createdList = append(createdList, nil) + userDirectoryTableWriterAppendError(tw, err, id) + }) + return printListOutputAndError(cmd, createdList, tw, total, err) + }, +} + +func init() { + settingsUserDirectoryCmd.AddCommand(userDirectoriesEditCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // userDirectoriesEditCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // userDirectoriesEditCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + initOutputFlags(userDirectoriesEditCmd) + initLoopControlFlags(userDirectoriesEditCmd) + initTenantFlags(userDirectoriesEditCmd) + + initInputFlags(userDirectoriesEditCmd, "userdirectory", + inputField{ + Name: "ID", + FlagName: "id", + FlagDescription: "specify the ID of the user to edit", + VarType: "int", + DefaultValue: 0, + Mandatory: true, + MainField: true, + SchemaName: "id", + }, + inputField{ + Name: "ShortCode", + FlagName: "shortcode", + FlagDescription: "specify a shortcode for the directory", + VarType: "string", + DefaultValue: "", + }, + inputField{ + Name: "Name", + FlagName: "name", + FlagDescription: "specify the name for the directory", + VarType: "string", + DefaultValue: "", + MainField: true, + }, + inputField{ + Name: "Type", + FlagName: "type", + FlagDescription: "specify source for the user directory", + VarType: "string", + DefaultValue: "", + }, + inputField{ + Name: "Notes", + FlagName: "notes", + FlagDescription: "additional notes", + VarType: "string", + Mandatory: false, + DefaultValue: "", + }) +} diff --git a/cmd/get-user-directory.go b/cmd/get-user-directory.go new file mode 100644 index 0000000..3f042ce --- /dev/null +++ b/cmd/get-user-directory.go @@ -0,0 +1,159 @@ +// Package cmd implements access-cli commands +package cmd + +/* +Copyright © 2020 Barracuda Networks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + "strconv" + "strings" + + "github.com/jedib0t/go-pretty/v6/table" + "github.com/jedib0t/go-pretty/v6/text" + "github.com/spf13/cobra" + + api "github.com/barracuda-cloudgen-access/access-cli/client/user_directories" + "github.com/barracuda-cloudgen-access/access-cli/models" +) + +// userDirectoryGetCmd represents the get command +var userDirectoryGetCmd = &cobra.Command{ + Use: "get [userdirectory ID]", + Short: "Get user directory", + PreRunE: func(cmd *cobra.Command, args []string) error { + err := preRunCheckAuth(cmd, args) + if err != nil { + return err + } + + err = preRunFlagChecks(cmd, args) + if err != nil { + return err + } + + if len(args) == 0 && !cmd.Flags().Changed("id") { + return fmt.Errorf("missing user ID argument") + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + var userID int64 + var err error + if cmd.Flags().Changed("id") { + var d int + d, err = cmd.Flags().GetInt("id") + userID = int64(d) + } else { + userID, err = strconv.ParseInt(args[0], 10, 64) + } + if err != nil { + return err + } + + params := api.NewGetUserDirectoryParams() + setTenant(cmd, params) + params.SetID(userID) + + resp, err := global.Client.UserDirectories.GetUserDirectory(params, global.AuthWriter) + if err != nil { + return processErrorResponse(err) + } + + tw := userDirectoryBuildTableWriter() + userDirectoryTableWriterAppend(tw, resp.Payload.UserDirectory) + + return printListOutputAndError(cmd, resp.Payload, tw, 1, err) + }, +} + +func userDirectoryBuildTableWriter() table.Writer { + tw := table.NewWriter() + tw.Style().Format.Header = text.FormatDefault + tw.AppendHeader(table.Row{ + "ID", + "Name", + "ShortCode", + "DirectoryType", + "TotalGroups", + "TotalUsers", + "LastSuccessfulSyncAt", + "LastJobState", + "LastJobErrors", + }) + + return tw +} + +func userDirectoryTableWriterAppend(tw table.Writer, config models.UserDirectory) table.Writer { + errors := "" + state := "never_started" + if config.LastJob != nil { + state = config.LastJob.State + errors = strings.Join(config.LastJob.Errors, ", ") + } + + tw.AppendRow(table.Row{ + config.ID, + config.Name, + config.ShortCode, + config.DirectoryType, + config.TotalGroups, + config.TotalUsers, + config.LastSuccessfulSyncAt, + state, + errors, + }) + return tw +} + +func userDirectoryTableWriterAppendError(tw table.Writer, err error, id interface{}) { + idStr := "[ERR]" + if id != nil { + idStr += fmt.Sprintf(" %v", id) + } + tw.AppendRow(table.Row{ + idStr, + processErrorResponse(err), + "-", + "-", + "-", + "-", + "-", + "-", + "-", + }) +} + +func init() { + settingsUserDirectoryCmd.AddCommand(userDirectoryGetCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // userDirectoryGetCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // userDirectoryGetCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + initOutputFlags(userDirectoryGetCmd) + initTenantFlags(userDirectoryGetCmd) + + userDirectoryGetCmd.Flags().Int("id", 0, "id of user to get") +} diff --git a/cmd/list-user-directories.go b/cmd/list-user-directories.go new file mode 100644 index 0000000..09b9b88 --- /dev/null +++ b/cmd/list-user-directories.go @@ -0,0 +1,89 @@ +// Package cmd implements access-cli commands +package cmd + +/* +Copyright © 2020 Barracuda Networks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/spf13/cobra" + + api "github.com/barracuda-cloudgen-access/access-cli/client/user_directories" +) + +// listUserDirectoriesCmd represents the get command +var listUserDirectoriesCmd = &cobra.Command{ + Use: "list", + Aliases: []string{"ls"}, + Short: "List user directory", + PreRunE: func(cmd *cobra.Command, args []string) error { + err := preRunCheckAuth(cmd, args) + if err != nil { + return err + } + + err = preRunFlagChecks(cmd, args) + if err != nil { + return err + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + params := api.NewListUserDirectoriesParams() + setTenant(cmd, params) + completePayload := []*api.ListUserDirectoriesOKBodyItems0{} + total := 0 + cutStart, cutEnd, err := forAllPages(cmd, params, func() (int, int64, error) { + resp, err := global.Client.UserDirectories.ListUserDirectories(params, global.AuthWriter) + if err != nil { + return 0, 0, err + } + completePayload = append(completePayload, resp.Payload...) + total = int(resp.Total) + return len(resp.Payload), resp.Total, err + }) + if err != nil { + return processErrorResponse(err) + } + completePayload = completePayload[cutStart:cutEnd] + + tw := userDirectoryBuildTableWriter() + + for _, item := range completePayload { + userDirectoryTableWriterAppend(tw, item.UserDirectory) + } + + return printListOutputAndError(cmd, completePayload, tw, total, err) + }, +} + +func init() { + settingsUserDirectoryCmd.AddCommand(listUserDirectoriesCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // listUserDirectoriesCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // listUserDirectoriesCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + initPaginationFlags(listUserDirectoriesCmd) + initTenantFlags(listUserDirectoriesCmd) + initOutputFlags(listUserDirectoriesCmd) +} diff --git a/cmd/root-settings.go b/cmd/root-settings.go index 0a4fd38..148e202 100644 --- a/cmd/root-settings.go +++ b/cmd/root-settings.go @@ -42,12 +42,18 @@ var settingsAnalyticsCmd = &cobra.Command{ Short: "Operations on analytics", } +var settingsUserDirectoryCmd = &cobra.Command{ + Use: "user_directories", + Short: "Operations on user directories", +} + func init() { rootCmd.AddCommand(settingsCmd) settingsCmd.AddCommand(settingsAgentConfigCmd) settingsCmd.AddCommand(settingsEnrollmentCmd) settingsCmd.AddCommand(settingsAnalyticsCmd) + settingsCmd.AddCommand(settingsUserDirectoryCmd) // Here you will define your flags and configuration settings. diff --git a/swagger.yml b/swagger.yml index dde1bd4..6479dd4 100644 --- a/swagger.yml +++ b/swagger.yml @@ -2494,6 +2494,165 @@ paths: $ref: "#/responses/NotFound" 422: $ref: "#/responses/UnprocessableEntity" + /tenants/{tenant_id}/user_directories: + get: + tags: + - "user_directories" + produces: + - "application/json" + summary: "Retrieve user directories" + operationId: "listUserDirectories" + parameters: + - $ref: '#/parameters/tenantIdParam' + - $ref: '#/parameters/pageParam' + - $ref: '#/parameters/perPageParam' + responses: + 200: + description: "successful operation" + headers: + total: + description: "Total number of items (for pagination)" + type: integer + schema: + type: array + items: + allOf: + - $ref: "#/definitions/UserDirectory" + 401: + $ref: "#/responses/Unauthorized" + 403: + $ref: "#/responses/Forbidden" + 404: + $ref: "#/responses/NotFound" + post: + tags: + - "user_directories" + produces: + - "application/json" + consumes: + - "application/json" + summary: "Create user directory" + operationId: "createUserDirectory" + parameters: + - in: "body" + name: "user_directory" + description: "Information about the user_directory to create" + required: true + schema: + type: object + properties: + user_directory: + type: object + properties: + directory_type: + type: string + enum: ['google_apps', 'azure_ad'] + name: + type: string + notes: + type: string + short_code: + type: string + - $ref: '#/parameters/tenantIdParam' + responses: + 201: + description: "User directory created" + schema: + allOf: + - $ref: "#/definitions/UserDirectory" + 401: + $ref: "#/responses/Unauthorized" + 404: + $ref: "#/responses/NotFound" + 422: + $ref: "#/responses/UnprocessableEntity" + /tenants/{tenant_id}/user_directories/{id}: + get: + tags: + - "user_directories" + produces: + - "application/json" + summary: "Retrieve information about a user directory" + operationId: "getUserDirectory" + parameters: + - in: path + name: "id" + required: true + type: integer + description: "The ID of the user directory to retrieve" + - $ref: '#/parameters/tenantIdParam' + responses: + 200: + description: "User directory info" + schema: + allOf: + - $ref: "#/definitions/UserDirectory" + 401: + $ref: "#/responses/Unauthorized" + 403: + $ref: "#/responses/Forbidden" + 404: + $ref: "#/responses/NotFound" + patch: + tags: + - "user_directories" + produces: + - "application/json" + consumes: + - "application/json" + summary: "Edit user directory" + operationId: "editUserDirectory" + parameters: + - in: path + name: "id" + required: true + type: integer + description: "The ID of the user to edit" + - in: body + name: "user_directory" + description: "User directory information to modify" + required: true + schema: + type: object + properties: + user_directory: + $ref: '#/definitions/UserDirectory' + - $ref: '#/parameters/tenantIdParam' + responses: + 200: + description: "User directory edited" + schema: + allOf: + - $ref: "#/definitions/UserDirectory" + 401: + $ref: "#/responses/Unauthorized" + 403: + $ref: "#/responses/Forbidden" + 404: + $ref: "#/responses/NotFound" + 422: + $ref: "#/responses/UnprocessableEntity" + delete: + tags: + - "user_directories" + summary: "Delete user directory" + operationId: "deleteUserDirectory" + parameters: + - in: path + name: "id" + required: true + type: integer + description: "The ID of the user directories to delete" + - $ref: '#/parameters/tenantIdParam' + responses: + 204: + description: "User directory deleted" + 401: + $ref: "#/responses/Unauthorized" + 404: + $ref: "#/responses/NotFound" + 422: + $ref: "#/responses/UnprocessableEntity" /tenants: get: tags: @@ -3330,6 +3489,53 @@ definitions: type: string example: events.acme.org/post + UserDirectory: + type: object + properties: + created_at: + type: string + format: date-time + directory_type: + type: string + example: google_apps + id: + type: integer + last_job: + type: object + x-nullable: true + properties: + errors: + type: array + items: + type: string + finished_at: + type: string + format: date-time + started_at: + type: string + format: date-time + state: + type: string + example: finished + sync_id: + type: string + last_successful_sync_at: + type: string + format: date-time + name: + type: string + notes: + type: string + short_code: + type: string + total_groups: + type: integer + total_users: + type: integer + updated_at: + type: string + format: date-time + Tenant: type: object properties: