// 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.storage.control.v2;

import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/field_info.proto";
import "google/api/resource.proto";
import "google/api/routing.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.Storage.Control.V2";
option go_package = "cloud.google.com/go/storage/control/apiv2/controlpb;controlpb";
option java_multiple_files = true;
option java_outer_classname = "StorageControlProto";
option java_package = "com.google.storage.control.v2";
option php_namespace = "Google\\Cloud\\Storage\\Control\\V2";
option ruby_package = "Google::Cloud::Storage::Control::V2";
option (google.api.resource_definition) = {
  type: "storage.googleapis.com/Bucket"
  pattern: "projects/{project}/buckets/{bucket}"
};

// StorageControl service includes selected control plane operations.
service StorageControl {
  option (google.api.default_host) = "storage.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/cloud-platform.read-only,"
      "https://www.googleapis.com/auth/devstorage.full_control,"
      "https://www.googleapis.com/auth/devstorage.read_only,"
      "https://www.googleapis.com/auth/devstorage.read_write";

  // Creates a new folder. This operation is only applicable to a hierarchical
  // namespace enabled bucket.
  rpc CreateFolder(CreateFolderRequest) returns (Folder) {
    option (google.api.routing) = {
      routing_parameters { field: "parent" path_template: "{bucket=**}" }
    };
    option (google.api.method_signature) = "parent,folder,folder_id";
  }

  // Permanently deletes an empty folder. This operation is only applicable to a
  // hierarchical namespace enabled bucket.
  rpc DeleteFolder(DeleteFolderRequest) returns (google.protobuf.Empty) {
    option (google.api.routing) = {
      routing_parameters {
        field: "name"
        path_template: "{bucket=projects/*/buckets/*}/**"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Returns metadata for the specified folder. This operation is only
  // applicable to a hierarchical namespace enabled bucket.
  rpc GetFolder(GetFolderRequest) returns (Folder) {
    option (google.api.routing) = {
      routing_parameters {
        field: "name"
        path_template: "{bucket=projects/*/buckets/*}/**"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Retrieves a list of folders. This operation is only applicable to a
  // hierarchical namespace enabled bucket.
  rpc ListFolders(ListFoldersRequest) returns (ListFoldersResponse) {
    option (google.api.routing) = {
      routing_parameters { field: "parent" path_template: "{bucket=**}" }
    };
    option (google.api.method_signature) = "parent";
  }

  // Renames a source folder to a destination folder. This operation is only
  // applicable to a hierarchical namespace enabled bucket. During a rename, the
  // source and destination folders are locked until the long running operation
  // completes.
  rpc RenameFolder(RenameFolderRequest) returns (google.longrunning.Operation) {
    option (google.api.routing) = {
      routing_parameters {
        field: "name"
        path_template: "{bucket=projects/*/buckets/*}/**"
      }
    };
    option (google.api.method_signature) = "name,destination_folder_id";
    option (google.longrunning.operation_info) = {
      response_type: "Folder"
      metadata_type: "RenameFolderMetadata"
    };
  }

  // Returns the storage layout configuration for a given bucket.
  rpc GetStorageLayout(GetStorageLayoutRequest) returns (StorageLayout) {
    option (google.api.routing) = {
      routing_parameters {
        field: "name"
        path_template: "{bucket=projects/*/buckets/*}/**"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a new managed folder.
  rpc CreateManagedFolder(CreateManagedFolderRequest) returns (ManagedFolder) {
    option (google.api.routing) = {
      routing_parameters { field: "parent" path_template: "{bucket=**}" }
    };
    option (google.api.method_signature) =
        "parent,managed_folder,managed_folder_id";
  }

  // Permanently deletes an empty managed folder.
  rpc DeleteManagedFolder(DeleteManagedFolderRequest)
      returns (google.protobuf.Empty) {
    option (google.api.routing) = {
      routing_parameters {
        field: "name"
        path_template: "{bucket=projects/*/buckets/*}/**"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Returns metadata for the specified managed folder.
  rpc GetManagedFolder(GetManagedFolderRequest) returns (ManagedFolder) {
    option (google.api.routing) = {
      routing_parameters {
        field: "name"
        path_template: "{bucket=projects/*/buckets/*}/**"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Retrieves a list of managed folders for a given bucket.
  rpc ListManagedFolders(ListManagedFoldersRequest)
      returns (ListManagedFoldersResponse) {
    option (google.api.routing) = {
      routing_parameters { field: "parent" path_template: "{bucket=**}" }
    };
    option (google.api.method_signature) = "parent";
  }
}

// Contains information about a pending rename operation.
message PendingRenameInfo {
  // Output only. The name of the rename operation.
  string operation = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// A folder resource. This resource can only exist in a hierarchical namespace
// enabled bucket.
message Folder {
  option (google.api.resource) = {
    type: "storage.googleapis.com/Folder"
    pattern: "projects/{project}/buckets/{bucket}/folders/{folder=**}"
    plural: "folders"
    singular: "folder"
  };

  // Identifier. The name of this folder.
  // Format: `projects/{project}/buckets/{bucket}/folders/{folder}`
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. The version of the metadata for this folder. Used for
  // preconditions and for detecting changes in metadata.
  int64 metageneration = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The creation time of the folder.
  google.protobuf.Timestamp create_time = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The modification time of the folder.
  google.protobuf.Timestamp update_time = 5
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Only present if the folder is part of an ongoing RenameFolder
  // operation. Contains information which can be used to query the operation
  // status. The presence of this field also indicates all write operations are
  // blocked for this folder, including folder, managed folder, and object
  // operations.
  PendingRenameInfo pending_rename_info = 7
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Request message for GetFolder. This operation is only applicable to a
// hierarchical namespace enabled bucket.
message GetFolderRequest {
  // Required. Name of the folder.
  // Format: `projects/{project}/buckets/{bucket}/folders/{folder}`
  string name = 6 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "storage.googleapis.com/Folder" }
  ];

  // Makes the operation only succeed conditional on whether the folder's
  // current metageneration matches the given value.
  optional int64 if_metageneration_match = 3;

  // Makes the operation only succeed conditional on whether the folder's
  // current metageneration does not match the given value.
  optional int64 if_metageneration_not_match = 4;

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 5 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// Request message for CreateFolder. This operation is only applicable to a
// hierarchical namespace enabled bucket.
message CreateFolderRequest {
  // Required. Name of the bucket in which the folder will reside. The bucket
  // must be a hierarchical namespace enabled bucket.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "storage.googleapis.com/Folder"
    }
  ];

  // Required. Properties of the new folder being created.
  // The bucket and name of the folder are specified in the parent and folder_id
  // fields, respectively. Populating those fields in `folder` will result in an
  // error.
  Folder folder = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The full name of a folder, including all its parent folders.
  // Folders use single '/' characters as a delimiter.
  // The folder_id must end with a slash.
  // For example, the folder_id of "books/biographies/" would create a new
  // "biographies/" folder under the "books/" folder.
  string folder_id = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. If true, parent folder doesn't have to be present and all missing
  // ancestor folders will be created atomically.
  bool recursive = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 5 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// Request message for DeleteFolder. This operation is only applicable to a
// hierarchical namespace enabled bucket.
message DeleteFolderRequest {
  // Required. Name of the folder.
  // Format: `projects/{project}/buckets/{bucket}/folders/{folder}`
  string name = 6 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "storage.googleapis.com/Folder" }
  ];

  // Makes the operation only succeed conditional on whether the folder's
  // current metageneration matches the given value.
  optional int64 if_metageneration_match = 3;

  // Makes the operation only succeed conditional on whether the folder's
  // current metageneration does not match the given value.
  optional int64 if_metageneration_not_match = 4;

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 5 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// Request message for ListFolders. This operation is only applicable to a
// hierarchical namespace enabled bucket.
message ListFoldersRequest {
  // Required. Name of the bucket in which to look for folders. The bucket must
  // be a hierarchical namespace enabled bucket.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "storage.googleapis.com/Folder"
    }
  ];

  // Optional. Maximum number of folders to return in a single response. The
  // service will use this parameter or 1,000 items, whichever is smaller.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A previously-returned page token representing part of the larger
  // set of results to view.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filter results to folders whose names begin with this prefix.
  // If set, the value must either be an empty string or end with a '/'.
  string prefix = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If set, returns results in a directory-like mode. The results
  // will only include folders that either exactly match the above prefix, or
  // are one level below the prefix. The only supported value is '/'.
  string delimiter = 8 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filter results to folders whose names are lexicographically equal
  // to or after lexicographic_start. If lexicographic_end is also set, the
  // folders listed have names between lexicographic_start (inclusive) and
  // lexicographic_end (exclusive).
  string lexicographic_start = 6 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filter results to folders whose names are lexicographically
  // before lexicographic_end. If lexicographic_start is also set, the folders
  // listed have names between lexicographic_start (inclusive) and
  // lexicographic_end (exclusive).
  string lexicographic_end = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 9 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// Response message for ListFolders.
message ListFoldersResponse {
  // The list of child folders
  repeated Folder folders = 1;

  // The continuation token, used to page through large result sets. Provide
  // this value in a subsequent request to return the next page of results.
  string next_page_token = 2;
}

// Request message for RenameFolder. This operation is only applicable to a
// hierarchical namespace enabled bucket.
message RenameFolderRequest {
  // Required. Name of the source folder being renamed.
  // Format: `projects/{project}/buckets/{bucket}/folders/{folder}`
  string name = 7 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "storage.googleapis.com/Folder" }
  ];

  // Required. The destination folder ID, e.g. `foo/bar/`.
  string destination_folder_id = 8 [(google.api.field_behavior) = REQUIRED];

  // Makes the operation only succeed conditional on whether the source
  // folder's current metageneration matches the given value.
  optional int64 if_metageneration_match = 4;

  // Makes the operation only succeed conditional on whether the source
  // folder's current metageneration does not match the given value.
  optional int64 if_metageneration_not_match = 5;

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted. This request is only
  // idempotent if a `request_id` is provided.
  string request_id = 6 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// The message contains metadata that is common to all Storage Control
// long-running operations, present in its `google.longrunning.Operation`
// messages, and accessible via `metadata.common_metadata`.
message CommonLongRunningOperationMetadata {
  // Output only. The time the operation was created.
  google.protobuf.Timestamp create_time = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the operation finished running.
  google.protobuf.Timestamp end_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the operation was last modified.
  google.protobuf.Timestamp update_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The type of operation invoked.
  string type = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Identifies whether the user has requested cancellation.
  bool requested_cancellation = 5 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The estimated progress of the operation in percentage [0,
  // 100]. The value -1 means the progress is unknown.
  int32 progress_percent = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Message returned in the metadata field of the Operation resource for
// RenameFolder operations.
message RenameFolderMetadata {
  // Generic metadata for the long running operation.
  CommonLongRunningOperationMetadata common_metadata = 1;

  // The path of the source folder.
  string source_folder_id = 2;

  // The path of the destination folder.
  string destination_folder_id = 3;
}

// The storage layout configuration of a bucket.
message StorageLayout {
  option (google.api.resource) = {
    type: "storage.googleapis.com/StorageLayout"
    pattern: "projects/{project}/buckets/{bucket}/storageLayout"
  };

  // Configuration for Custom Dual Regions.  It should specify precisely two
  // eligible regions within the same Multiregion. More information on regions
  // may be found [https://cloud.google.com/storage/docs/locations][here].
  message CustomPlacementConfig {
    // List of locations to use for data placement.
    repeated string data_locations = 1;
  }

  // Configuration for a bucket's hierarchical namespace feature.
  message HierarchicalNamespace {
    // Enables the hierarchical namespace feature.
    bool enabled = 1;
  }

  // Output only. The name of the StorageLayout resource.
  // Format: `projects/{project}/buckets/{bucket}/storageLayout`
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The location of the bucket.
  string location = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The location type of the bucket (region, dual-region,
  // multi-region, etc).
  string location_type = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The data placement configuration for custom dual region. If
  // there is no configuration, this is not a custom dual region bucket.
  CustomPlacementConfig custom_placement_config = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The bucket's hierarchical namespace configuration. If there is
  // no configuration, the hierarchical namespace is disabled.
  HierarchicalNamespace hierarchical_namespace = 5
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Request message for GetStorageLayout.
message GetStorageLayoutRequest {
  // Required. The name of the StorageLayout resource.
  // Format: `projects/{project}/buckets/{bucket}/storageLayout`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "storage.googleapis.com/StorageLayout"
    }
  ];

  // An optional prefix used for permission check. It is useful when the caller
  // only has limited permissions under a specific prefix.
  string prefix = 2;

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 3 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// A managed folder.
message ManagedFolder {
  option (google.api.resource) = {
    type: "storage.googleapis.com/ManagedFolder"
    pattern: "projects/{project}/buckets/{bucket}/managedFolders/{managed_folder=**}"
    plural: "managedFolders"
    singular: "managedFolder"
  };

  // Identifier. The name of this managed folder.
  // Format:
  // `projects/{project}/buckets/{bucket}/managedFolders/{managedFolder}`
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. The metadata version of this managed folder. It increases
  // whenever the metadata is updated. Used for preconditions and for detecting
  // changes in metadata. Managed folders don't have a generation number.
  int64 metageneration = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The creation time of the managed folder.
  google.protobuf.Timestamp create_time = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The modification time of the managed folder.
  google.protobuf.Timestamp update_time = 5
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Request message for GetManagedFolder.
message GetManagedFolderRequest {
  // Required. Name of the managed folder.
  // Format:
  // `projects/{project}/buckets/{bucket}/managedFolders/{managedFolder}`
  string name = 6 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "storage.googleapis.com/ManagedFolder"
    }
  ];

  // The operation succeeds conditional on the managed folder's current
  // metageneration matching the value here specified.
  optional int64 if_metageneration_match = 3;

  // The operation succeeds conditional on the managed folder's current
  // metageneration NOT matching the value here specified.
  optional int64 if_metageneration_not_match = 4;

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 5 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// Request message for CreateManagedFolder.
message CreateManagedFolderRequest {
  // Required. Name of the bucket this managed folder belongs to.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "storage.googleapis.com/ManagedFolder"
    }
  ];

  // Required. Properties of the managed folder being created.
  // The bucket and managed folder names are specified in the `parent` and
  // `managed_folder_id` fields. Populating these fields in `managed_folder`
  // will result in an error.
  ManagedFolder managed_folder = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The name of the managed folder. It uses a single `/` as delimiter
  // and leading and trailing `/` are allowed.
  string managed_folder_id = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 4 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// DeleteManagedFolder RPC request message.
message DeleteManagedFolderRequest {
  // Required. Name of the managed folder.
  // Format:
  // `projects/{project}/buckets/{bucket}/managedFolders/{managedFolder}`
  string name = 7 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "storage.googleapis.com/ManagedFolder"
    }
  ];

  // The operation succeeds conditional on the managed folder's current
  // metageneration matching the value here specified.
  optional int64 if_metageneration_match = 3;

  // The operation succeeds conditional on the managed folder's current
  // metageneration NOT matching the value here specified.
  optional int64 if_metageneration_not_match = 4;

  // Allows deletion of a managed folder even if it is not empty.
  // A managed folder is empty if it manages no child managed folders or
  // objects. Caller must have permission for
  // storage.managedFolders.setIamPolicy.
  bool allow_non_empty = 5;

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 6 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// Request message for ListManagedFolders.
message ListManagedFoldersRequest {
  // Required. Name of the bucket this managed folder belongs to.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "storage.googleapis.com/ManagedFolder"
    }
  ];

  // Optional. Maximum number of managed folders to return in a single response.
  // The service will use this parameter or 1,000 items, whichever is smaller.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A previously-returned page token representing part of the larger
  // set of results to view.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filter results to match managed folders with name starting with
  // this prefix.
  string prefix = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A unique identifier for this request. UUID is the recommended
  // format, but other formats are still accepted.
  string request_id = 5 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OPTIONAL
  ];
}

// Response message for ListManagedFolders.
message ListManagedFoldersResponse {
  // The list of matching managed folders
  repeated ManagedFolder managed_folders = 1;

  // The continuation token, used to page through large result sets. Provide
  // this value in a subsequent request to return the next page of results.
  string next_page_token = 2;
}
