/*
  Сервис реализует функционал управления пользователями
*/
syntax = "proto3";


import "google/api/visibility.proto";
import "google/protobuf/timestamp.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/descriptor.proto";
import "google/protobuf/wrappers.proto";

package keyapis.user.v1;

option java_package = "ru.keyapis.user.v1";
option java_outer_classname = "KeyapisUserV1Proto";
option java_multiple_files = false;
option java_string_check_utf8 = true;
option go_package = "/keyapis_user_v1";
option cc_enable_arenas = true;
option csharp_namespace = "Keyapis.User.V1";
option objc_class_prefix = "KEYAPISUSERV1";
option php_namespace = "Keyapis\\User\\V1";
option ruby_package = "Keyapis::User::V1";
option optimize_for = LITE_RUNTIME;

// Сервис пользователей
service UserService {
  // Метод получения пользователей.
  // Метод доступен для: admin, service, manager, bti, ltp_first, owner, empolyee.
  // Роли owner или employee могут запрашивать только пользователей, принадлежащих их компании
  rpc GetUser(GetUserRequest) returns (GetUserResponse) {
    option (google.api.http) = {
      get: "/user/api/v1/user/{id}"
    };
  }
  // Метод получения списка пользователей.
  // Метод доступен для: admin, service, manager, bti, ltp_first, owner, empolyee.
  // Если метод вызван ролями owner или employee в фильтре поле company_ids принудительно замещается их company_id
  rpc GetUserList(GetUserListRequest) returns (stream GetUserListResponse) {
    option (google.api.http) = {
      get: "/user/api/v1/user/list"
    };
  }
  // Метод получения количества пользователей.
  // Метод доступен для: admin, service, manager, bti, ltp_first, owner, empolyee.
  // Если метод вызван ролями owner или employee в фильтре поле company_ids принудительно замещается их company_id
  rpc GetUserCount(GetUserCountRequest) returns (GetUserCountResponse) {
    option (google.api.http) = {
      get: "/user/api/v1/user/count"
    };
  }
  // Метод удаления пользователей.
  // Метод доступен для: admin, service
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse) {
    option (google.api.http) = {
      delete: "/user/api/v1/user/{id}"
    };
  }

  // Метод удаления всех пользовательских сессий.
  // Метод доступен для: admin, service
  rpc DeleteUserSessions(DeleteUserSessionsRequest) returns (DeleteUserSessionsResponse) {
    option (google.api.http) = {
      delete: "/user/api/v1/user/{id}/sessions"
    };
  }
  // Метод получения идентификационного кода пользователя.
  // Метод доступен для: admin, service, ltp_first
  rpc GetUserCode(GetUserCodeRequest) returns (GetUserCodeResponse) {
    option (google.api.http) = {
      get: "/user/api/v1/user/{id}/code"
    };
  }
  // Метод создания идентификационного кода пользователя.
  // После создания кода отправляется событие SendingSmsTask.
  // Метод доступен для: admin, service, ltp_first
  rpc PostUserCodeCreate(PostUserCodeCreateRequest) returns (PostUserCodeCreateResponse) {
    option (google.api.http) = {
      post: "/user/api/v1/user/code/create",
      body: "*"
    };
  }
  // Метод создания пользователя.
  // Метод доступен для: admin, service.
  // Доступно создание пользователей с типом: ADMIN, MRF, BTI, LTP_FIRST, SERVICE, DEVICE_ADMIN, MANAGER
  rpc PostUser(PostUserRequest) returns (PostUserResponse) {
    option (google.api.http) = {
      post: "/user/api/v1/user",
      body: "*"
    };
  }
}


// Запрос удаления всех пользовательских сессий
message DeleteUserSessionsRequest {
  // Идентификатор пользователя.
  // # Диапазон: 1..2147483647
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос удаления всех пользовательских сессий
message DeleteUserSessionsResponse {
  // Ошибка запроса
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Ошибка
    Error error = 1;
  }
}


// Пользователь
message User {
  // Идентификатор.
  // # Диапазон: 0..2147483647
  int32 id = 1;
  // Справочник типов пользователей.
  // # Тип: byte
  enum Type {
    // Значение не указано
    TYPE_UNKNOWN = 0;
    // Владелец УК
    OWNER = 1;
    // Сотрудник УК
    EMPLOYEE = 2;
    // Мастер житель
    MASTER = 3;
    // Подчиненный житель
    SLAVE = 4;
    // Администратор
    ADMIN = 5;
    // Сотрудники ГАП
    SELLER = 6;
    // МРФ
    MRF = 7;
    // ГРЗУК
    BACKOFFICE = 8;
    // Сервис
    SERVICE = 9;
    // Супер админ
    ROOT = 10;
    // Сотрудник БТИ
    BTI = 11;
    // Сотрудник 1 ЛТП
    LTP_FIRST = 12;
    // Сотрудник ГАП
    EXTERNAL_SELLER = 13;
    // Приложение
    APPLICATION = 14;
    // Администратор точек продаж
    MANAGER = 15;
    // Администратор устройств
    DEVICE_ADMIN = 16;
  }
  // Тип пользователя
  Type type = 2 [(google.api.field_behavior) = REQUIRED];
  // Справочник типов статусов пользователей.
  // # Тип: byte
  enum StatusType {
    // Значение не указано
    STATUS_TYPE_UNKNOWN = 0;
    // Не активный пользователь
    NEW = 1;
    // Демо пользователь
    DEMO = 2;
    // Активный пользователь
    ACTIVE = 3;
    // Архивный пользователь
    BLOCKED = 4;
  }
  // Статус пользователя
  StatusType status_type = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Логин.
  // # Диапазон: 3..64
  google.protobuf.StringValue login = 4;
  // Электронная почта.
  // # Диапазон: 4..256
  google.protobuf.StringValue email = 5;
  // Номер телефона.
  // # Диапазон: 5..14
  google.protobuf.StringValue phone_number = 6;
  // Идентификатор компании.
  // # Диапазон: 1..2147483647
  google.protobuf.Int32Value company_id = 7;
  // Идентификатор МРФ
  google.protobuf.Int32Value mrf_id = 8;
  // Идентификатор РФ
  google.protobuf.Int32Value rf_id = 9;
  // Дата создания.
  // # Тип: DateTime
  google.protobuf.Timestamp created_at = 10 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Дата изменения.
  // # Тип: DateTime
  google.protobuf.Timestamp changed_at = 11;
  // Дата активации.
  // # Тип: DateTime
  google.protobuf.Timestamp activated_at = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Дата активации.
  // # Тип: DateTime
  google.protobuf.Timestamp blocked_at = 13 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Идентификатор создавшего пользователя.
  // Берется из токена.
  // # Диапазон: 1..2147483647
  google.protobuf.Int32Value creator_user_id = 14 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Идентификатор пользователя-владельца.
  // # Диапазон: 1..2147483647
  google.protobuf.Int32Value owner_user_id = 15;
  // Электронная почта для чеков.
  // # Диапазон: 4..256
  google.protobuf.StringValue invoice_email = 16;
  // Идентификатор пользователя в Видеонаблюдении.
  // Вычисляется на стороне сервера при создании пользователя
  google.protobuf.Int32Value vc_user_id = 17 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Описание
  google.protobuf.StringValue description = 18;
  // Идентификатор пользователя в сервисе ustore.
  // Вычисляется на стороне сервера при создании пользователя
  google.protobuf.Int32Value ustore_user_id = 19 [(google.api.field_behavior) = OUTPUT_ONLY];
   // Адрес окружения для внутренних пользователей
  google.protobuf.StringValue env_url = 20;
  // Ошибка сохранения.
  // Эти проверки выполняются при работе с базой данных и сторонними сервисами
  message SavingError {
    // Конфликт версий.
    // Причины:
    // - В базе хранится другая версия строки, значения changed_at отличаются
    message Conflict {}
    // Нельзя удалять пользователя с данным типом.
    // Доступные типы:
    // - Жилец (мастер)
    message UserTypeForbidden {}
    // Нельзя удалять пользователя в текущем статусе.
    // В каких статусах можно удалить пользователя:
    // - demo
    message UserStatusForbidden {}
    // Для данного типа пользователя идентификатор МРФ обязателен
    message MrfIdRequiredForUserType {}
    // Создатель пользователя должен иметь роль Admin
    message CreatorMustBeAdmin {}
    // Идентификатор РФ не соответствует идентификатору МРФ
    message RfIdDoesNotMatchMrfId {}
    // Email уже занят
    message EmailIsAlreadyTaken {}
    // Связанная с пользователем сущность не найдена.
    // Например: компания по company_id, пользователь по owner_user_id
    message EntityNotFound {
      // Поле
      string field = 1;
    }

    // Причина ошибки
    oneof reason {
      // Конфликт версий
      Conflict conflict = 1;
      // Нельзя удалять пользователя с данным типом
      UserTypeForbidden user_type_forbidden = 2;
      // Нельзя удалять пользователя в текущем статусе
      UserStatusForbidden user_status_forbidden = 3;
      // Идентификатор МРФ обязателен
      MrfIdRequiredForUserType mrf_id_is_required_for_user_type = 4;
      // Создатель пользователя должен иметь роль Admin
      CreatorMustBeAdmin creator_must_be_admin = 5;
      // Идентификатор РФ не соответствует идентификатору МРФ
      RfIdDoesNotMatchMrfId rf_id_does_not_match_mrf_id = 6;
      // Email уже занят
      EmailIsAlreadyTaken email_is_already_taken = 7;
      // Связанная с пользователем сущность не найдена
      EntityNotFound entity_not_found = 8;
    }
  }
}

// Идентификационный код пользователя
message UserCode {
  // Идентификационный код.
  // Если поле не заполнено, генерируется автоматически.
  // # Диапазон: 10000..99999
  int32 code = 1;
  // Идентификатор пользователя.
  // # Диапазон: 0..2147483647
  int32 user_id = 2 [(google.api.field_behavior) = REQUIRED];
  // Дата создания.
  // # Тип: DateTime
  google.protobuf.Timestamp created_at = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Идентификатор создателя кода
  int32 creator_user_id = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Тип создателя кода
  User.Type creator_user_type = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Запрос получения пользователя
message GetUserRequest {
  // Идентификатор
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос получения пользователя
message GetUserResponse {
  // Ошибка запроса получения пользователя
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Пользователь
    User data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Запрос на получение списка пользователей
message GetUserListRequest {
  // Фильтр
  UserFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Стандартный постраничный вывод
    UserPaging paging = 2;
  }
}

// Ответ на получение списка пользователей
message GetUserListResponse {
  // Ошибка запроса получения списка пользователей
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Пользователь
    User data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Запрос получения количества пользователей
message GetUserCountRequest {
  // Фильтр
  UserFilter filter = 1;
}

// Ответ на запрос получения количества пользователей
message GetUserCountResponse {
  // Ошибка запроса получения количества пользователей
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Всего пользователей
    int32 data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Запрос удаления пользователя
message DeleteUserRequest {
  // Идентификатор
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос удаления пользователя
message DeleteUserResponse {
  // Ошибка запроса удаления пользователя
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
      // Ошибка сохранения
      User.SavingError saving = 2;
    }
  }
  // Тип результата
  oneof type {
    // Ошибка
    Error error = 1;
  }
}

// Запрос получения идентификационного кода пользователя
message GetUserCodeRequest {
  // Идентификатор.
  // # Диапазон: 0..2147483647
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос получения идентификационного кода пользователя
message GetUserCodeResponse {
  // Ошибка запроса получения идентификационного кода пользователя
  message Error {
    // У пользователя отсутствует идентификационный код
    message UserCodeNotFound {}
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
      // У пользователя отсутствует идентификационный код
      UserCodeNotFound user_code_not_found = 2;
    }
  }
  // Тип результата
  oneof type {
    // Идентификационный код
    UserCode data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Запрос создания идентификационного кода пользователя
message PostUserCodeCreateRequest {
  // Идентификационный код пользователя
  UserCode user_code = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос создания идентификационного кода пользователя
message PostUserCodeCreateResponse {
  // Ошибка запроса создания идентификационного кода пользователя
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Идентификационный код пользователя
    UserCode data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Фильтр по пользователям
message UserFilter {
  // По идентификаторам компаний
  repeated int32 company_ids = 1;
  // По типам
  repeated User.Type user_types = 2;
  // По статусам
  repeated User.StatusType user_status_types = 3;
  // По электронной почте
  repeated string emails = 4;
  // По номеру телефона
  repeated string phone_numbers = 5;
  // По логину
  repeated string logins = 6;
  // Поиск по тексту.
  // Если значение не передано то поиск по нему не производится.
  // # Диапазон: 3..64.
  // # Поиск производится по полям:
  // # - Описание
  google.protobuf.StringValue text = 7;
  // Поиск по контактным данным пользователя (электронная почта или номер телефона).
  // Если значение не передано то поиск по нему не производится.
  // # Диапазон: 3..64.
  // # Поиск производится по полям:
  // # - Электронная почта;
  // # - Номер телефона
  google.protobuf.StringValue contacts = 8;
}

// Постраничный вывод
message UserPaging {
  // Справочник типов значений сортировки.
  // # Тип: byte
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По идентификатору
    ID = 1;
    // По времени создания
    CREATED_AT = 2;
    // По времени изменения
    CHANGED_AT = 3;
    // По электронной почте
    EMAIL = 4;
    // По рангу для поиска по тексту.
    // Применяется когда передано поле для поиска по тексту.
    // В случае если текстовое поле не передано, применяется значение по умолчанию
    RANK = 5;
    // По описанию (collate-agnostic ordering)
    DESCRIPTION = 6;
  }
  // Тип значения сортировки.
  // Если значение не передано, то будет взято значение по умолчанию.
  // # По умолчанию: CHANGED_AT
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки.
  // # Тип: byte
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // # По умолчанию: DESC
  DirectionType direction_type = 2;
  // Количество записей на страницу.
  // Если значение 0 (не передано), то будет взято значение по умолчанию.
  // # Диапазон: 0..100.
  // # По умолчанию: 20
  int32 limit = 3;
  // Сдвиг.
  // # Диапазон: 0..2147483647
  int32 offset = 4;
}
// Запрос на создание пользователя
message PostUserRequest {
  // Пользователь
  User data = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос на создание пользователя
message PostUserResponse {
  // Ошибка запроса сохранения пользователя
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
      // Ошибка сохранения
      User.SavingError saving = 2;
    }
  }
  // Тип ответа
  oneof type {
    // Пользователь
    User data = 1;
    // Ошибка
    Error error = 2;
  }
}
// Ошибки валидации.
// Эти проверки выполняются до обращения в базу данных
message ValidationError {
  // Путь к полю в формате наименования прото
  string path = 1 [(google.api.field_behavior) = REQUIRED];
  // Валидационное сообщение
  string message = 2 [(google.api.field_behavior) = REQUIRED];
}
