syntax = "proto3";

package code.justin.tv.devrel.rbac;
option go_package = "rbacrpc";

// RBAC Is the original service that evolved to have too much functionality.
// We are slowly moving away from this god-service in favor of more focused services.
service RBAC {

  //
  // RBACCore
  //

  // List all companies. Administrative endpoint
  rpc ListCompanies(ListCompaniesRequest) returns (ListCompaniesResponse);
  // List memberships by user twitch ID; the orgs that the user is member of, with permissions for that role.
  rpc ListCompanyMemberships(ListCompanyMembershipsRequest) returns (ListCompanyMembershipsResponse);
  rpc SearchCompanies(SearchCompaniesRequest) returns (SearchCompaniesResponse);
  rpc GetCompany(Id) returns (Company);
  rpc UpdateCompany(UpdateCompanyRequest) returns (Company);

  // Creates an applicaton for a company. Company applications are manually reviewed in Vienna to ensure the company and requesting user have rights to the games they are requesting. When an application does not have games, it is auto approved and the company is created. The created company has the same ID as the application thus the ID returned will be the company ID when there are games.
  rpc CreateCompanyApplication(CreateCompanyApplicationRequest) returns (CompanyApplication);

  // Get membership data for a user in an organization.
  // Some data is protected to the same user or whitelisted-admins, and will be empty for other users
  rpc GetMembership(GetMembershipRequest) returns (Membership);
  // List memberships by company ID; the users that belong to the org with their roles.
  rpc GetUsersByCompanyId(GetUsersByCompanyIdRequest) returns (GetUsersByCompanyIdResponse);
  rpc AddUserToCompany(AddUserToCompanyRequest) returns (Empty); // Create a membership of a user into an organization
  rpc RemoveCompanyMembership(RemoveCompanyMembershipRequest) returns (Empty); // removes a user from a company
  rpc UpdateUser(UpdateUserRequest) returns (Empty); // Update membership (everything except the role)
  rpc UpdateUserRole(UpdateUserRoleRequest) returns (Membership); // Update membership role

  // List all roles, e.g. "Owner", "Manager", "Billing_Manager", etc.
  rpc ListAllRoles(Empty) returns (ListAllRolesResponse);

  // Validates if a twitch user has permission to resource. Resource is specificed as a resource type (namespace) and unique resource identifier.
  // Returns twirp NotFound with msg "resource" when resource is not found
  rpc ValidateByTwitchID(ValidateQuery) returns (ValidateResponse);
  // Creates a new resource and adds it to a company.
  // It only validates that the resource is wellformed and not duplicated.
  // Other specific validations should be done in the service that is using RBAC.
  rpc CreateResource(CreateResourceRequest) returns (CreateResourceResponse);
  // Get all resources by company and optionally type. May not be used yet
  // in production. It's for demo purposes of RBAC supporting new resource_types.
  rpc ListResources(ListResourcesRequest) returns (ListResourcesResponse);

  // Set the assigned billing manager for an extension in an organization.
  // The assigned organization member needs to have the Billing Manager role or be an Owner.
  rpc SetExtensionBillingManager(SetExtensionBillingManagerRequest) returns (SetExtensionBillingManagerResponse);
  // Get get extension billing managers for the specified extension client IDs
  rpc GetExtensionBillingManager(GetExtensionBillingManagerRequest) returns (GetExtensionBillingManagerResponse);
  // Return paginated shadow accounts across all companies. Mainly for the usage of chat's server firehose
  rpc GetPaginatedShadowAccounts(GetPaginatedShadowAccountsRequest) returns (GetPaginatedShadowAccountsResponse);

  //
  // ViennaBackend
  //

  rpc TransferExtensionToCompany(TransferExtensionRequest) returns (Empty);
  rpc DetachExtensionFromCompany(DetachExtensionRequest) returns (Empty);

  rpc ListCompanyApplications(ListCompanyApplicationsRequest) returns (ListCompanyApplicationsResponse);
  rpc SearchCompanyApplications(SearchCompanyApplicationsRequest) returns (SearchCompanyApplicationsResponse);
  rpc GetCompanyApplication(Id) returns (CompanyApplication);
  rpc UpdateCompanyApplication(UpdateCompanyApplicationRequest) returns (CompanyApplication);
  rpc DeleteCompanyApplication(DeleteCompanyApplicationRequest) returns (Empty); // reject application (soft delete)
  rpc OnboardCompany(OnboardCompanyRequest) returns (OnboardCompanyResponse); // approve company

  rpc ListGameApplications(ListGameApplicationsRequest) returns (ListGameApplicationsResponse);
  rpc GetGameApplicationsByCompany(Id) returns (GetGameApplicationsByCompanyResponse);
  rpc GetGameApplication(Id) returns (GameApplication);
  rpc CreateGameApplication(CreateGameApplicationRequest) returns (GameApplication);
  rpc CreateGameApplicationV2(CreateGameApplicationRequestV2) returns (GameApplication);
  rpc DeleteGameApplication(DeleteGameApplicationRequest) returns (Empty);
  rpc OnboardGame(OnboardGameRequest) returns (OnboardGameResponse); // approve game owned by a company

  rpc GetDeveloperApplications(GetDeveloperApplicationsRequest) returns (GetDeveloperApplicationsResponse);
  rpc DeleteDeveloperApplication(DeleteDeveloperApplicationRequest) returns (Empty);
  rpc OnboardDeveloper(OnboardDeveloperRequest) returns (OnboardDeveloperResponse); // approve user requesting to join company through the register company form

  rpc GetGamesByCompany(Id) returns (GetGamesByCompanyResponse);
  rpc GetGamesByTwitchID(Id) returns (GetGamesByTwitchIDResponse);

  // DEPRECATED: when multi-org is released, this will return the first of many possible companies.
  // Use ListCompanyMemberships instead of this endpoint.
  rpc GetCompanyByTwitchID(Id) returns (Company);

  //
  // Drops
  //

  rpc CreateJWT(JWTRequest) returns (JWT); // called from kraken/Visage
  rpc GetAllGamesWithCompanies(GetAllGamesWithCompaniesRequest) returns (GetAllGamesWithCompaniesResponse); // Called from Drops lambda

  //
  //  Feature Gating
  //

  // check if a feature gating is turned on
  rpc IsFeatureEnabled(IsFeatureEnabledRequest) returns (FeatureEnabledResponse);
  // check if a value is in the whitelist of a feature gating
  rpc IsValueEnabled(IsValueEnabledRequest) returns (FeatureEnabledResponse);
}

// RBACAdmin has methods for service data maintenance, for RBAC developers only.
// Should be merged into ViennaBackend
service RBACAdmin {
  // APIs for Company Management
  rpc DeleteCompany(DeleteCompanyRequest) returns (Empty);
  rpc OffboardResource(OffboardResourceRequest) returns (Empty);
  rpc TransferCompanyOwnership(TransferCompanyOwnershipRequest) returns (Empty);

  // APIs for internal user whitelist management
  rpc WhitelistUser(WhitelistUserRequest) returns (Empty);
  rpc RemoveUserFromWhitelist(RemoveUserFromWhitelistRequest) returns (Empty);
  rpc UpdateUserRoleInWhitelist(WhitelistUserRequest) returns (Empty);
  rpc ListUserWhitelistByRole(ListUserWhitelistByRoleRequest) returns (ListUserWhitelistByRoleResponse);

  // APIs for feature gating
  // Get/Set bool value
  // example: get/set feature gating on some thing can be controlled by bool value, like gating an API for all users
  rpc GetFeatureGatingValueInBool(GetFeatureGatingValueRequest) returns (GetFeatureGatingValueResponse);
  rpc SetFeatureGatingBoolValue(SetFeatureGatingBoolValueRequest) returns (Empty);
  // Get/Update value(s)
  // example: get/update feature gating on some thing needs a whitelist, like gating an API by whitelisted users
  rpc GetFeatureGatingValueInStrings(GetFeatureGatingValueRequest) returns (GetFeatureGatingValueResponse);
  rpc UpdateFeatureGatingValue(UpdateFeatureGatingValueRequest) returns (GetFeatureGatingValueResponse);
  // new RPC to create a new user with Shadow_Account role, this RPC will only be used in Vienna (internally).
  rpc CreateShadowAccount(CreateShadowAccountRequest) returns (CreateShadowAccountResponse);
}

// RBACActionHistory has extracted form RBAC. It just has one method to load action history.
// Should be merged into ViennaBackend
service RBACActionHistory {
  // Called from Vienna. List admin actions on a resource.
  rpc ListEntityActionHistories(ListEntityActionHistoriesRequest) returns (ListActionHistoriesResponse);
  // Called from Vienna. List actions.
  rpc ListActionHistories(ListActionHistoriesRequest) returns (ListActionHistoriesResponse);
}

// ExtensionReviews service has endpoints for both GraphQL and Vienna to manage extension version states
// lifecycle: => "review" => {"approved" | "pending_action"}.
// Methods called from the edge (GraphQL) need a valid Cartman Twitch-Authorization header,
// the user_twitch_id parameter must be owner of the Cartman token (current user).
// Methods called from Vienna (internal tool) need a valid OAuth token Authorization header,
// that is used to retrieve the Twitch-Authorization token from Cartman.
service ExtensionReviews {

  // Called from the edge (GraphQL). Author sets the version state to be in review.
  // Creates an Extension Case in Salesforce, then transitions the version in EMS to "review".
  rpc SetStateInReview(SetStateInReviewRequest) returns (Empty);

  // Called from the edge (GraphQL). Load latest author review notes and test-channel from review logs.
  rpc GetLatestAuthorNotes(GetLatestAuthorNotesRequest) returns (GetLatestAuthorNotesResponse);

  // Called from Vienna. Load the extension details for review and the review logs.
  rpc GetExtension(ExtensionVersionID) returns (Extension);

  // Called from Vienna. Moderator sets the state to "review".
  rpc SetStateApproved(SetStateReviewerRequest) returns (Empty);

  // Called from Vienna. Moderator sets the state to "pending_action".
  rpc SetStatePendingAction(SetStateReviewerRequest) returns (Empty);
}

message Empty {}

message Id {
  string id = 1;
}

message TransferExtensionRequest {
  string company_id = 1;
  string extension_id = 2;
  // billing mangers are used only during the transfer of a monetized extension
  // since a monetized extensions requires TIMS enabled (billing manager)
  // it could be left empty when not handling non-monetized extensions
  string billing_manager_id = 3;
}

message DetachExtensionRequest {
  string company_id = 1;
  string extension_id = 2;
  // required when detaching monetized extensions to set back to the original extension owner
  string owner_id = 3;
}

message SetStateInReviewRequest {
  string user_twitch_id = 1;
  string extension_id = 2;
  string extension_version = 3;
  string test_channel = 4;
  string notes = 5;
}

message GetLatestAuthorNotesRequest {
  string author_twitch_id = 1;
  string extension_id = 2;
}

message GetLatestAuthorNotesResponse {
  string author_twitch_id = 1;
  string extension_id = 2;
  string extension_version = 3;
  string review_log_created_at = 4; // timestamp in RFC3339 format
  string author_notes = 5;
  string author_channel = 6;
}

message SetStateReviewerRequest {
  string extension_id = 1;
  string extension_version = 2;
  repeated string review_reason_codes = 3; // list of reason codes like "1.1", "6.2.1", etc.
  string review_reason = 4; // other reasons
}

message ExtensionVersionID {
  string id = 1;
  string version = 2;
}
message Extension {
  string id = 1;
  string version = 2;
  string name = 3;
	string description = 4;
  string summary = 5;
	string state = 6;
  string author_name = 7;
  repeated ExtensionReviewLog transition_logs = 8;
}

message ExtensionReviewLog {
  string created_at = 1; // timestamp in RFC3339 format
  string state = 2; // "review", "approved", "pending_action"
  string author_twitch_id = 3;
  string author_notes = 4;
  string author_channel = 5;
  string extension_id = 6;
  string extension_version = 7;
  string reviewer_twitch_id = 8;
  repeated string review_reason_codes = 9; // list of policy codes like "1.1", "6.2.1", etc.
  string review_reason = 10; // other reasons as text
  string salesforce_case_id = 11;
}

message ListEntityActionHistoriesRequest {
  string entity_id = 1;
  string entity_type = 2;
}

message ListActionHistoriesRequest {
  string company_id = 1;
  string entity_id = 2;
  string entity_type = 3;
  uint64 limit = 4;
  uint64 offset = 5;
}

message ListActionHistoriesResponse {
  repeated ActionHistory actionHistories = 1;
  uint64 total = 2;
}

message ActionHistory {
  string id = 1;
  string action = 2;
  string user_twitch_id = 7;
  string createdAt = 4;
  string entity_id = 5;
  string entity_type = 6;
  string company_id = 8;
}

message Company {
  string id = 1;
  string companyName = 2;
  // Company URL for their Corporate Website
  string url = 3;
  // Indicates if company is a developer, publisher or other.
  int32 type = 4;
  // Legacy Companies are required to sign VHS Contract
  bool vhs_contractSigned = 5;
  // Legacy Companies need to agree to the Drops Terms
  bool campaignsEnabled = 6;
  // Resource Identifier to build permisisons & resources for validation.
  string identifier = 7;
  // ID of the Company in the CurseForge INfrastructure
  int32 curseCompany_id = 8;
  string createdAt = 9;
  // Indicates if the Company is a Legacy Company from the first iteration of the DevSite
  bool legacy = 10;
}

message DeleteCompanyRequest {
  string id = 1;
}

message ListCompaniesRequest {
  uint64 limit = 1;
  uint64 offset = 2;
  bool has_games_pending = 3;
  int32 owns_game_id = 4;
  bool has_developers_pending = 5;
}

message ListCompaniesResponse {
  repeated Company companies = 1;
  int32 _total = 2;
}

message UpdateCompanyRequest {
  string id = 1;
  string companyName = 2;
  string url = 3;
  int32 type = 4;
  bool vhs_contractSigned = 5;
  bool campaignsEnabled = 6;
  string identifier = 7;
  int32 curseCompany_id = 8;
}

message CompanyApplication {
  message Game {
    string id = 1;
    string name = 2;
  }

  string id = 1;
  string company_name = 2;
  string company_website = 3;
  int32 company_type = 4;
  repeated Game games = 5; // todo should be removed once Twilight #10790 merged
  string industry = 6;
  string company_size = 7;
  string city = 8;
  string state = 9;
  string country = 10;
  string contact_first_name = 11;
  string contact_last_name = 12;
  string contact_title = 13;
  string contact_email = 14;
  string product_interest = 15;
  string join_reason = 16;
  string twitch_id = 17;
  int32 status = 18;
  string created_at = 19; // RFC3339 timestamp
  string updated_at = 21; // RFC3339 timestamp, is empty until updated at least once
  string email_verification_status = 22;
}

message CreateCompanyApplicationRequest {
  string company_name = 1;
  string company_website = 2;
  int32 company_type = 3;
  repeated string games = 4;
  string industry = 5;
  string company_size = 6;
  string city = 7;
  string state = 8;
  string country = 9;
  string contact_first_name = 10;
  string contact_last_name = 11;
  string contact_title = 12;
  string contact_email = 13;
  string product_interest = 14;
  string join_reason = 15;
  string twitch_id = 16;
}

message DeleteCompanyApplicationRequest {
  string id = 1;
  bool skip_email = 2;
}

message ListCompanyApplicationsRequest {
  uint64 limit = 1;
  uint64 offset = 2;
  int32 status = 3;
  string twitch_id = 4;
}

message ListCompanyApplicationsResponse {
  repeated CompanyApplication companyApplications = 1;
  int32 _total = 2;
}

message UpdateCompanyApplicationRequest {
  string id = 1;
  string company_name = 2;
  string company_website = 3;
  int32 company_type = 4;
  repeated string games = 5;
  string industry = 6;
  string company_size = 7;
  string city = 8;
  string state = 9;
  string country = 10;
  string contact_first_name = 11;
  string contact_last_name = 12;
  string contact_title = 13;
  string contact_email = 14;
  string product_interest = 15;
  string join_reason = 16;
  string twitch_id = 17;
  int32 status = 18;
}

message OnboardCompanyRequest {
  string id = 1;
}

message OnboardCompanyResponse {
  string id = 1;
  Company company = 2;
}

message Game {
  int32 id = 1;
  int32 giantbomb_id = 2;
  string name = 3;
}

message GameWithCompany {
  int32 id = 1;
  int32 giantbomb_id = 2;
  string company_id = 3;
  int32 curseCompany_id = 4;
  string gamename = 5;
  bool legacy = 6;
}

message GetAllGamesWithCompaniesRequest {
  uint64 limit = 1;
  uint64 offset = 2;
}

message GetAllGamesWithCompaniesResponse {
  int32 _total = 1;
  repeated GameWithCompany games = 2;
}

message GetGamesByCompanyResponse {
  int32 _total = 1;
  Company company = 2;
  repeated Game games = 3;
}

message GetGamesByTwitchIDResponse {
  int32 _total = 1;
  repeated Game games = 2;
}

message GameApplication {
  string id = 1;
  int32 game_id = 2;
  string company_id = 3;
  string createdAt = 4;
  string game_name = 5;
}

message CreateGameApplicationRequest {
  int32 game_id = 1;
  string company_id = 2;
}

message CreateGameApplicationRequestV2
{
  int32 game_id = 1;
  string company_id = 2;

  // Current user performing the request, set from GraphQL authed user.
  // Vienna and other internal tools should use an OAuth token instead, to identify a whitelisted-admin.
  string requesting_twitch_id = 3;
}

message DeleteGameApplicationRequest {
  string id = 1;
  bool skip_email = 2;
}

message DeleteDeveloperApplicationRequest {
  string id = 1;
  bool skip_email = 2;
}


message GetGameApplicationsByCompanyResponse {
  repeated GameApplication gameApplications = 1;
  int32 _total = 2;
}

message GetDeveloperApplicationsRequest {
  string company_id = 1;
  uint64 limit = 2;
  uint64 offset = 3;
}

message GetDeveloperApplicationsResponse {
  repeated DeveloperApplication developer_applications = 1;
  int32 _total = 2;
}

message DeveloperApplication {
  string id = 1;
  string company_id = 3;
  string twitch_id = 4;
  string first_name = 5;
  string last_name = 6;
  string title = 7;
  string email = 8;
  string created_at = 9;
  string email_verification_status = 10;
}

message ListGameApplicationsRequest {
  uint64 limit = 1;
  uint64 offset = 2;
  int32 game_id = 3;
  string company_id = 4;
}

message ListGameApplicationsResponse {
  repeated GameApplication gameApplications = 1;
  int32 _total = 2;
}

message Name {
  string name = 1;
}

message UpdateUserRequest {
  string twitch_id = 2;
  string company_id = 7;
  string first_name = 3;
  string last_name = 4;
  string dev_title = 5;
  string dev_email = 6;
}

message GetMembershipRequest {
  string company_id = 1;
  string twitch_id = 2;
  string requesting_twitch_id = 3;
}

// Membership of a user to an organization, identified by twitch_id + company_id.
// A user (twitch_id) may belong to multiple organizations (company_id).
message Membership {
  string twitch_id = 2; // user id
  string company_id = 10; // company/organization
  string role = 9; // role in the organization: "Administrator", "Manager", "Developer" ...

  string first_name = 3;
  string last_name = 4;
  string dev_title = 5; // job position
  string dev_email = 6; // email with same domain as the organization

  string created_at = 7; // timestamp in RFC3339 format, when the user joined the org
  string modified_at = 8; // timestamp in RFC3339 format, when some data was modified
}

enum WhitelistUserRole {
  // User who can use vienna
  VIEWER = 0;
  // User who can use vienna and access user data
  SECURE_VIEWER = 1;
  // Admin who has access to everything
  ADMIN = 2;
}

message UserWhitelist {
  string twitch_id = 1;
  WhitelistUserRole role = 2;
}

enum SortOrder {
  ASC = 0;
  DESC = 1;
}

message GetUsersByCompanyIdRequest {
  string id = 1; // company id
  uint64 offset = 2;
  uint64 limit = 3;
  string sort_by = 4; // field name to be sorted on
  SortOrder order_by = 5;
  string role = 6; // filters users by role
}

message GetUsersByCompanyIdResponse {
  string id = 1; // company_id
  repeated Membership memberships = 2;
  uint64 total = 3;
  uint64 offset = 4;
}

message UpdateUserRoleRequest {
  string company_id = 3;
  string role = 4; // one of valid roles, e.g. "Developer"
  string twitch_id = 5;

  // Current user performing the request, set from GraphQL authed user.
  // Vienna and other internal tools should use an OAuth token instead, to identify a whitelisted-admin.
  string requesting_twitch_id = 6;
}

message ListAllRolesResponse {
  // List with all roles: e.g. "Owner", "Manager", "Billing_Manager", etc.
  // Note the Camel_Case_Underscored notation, that is different from GraphQL where enum constants are UPPERCASE_UNDERSCORE.
  repeated string roles = 1;
}

message SearchCompaniesRequest {
  string query = 1;
  uint64 limit = 2;
}

message SearchCompaniesResponse {
  repeated Company companies = 1;
  int32 _total = 2;
}

message SearchCompanyApplicationsRequest {
  string query = 1;
  uint64 limit = 2;
}

message SearchCompanyApplicationsResponse {
  repeated CompanyApplication companyApplications = 1;
  int32 _total = 2;
}

message ValidateQuery {
  // user_id is the Twitch ID of the acting user.
  // The validation will depend on the acting user having the right role and access to the resource.
  string user_id = 1;

  // permission to apply to resource for user. values are defined in RBAC.
  // A few are "addUser", "removeUser", "gamesAdd", "drops::manage".
  // For a full list, reach out to the team. Permissions are manually added to the service at this time.
  string permission = 5;
  // identifier of resource associated to permission. either RBAC company ID or discovery game ID.
  string resource_id = 6;
  // type of resource. values are "company", "game".
  string resource_type = 7;
}

message ValidateResponse {
  // Whether the user has access.
  bool valid = 1;
}

message JWT {
  // JWT Consumed by VHS
  string token = 1;
  // Account ID to use when calling VHS
  string account_id = 2;
}

message JWTRequest {
  // Operation requested from VHS
  string operation = 1;
  string company_id = 2;
  string user_id = 3;
}

message AddUserToCompanyRequest {
  CreateUserRequest user = 1;
  string company_id = 2;
  string role = 4;

  // Current user performing the request, set from GraphQL authed user.
  // Vienna and other internal tools should use an OAuth token instead, to identify a whitelisted-admin.
  string requesting_twitch_id = 5;
}

message CreateUserRequest {
  string twitch_id = 1;
  string first_name = 2;
  string last_name = 3;
  string title = 4;
  string email = 5;
}

message OnboardGameRequest {
  string game_application_id = 1;
}

message OnboardGameResponse {
  int32 game_id = 1;
  string game_name = 2;
}

message OffboardResourceRequest {
  string company_id = 1;
  string resource_id = 2;
  string resource_type = 3;
}

message OnboardDeveloperRequest {
  string developer_application_id = 1;
  // DEPRECATED: use role instead
  string role_id = 2;
  string role = 3;
}

message OnboardDeveloperResponse {
  // nothing for now
}

message Resource {
  // used to identity resource within owning twitch service
  string external_id = 1;
  // resource type can be: "game", "extension".
  string type = 2;
}

message CreateResourceRequest {
  // company to receive resource.
  string company_id = 1;
  // resource to add to company.
  Resource resource = 2;
}

message CreateResourceResponse {
  // nothing for now.
}

message ListResourcesRequest {
  // filter resources by company
  string company_id = 1;
  // filter resources by type
  string resource_type = 2;

  // pagination parameters
  // number of resources to return in the query
  uint64 limit = 3;
  // offset of resources
  uint64 offset= 4;
}

message ListResourcesResponse {
  repeated Resource resources = 1;
  uint64 _total = 2;
}

message WhitelistUserRequest {
  string twitch_id = 1;
  WhitelistUserRole role = 2;
}

message RemoveUserFromWhitelistRequest {
  string twitch_id = 1;
}

message ListUserWhitelistByRoleRequest {
  WhitelistUserRole role = 1;
  int32 offset = 2;
  int32 limit = 3;
}

message ListUserWhitelistByRoleResponse {
  repeated UserWhitelist users = 1;
  int32 total = 2;
}

message ListCompanyMembershipsRequest {
  string twitch_id = 1;
}

message CompanyMembership {
  Company company = 1;
  string role = 2;

  // user's company Companymembership permissions
  bool self_can_leave = 3;
  bool self_can_add_member = 4;
  bool self_can_remove_member = 5;

  // when the user joined
  string joined_at = 6; // RFC3339 timestamp
}

message ListCompanyMembershipsResponse {
  repeated CompanyMembership memberships = 1;
}

message GetFeatureGatingValueRequest {
   string key = 1;
 }

message GetFeatureGatingValueResponse {
  string key = 1;
  bool value_in_bool = 2;
  repeated string values_in_string = 3;
}

message SetFeatureGatingBoolValueRequest {
  string key = 1;
  bool value_in_bool = 2;
}

enum UpdateFeatureGatingValueAction {
  ADD = 0;
  REMOVE = 1;
}

message UpdateFeatureGatingValueRequest {
  string key = 1;
  string value_in_string = 2;
  UpdateFeatureGatingValueAction action = 3;
}

message RemoveCompanyMembershipRequest {
  string company_id = 1;
  string twitch_id = 2;

  // Current user performing the request, set from GraphQL authed user.
  // Vienna and other internal tools should use an OAuth token instead, to identify a whitelisted-admin.
  string requesting_twitch_id = 3;
}

message IsFeatureEnabledRequest {
  string feature_gating_key = 1;
}

message FeatureEnabledResponse {
  bool enabled = 1;
}

message IsValueEnabledRequest {
  string feature_gating_key = 1;
  string value_in_string = 2;
}

message ExtensionBillingManager {
  string extension_client_id = 1;
  // Assigned billing manager member, could have Billing_Manager role or be an Owner
  string billing_manager_twitch_id = 2;
  string created_at = 3;
  string updated_at = 4;
}

message SetExtensionBillingManagerRequest {
  string extension_client_id = 1;
  string billing_manager_twitch_id = 2;
  string requesting_twitch_id = 3;
}

message SetExtensionBillingManagerResponse {
  ExtensionBillingManager extension_billing_manager = 1;
}

message GetExtensionBillingManagerRequest {
  string extension_client_id = 1;
  string requesting_twitch_id = 2;
}

message GetExtensionBillingManagerResponse {
  ExtensionBillingManager extension_billing_manager = 1;
  // Check to see if the Twitch account was deleted. This could happen if monetizing billing manager leaves Twitch.
  bool is_billing_manager_account_deleted = 2;
}

message TransferCompanyOwnershipRequest {
  string company_id = 1; // company to have owner transfers
  string owners_new_role = 2; // new role for the current owner
  string twitch_id_to_promote = 3; // twitch id of company member to promote to owner
}

message CreateShadowAccountRequest {
  string company_id = 1;
  string client_id = 2;
  repeated CreateShadowAccountUserInput user_input = 3;
}

message CreateShadowAccountUserInput {
  string email = 1;
  string first_name = 2;
  string last_name = 3;
  string title = 4;
}

message CreateShadowAccountRecord {
  string email = 1;
  string twitch_id = 2;
  string username = 3;
  string error_message = 4;
}

message CreateShadowAccountResponse {
  string error = 1;
  repeated CreateShadowAccountRecord records = 2;
}

message GetPaginatedShadowAccountsRequest {
  uint64 limit = 1;
  uint64 offset = 2;
}

message GetPaginatedShadowAccountsResponse {
  repeated string twitch_ids = 1;
  uint64 next_offset = 2;
}
