// Copyright 2020-2025 Buf Technologies, 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.

syntax = "proto3";

package buf.alpha.registry.v1alpha1;

import "buf/alpha/registry/v1alpha1/plugin_curation.proto";
import "buf/alpha/registry/v1alpha1/role.proto";
import "buf/alpha/registry/v1alpha1/verification_status.proto";
import "google/protobuf/timestamp.proto";

message User {
  // primary key, unique, immutable
  string id = 1;
  // immutable
  google.protobuf.Timestamp create_time = 2;
  // mutable
  google.protobuf.Timestamp update_time = 3;
  // unique, mutable
  string username = 4;
  // mutable
  bool deactivated = 5;
  // description is the user configurable description of the user.
  string description = 6;
  // url is the user configurable URL in the description of the user,
  // always included the scheme and will not have a #fragment suffix.
  string url = 7;
  // verification status of the user, configurable by server admin.
  VerificationStatus verification_status = 8;
  // user type of the user, depends on how the user was created.
  UserType user_type = 9;
}

// TODO: #663 move this to organization service
message OrganizationUser {
  User user = 1;
  // The ID of the organization for which the role belongs to.
  string organization_id = 2;
  // The role that the user has in the organization above.
  OrganizationRole organization_role = 3;
  // The source of the user's role in the organization above.
  OrganizationRoleSource organization_role_source = 4;
}

// UserPluginPreference contains the user's preferred language and the
// list of plugins for that language, which they selected in the BSR's Generated SDKs UI flow.
// These preferences are stored in the database so the language and plugins
// are pre-selected when the user navigates back to the Generated SDKs page from any device or browser.
message UserPluginPreference {
  reserved 1;
  reserved "user_id";
  // The language that the user has indicated as their preferred language for plugins.
  PluginLanguage selected_language = 2;
  // A list of plugin names selected by the user.
  repeated string selected_plugins = 3;
}

enum UserState {
  USER_STATE_UNSPECIFIED = 0;
  USER_STATE_ACTIVE = 1;
  USER_STATE_DEACTIVATED = 2;
}

enum UserType {
  USER_TYPE_UNSPECIFIED = 0;
  USER_TYPE_PERSONAL = 1;
  USER_TYPE_MACHINE = 2;
  USER_TYPE_SYSTEM = 3;
}

// UserService is the User service.
service UserService {
  // CreateUser creates a new user with the given username.
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // GetUser gets a user by ID.
  rpc GetUser(GetUserRequest) returns (GetUserResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // GetUserByUsername gets a user by username.
  rpc GetUserByUsername(GetUserByUsernameRequest) returns (GetUserByUsernameResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // ListUsers lists all users.
  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // ListOrganizationUsers lists all users for an organization.
  // TODO: #663 move this to organization service
  rpc ListOrganizationUsers(ListOrganizationUsersRequest) returns (ListOrganizationUsersResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // DeleteUser deletes a user.
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // Deactivate user deactivates a user.
  rpc DeactivateUser(DeactivateUserRequest) returns (DeactivateUserResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // UpdateUserServerRole update the role of an user in the server.
  rpc UpdateUserServerRole(UpdateUserServerRoleRequest) returns (UpdateUserServerRoleResponse);
  // CountUsers returns the number of users in the server by the user state provided.
  rpc CountUsers(CountUsersRequest) returns (CountUsersResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // UpdateUserSettings update the user settings including description.
  rpc UpdateUserSettings(UpdateUserSettingsRequest) returns (UpdateUserSettingsResponse);
}

message CreateUserRequest {
  string username = 1;
}

message CreateUserResponse {
  User user = 1;
}

message GetUserRequest {
  string id = 1;
}

message GetUserResponse {
  User user = 1;
}

message GetUserByUsernameRequest {
  string username = 1;
}

message GetUserByUsernameResponse {
  User user = 1;
}

message ListUsersRequest {
  uint32 page_size = 1;
  // The first page is returned if this is empty.
  string page_token = 2;
  bool reverse = 3;
  // If the user_state_filter is unspecified, users of all states are included.
  UserState user_state_filter = 4;
  // If the user_type_filters is empty, users of all types are included.
  repeated UserType user_type_filters = 5;
}

message ListUsersResponse {
  repeated User users = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message ListOrganizationUsersRequest {
  string organization_id = 1;
  uint32 page_size = 2;
  // The first page is returned if this is empty.
  string page_token = 3;
  bool reverse = 4;
}

message ListOrganizationUsersResponse {
  repeated OrganizationUser users = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message DeleteUserRequest {}

message DeleteUserResponse {}

message DeactivateUserRequest {
  string id = 1;
}

message DeactivateUserResponse {}

message UpdateUserServerRoleRequest {
  // The ID of the user for which to be updated a role.
  string user_id = 1;
  // The new role of the user in the server.
  ServerRole server_role = 2;
}

message UpdateUserServerRoleResponse {}

message CountUsersRequest {
  // If the user_state_filter is unspecified, all users are included.
  UserState user_state_filter = 1;
}

message CountUsersResponse {
  uint32 total_count = 1;
}

message UpdateUserSettingsRequest {
  string user_id = 1;
  // optional, update to description will only be made when this is present
  optional string description = 2;
  // optional, update to url will only be made when this is present
  optional string url = 3;
}

message UpdateUserSettingsResponse {}
