// Copyright 2024 Google LLC
//
// 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.
//

syntax = "proto3";

package google.cloud.resourcemanager.v2;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/iam/v1/iam_policy.proto";
import "google/iam/v1/policy.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.ResourceManager.V2";
option go_package = "cloud.google.com/go/resourcemanager/apiv2/resourcemanagerpb;resourcemanagerpb";
option java_multiple_files = true;
option java_outer_classname = "FoldersProto";
option java_package = "com.google.cloud.resourcemanager.v2";
option php_namespace = "Google\\Cloud\\ResourceManager\\V2";

// Manages Cloud Resource Folders.
// Cloud Resource Folders can be used to organize the resources under an
// organization and to control the IAM policies applied to groups of resources.
service Folders {
  option (google.api.default_host) = "cloudresourcemanager.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/cloud-platform.read-only";

  // Lists the Folders that are direct descendants of supplied parent resource.
  // List provides a strongly consistent view of the Folders underneath
  // the specified parent resource.
  // List returns Folders sorted based upon the (ascending) lexical ordering
  // of their display_name.
  // The caller must have `resourcemanager.folders.list` permission on the
  // identified parent.
  rpc ListFolders(ListFoldersRequest) returns (ListFoldersResponse) {
    option (google.api.http) = {
      get: "/v2/folders"
    };
    option (google.api.method_signature) = "parent,show_deleted";
  }

  // Search for folders that match specific filter criteria.
  // Search provides an eventually consistent view of the folders a user has
  // access to which meet the specified filter criteria.
  //
  // This will only return folders on which the caller has the
  // permission `resourcemanager.folders.get`.
  rpc SearchFolders(SearchFoldersRequest) returns (SearchFoldersResponse) {
    option (google.api.http) = {
      post: "/v2/folders:search"
      body: "*"
    };
    option (google.api.method_signature) = "query";
  }

  // Retrieves a Folder identified by the supplied resource name.
  // Valid Folder resource names have the format `folders/{folder_id}`
  // (for example, `folders/1234`).
  // The caller must have `resourcemanager.folders.get` permission on the
  // identified folder.
  rpc GetFolder(GetFolderRequest) returns (Folder) {
    option (google.api.http) = {
      get: "/v2/{name=folders/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a Folder in the resource hierarchy.
  // Returns an Operation which can be used to track the progress of the
  // folder creation workflow.
  // Upon success the Operation.response field will be populated with the
  // created Folder.
  //
  // In order to succeed, the addition of this new Folder must not violate
  // the Folder naming, height or fanout constraints.
  //
  // + The Folder's display_name must be distinct from all other Folder's that
  // share its parent.
  // + The addition of the Folder must not cause the active Folder hierarchy
  // to exceed a height of 4. Note, the full active + deleted Folder hierarchy
  // is allowed to reach a height of 8; this provides additional headroom when
  // moving folders that contain deleted folders.
  // + The addition of the Folder must not cause the total number of Folders
  // under its parent to exceed 100.
  //
  // If the operation fails due to a folder constraint violation, some errors
  // may be returned by the CreateFolder request, with status code
  // FAILED_PRECONDITION and an error description. Other folder constraint
  // violations will be communicated in the Operation, with the specific
  // PreconditionFailure returned via the details list in the Operation.error
  // field.
  //
  // The caller must have `resourcemanager.folders.create` permission on the
  // identified parent.
  rpc CreateFolder(CreateFolderRequest) returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v2/folders"
      body: "folder"
    };
    option (google.api.method_signature) = "parent,folder";
    option (google.longrunning.operation_info) = {
      response_type: "Folder"
      metadata_type: "FolderOperation"
    };
  }

  // Updates a Folder, changing its display_name.
  // Changes to the folder display_name will be rejected if they violate either
  // the display_name formatting rules or naming constraints described in
  // the [CreateFolder][google.cloud.resourcemanager.v2.Folders.CreateFolder] documentation.
  //
  // The Folder's display name must start and end with a letter or digit,
  // may contain letters, digits, spaces, hyphens and underscores and can be
  // no longer than 30 characters. This is captured by the regular expression:
  // [\p{L}\p{N}]([\p{L}\p{N}_- ]{0,28}[\p{L}\p{N}])?.
  // The caller must have `resourcemanager.folders.update` permission on the
  // identified folder.
  //
  // If the update fails due to the unique name constraint then a
  // PreconditionFailure explaining this violation will be returned
  // in the Status.details field.
  rpc UpdateFolder(UpdateFolderRequest) returns (Folder) {
    option (google.api.http) = {
      patch: "/v2/{folder.name=folders/*}"
      body: "folder"
    };
    option (google.api.method_signature) = "folder,update_mask";
  }

  // Moves a Folder under a new resource parent.
  // Returns an Operation which can be used to track the progress of the
  // folder move workflow.
  // Upon success the Operation.response field will be populated with the
  // moved Folder.
  // Upon failure, a FolderOperationError categorizing the failure cause will
  // be returned - if the failure occurs synchronously then the
  // FolderOperationError will be returned via the Status.details field
  // and if it occurs asynchronously then the FolderOperation will be returned
  // via the Operation.error field.
  // In addition, the Operation.metadata field will be populated with a
  // FolderOperation message as an aid to stateless clients.
  // Folder moves will be rejected if they violate either the naming, height
  // or fanout constraints described in the
  // [CreateFolder][google.cloud.resourcemanager.v2.Folders.CreateFolder] documentation.
  // The caller must have `resourcemanager.folders.move` permission on the
  // folder's current and proposed new parent.
  rpc MoveFolder(MoveFolderRequest) returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v2/{name=folders/*}:move"
      body: "*"
    };
    option (google.api.method_signature) = "name,destination_parent";
    option (google.longrunning.operation_info) = {
      response_type: "Folder"
      metadata_type: "FolderOperation"
    };
  }

  // Requests deletion of a Folder. The Folder is moved into the
  // [DELETE_REQUESTED][google.cloud.resourcemanager.v2.Folder.LifecycleState.DELETE_REQUESTED] state
  // immediately, and is deleted approximately 30 days later. This method may
  // only be called on an empty Folder in the
  // [ACTIVE][google.cloud.resourcemanager.v2.Folder.LifecycleState.ACTIVE] state, where a Folder is empty if
  // it doesn't contain any Folders or Projects in the
  // [ACTIVE][google.cloud.resourcemanager.v2.Folder.LifecycleState.ACTIVE] state.
  // The caller must have `resourcemanager.folders.delete` permission on the
  // identified folder.
  rpc DeleteFolder(DeleteFolderRequest) returns (Folder) {
    option (google.api.http) = {
      delete: "/v2/{name=folders/*}"
    };
    option (google.api.method_signature) = "name";
    option (google.api.method_signature) = "name,recursive_delete";
  }

  // Cancels the deletion request for a Folder. This method may only be
  // called on a Folder in the
  // [DELETE_REQUESTED][google.cloud.resourcemanager.v2.Folder.LifecycleState.DELETE_REQUESTED] state.
  // In order to succeed, the Folder's parent must be in the
  // [ACTIVE][google.cloud.resourcemanager.v2.Folder.LifecycleState.ACTIVE] state.
  // In addition, reintroducing the folder into the tree must not violate
  // folder naming, height and fanout constraints described in the
  // [CreateFolder][google.cloud.resourcemanager.v2.Folders.CreateFolder] documentation.
  // The caller must have `resourcemanager.folders.undelete` permission on the
  // identified folder.
  rpc UndeleteFolder(UndeleteFolderRequest) returns (Folder) {
    option (google.api.http) = {
      post: "/v2/{name=folders/*}:undelete"
      body: "*"
    };
    option (google.api.method_signature) = "name";
  }

  // Gets the access control policy for a Folder. The returned policy may be
  // empty if no such policy or resource exists. The `resource` field should
  // be the Folder's resource name, e.g. "folders/1234".
  // The caller must have `resourcemanager.folders.getIamPolicy` permission
  // on the identified folder.
  rpc GetIamPolicy(google.iam.v1.GetIamPolicyRequest) returns (google.iam.v1.Policy) {
    option (google.api.http) = {
      post: "/v2/{resource=folders/*}:getIamPolicy"
      body: "*"
    };
    option (google.api.method_signature) = "resource";
  }

  // Sets the access control policy on a Folder, replacing any existing policy.
  // The `resource` field should be the Folder's resource name, e.g.
  // "folders/1234".
  // The caller must have `resourcemanager.folders.setIamPolicy` permission
  // on the identified folder.
  rpc SetIamPolicy(google.iam.v1.SetIamPolicyRequest) returns (google.iam.v1.Policy) {
    option (google.api.http) = {
      post: "/v2/{resource=folders/*}:setIamPolicy"
      body: "*"
    };
    option (google.api.method_signature) = "resource,policy";
  }

  // Returns permissions that a caller has on the specified Folder.
  // The `resource` field should be the Folder's resource name,
  // e.g. "folders/1234".
  //
  // There are no permissions required for making this API call.
  rpc TestIamPermissions(google.iam.v1.TestIamPermissionsRequest) returns (google.iam.v1.TestIamPermissionsResponse) {
    option (google.api.http) = {
      post: "/v2/{resource=folders/*}:testIamPermissions"
      body: "*"
    };
    option (google.api.method_signature) = "resource,permissions";
  }
}

// A Folder in an Organization's resource hierarchy, used to
// organize that Organization's resources.
message Folder {
  option (google.api.resource) = {
    type: "cloudresourcemanager.googleapis.com/Folder"
    pattern: "folders/{folder}"
  };

  // Folder lifecycle states.
  enum LifecycleState {
    // Unspecified state.
    LIFECYCLE_STATE_UNSPECIFIED = 0;

    // The normal and active state.
    ACTIVE = 1;

    // The folder has been marked for deletion by the user.
    DELETE_REQUESTED = 2;
  }

  // Output only. The resource name of the Folder.
  // Its format is `folders/{folder_id}`, for example: "folders/1234".
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. The Folder’s parent's resource name.
  // Updates to the folder's parent must be performed via
  // [MoveFolder][google.cloud.resourcemanager.v2.Folders.MoveFolder].
  string parent = 2 [(google.api.field_behavior) = REQUIRED];

  // The folder’s display name.
  // A folder’s display name must be unique amongst its siblings, e.g.
  // no two folders with the same parent can share the same display name.
  // The display name must start and end with a letter or digit, may contain
  // letters, digits, spaces, hyphens and underscores and can be no longer
  // than 30 characters. This is captured by the regular expression:
  // [\p{L}\p{N}]([\p{L}\p{N}_- ]{0,28}[\p{L}\p{N}])?.
  string display_name = 3;

  // Output only. The lifecycle state of the folder.
  // Updates to the lifecycle_state must be performed via
  // [DeleteFolder][google.cloud.resourcemanager.v2.Folders.DeleteFolder] and
  // [UndeleteFolder][google.cloud.resourcemanager.v2.Folders.UndeleteFolder].
  LifecycleState lifecycle_state = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Timestamp when the Folder was created. Assigned by the server.
  google.protobuf.Timestamp create_time = 5 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Timestamp when the Folder was last modified.
  google.protobuf.Timestamp update_time = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// The ListFolders request message.
message ListFoldersRequest {
  // Required. The resource name of the Organization or Folder whose Folders are
  // being listed.
  // Must be of the form `folders/{folder_id}` or `organizations/{org_id}`.
  // Access to this method is controlled by checking the
  // `resourcemanager.folders.list` permission on the `parent`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "*"
    }
  ];

  // Optional. The maximum number of Folders to return in the response.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A pagination token returned from a previous call to `ListFolders`
  // that indicates where this listing should continue from.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Controls whether Folders in the
  // [DELETE_REQUESTED][google.cloud.resourcemanager.v2.Folder.LifecycleState.DELETE_REQUESTED]
  // state should be returned. Defaults to false.
  bool show_deleted = 4 [(google.api.field_behavior) = OPTIONAL];
}

// The ListFolders response message.
message ListFoldersResponse {
  // A possibly paginated list of Folders that are direct descendants of
  // the specified parent resource.
  repeated Folder folders = 1;

  // A pagination token returned from a previous call to `ListFolders`
  // that indicates from where listing should continue.
  string next_page_token = 2;
}

// The request message for searching folders.
message SearchFoldersRequest {
  // Optional. The maximum number of folders to return in the response.
  int32 page_size = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A pagination token returned from a previous call to `SearchFolders`
  // that indicates from where search should continue.
  string page_token = 2 [(google.api.field_behavior) = OPTIONAL];

  // Search criteria used to select the Folders to return.
  // If no search criteria is specified then all accessible folders will be
  // returned.
  //
  // Query expressions can be used to restrict results based upon displayName,
  // lifecycleState and parent, where the operators `=`, `NOT`, `AND` and `OR`
  // can be used along with the suffix wildcard symbol `*`.
  //
  // The displayName field in a query expression should use escaped quotes
  // for values that include whitespace to prevent unexpected behavior.
  //
  // Some example queries are:
  //
  // * Query `displayName=Test*` returns Folder resources whose display name
  // starts with "Test".
  // * Query `lifecycleState=ACTIVE` returns Folder resources with
  // `lifecycleState` set to `ACTIVE`.
  // * Query `parent=folders/123` returns Folder resources that have
  // `folders/123` as a parent resource.
  // * Query `parent=folders/123 AND lifecycleState=ACTIVE` returns active
  // Folder resources that have `folders/123` as a parent resource.
  // * Query `displayName=\\"Test String\\"` returns Folder resources with
  // display names that include both "Test" and "String".
  string query = 3;
}

// The response message for searching folders.
message SearchFoldersResponse {
  // A possibly paginated folder search results.
  // the specified parent resource.
  repeated Folder folders = 1;

  // A pagination token returned from a previous call to `SearchFolders`
  // that indicates from where searching should continue.
  string next_page_token = 2;
}

// The GetFolder request message.
message GetFolderRequest {
  // Required. The resource name of the Folder to retrieve.
  // Must be of the form `folders/{folder_id}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Folder"
    }
  ];
}

// The CreateFolder request message.
message CreateFolderRequest {
  // Required. The resource name of the new Folder's parent.
  // Must be of the form `folders/{folder_id}` or `organizations/{org_id}`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "*"
    }
  ];

  // Required. The Folder being created, only the display name will be consulted.
  // All other fields will be ignored.
  Folder folder = 2 [(google.api.field_behavior) = REQUIRED];
}

// The MoveFolder request message.
message MoveFolderRequest {
  // Required. The resource name of the Folder to move.
  // Must be of the form folders/{folder_id}
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Folder"
    }
  ];

  // Required. The resource name of the Folder or Organization to reparent
  // the folder under.
  // Must be of the form `folders/{folder_id}` or `organizations/{org_id}`.
  string destination_parent = 2 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "*"
    }
  ];
}

// The request message for updating a folder's display name.
message UpdateFolderRequest {
  // Required. The new definition of the Folder. It must include a
  // a `name` and `display_name` field. The other fields
  // will be ignored.
  Folder folder = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. Fields to be updated.
  // Only the `display_name` can be updated.
  google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
}

// The DeleteFolder request message.
message DeleteFolderRequest {
  // Required. The resource name of the Folder to be deleted.
  // Must be of the form `folders/{folder_id}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Folder"
    }
  ];

  // Instructs DeleteFolderAction to delete a folder even when the folder is not
  // empty.
  bool recursive_delete = 2;
}

// The UndeleteFolder request message.
message UndeleteFolderRequest {
  // Required. The resource name of the Folder to undelete.
  // Must be of the form `folders/{folder_id}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Folder"
    }
  ];
}

// Metadata describing a long running folder operation
message FolderOperation {
  // The type of operation that failed.
  enum OperationType {
    // Operation type not specified.
    OPERATION_TYPE_UNSPECIFIED = 0;

    // A create folder operation.
    CREATE = 1;

    // A move folder operation.
    MOVE = 2;
  }

  // The display name of the folder.
  string display_name = 1;

  // The type of this operation.
  OperationType operation_type = 2;

  // The resource name of the folder's parent.
  // Only applicable when the operation_type is MOVE.
  string source_parent = 3;

  // The resource name of the folder or organization we are either creating
  // the folder under or moving the folder to.
  string destination_parent = 4;
}
