syntax = "proto3";

package memos.api.v1;

import "api/v1/common.proto";
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/httpbody.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";

option go_package = "gen/api/v1";

service UserService {
  // ListUsers returns a list of users.
  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
    option (google.api.http) = {get: "/api/v1/users"};
  }
  // GetUser gets a user by name.
  rpc GetUser(GetUserRequest) returns (User) {
    option (google.api.http) = {get: "/api/v1/{name=users/*}"};
    option (google.api.method_signature) = "name";
  }
  // GetUserByUsername gets a user by username.
  rpc GetUserByUsername(GetUserByUsernameRequest) returns (User) {
    option (google.api.http) = {get: "/api/v1/users:username"};
    option (google.api.method_signature) = "username";
  }
  // GetUserAvatarBinary gets the avatar of a user.
  rpc GetUserAvatarBinary(GetUserAvatarBinaryRequest) returns (google.api.HttpBody) {
    option (google.api.http) = {get: "/file/{name=users/*}/avatar"};
    option (google.api.method_signature) = "name";
  }
  // CreateUser creates a new user.
  rpc CreateUser(CreateUserRequest) returns (User) {
    option (google.api.http) = {
      post: "/api/v1/users"
      body: "user"
    };
    option (google.api.method_signature) = "user";
  }
  // UpdateUser updates a user.
  rpc UpdateUser(UpdateUserRequest) returns (User) {
    option (google.api.http) = {
      patch: "/api/v1/{user.name=users/*}"
      body: "user"
    };
    option (google.api.method_signature) = "user,update_mask";
  }
  // DeleteUser deletes a user.
  rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {delete: "/api/v1/{name=users/*}"};
    option (google.api.method_signature) = "name";
  }
  // ListAllUserStats returns all user stats.
  rpc ListAllUserStats(ListAllUserStatsRequest) returns (ListAllUserStatsResponse) {
    option (google.api.http) = {post: "/api/v1/users/-/stats"};
  }
  // GetUserStats returns the stats of a user.
  rpc GetUserStats(GetUserStatsRequest) returns (UserStats) {
    option (google.api.http) = {get: "/api/v1/{name=users/*}/stats"};
    option (google.api.method_signature) = "name";
  }
  // GetUserSetting gets the setting of a user.
  rpc GetUserSetting(GetUserSettingRequest) returns (UserSetting) {
    option (google.api.http) = {get: "/api/v1/{name=users/*}/setting"};
    option (google.api.method_signature) = "name";
  }
  // UpdateUserSetting updates the setting of a user.
  rpc UpdateUserSetting(UpdateUserSettingRequest) returns (UserSetting) {
    option (google.api.http) = {
      patch: "/api/v1/{setting.name=users/*/setting}"
      body: "setting"
    };
    option (google.api.method_signature) = "setting,update_mask";
  }
  // ListUserAccessTokens returns a list of access tokens for a user.
  rpc ListUserAccessTokens(ListUserAccessTokensRequest) returns (ListUserAccessTokensResponse) {
    option (google.api.http) = {get: "/api/v1/{name=users/*}/access_tokens"};
    option (google.api.method_signature) = "name";
  }
  // CreateUserAccessToken creates a new access token for a user.
  rpc CreateUserAccessToken(CreateUserAccessTokenRequest) returns (UserAccessToken) {
    option (google.api.http) = {
      post: "/api/v1/{name=users/*}/access_tokens"
      body: "*"
    };
    option (google.api.method_signature) = "name";
  }
  // DeleteUserAccessToken deletes an access token for a user.
  rpc DeleteUserAccessToken(DeleteUserAccessTokenRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {delete: "/api/v1/{name=users/*}/access_tokens/{access_token}"};
    option (google.api.method_signature) = "name,access_token";
  }
}

message User {
  // The name of the user.
  // Format: users/{id}, id is the system generated auto-incremented id.
  string name = 1 [
    (google.api.field_behavior) = OUTPUT_ONLY,
    (google.api.field_behavior) = IDENTIFIER
  ];

  enum Role {
    ROLE_UNSPECIFIED = 0;
    HOST = 1;
    ADMIN = 2;
    USER = 3;
  }
  Role role = 3;

  string username = 4;

  string email = 5;

  string nickname = 6;

  string avatar_url = 7;

  string description = 8;

  string password = 9 [(google.api.field_behavior) = INPUT_ONLY];

  State state = 10;

  google.protobuf.Timestamp create_time = 11 [(google.api.field_behavior) = OUTPUT_ONLY];

  google.protobuf.Timestamp update_time = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
}

message ListUsersRequest {}

message ListUsersResponse {
  repeated User users = 1;
}

message GetUserRequest {
  // The name of the user.
  string name = 1;
}

message GetUserByUsernameRequest {
  // The username of the user.
  string username = 1;
}

message GetUserAvatarBinaryRequest {
  // The name of the user.
  string name = 1;

  // The raw HTTP body is bound to this field.
  google.api.HttpBody http_body = 2;
}

message CreateUserRequest {
  User user = 1;
}

message UpdateUserRequest {
  User user = 1 [(google.api.field_behavior) = REQUIRED];

  google.protobuf.FieldMask update_mask = 2;
}

message DeleteUserRequest {
  // The name of the user.
  string name = 1;
}

message UserStats {
  // The name of the user.
  string name = 1;

  // The timestamps when the memos were displayed.
  // We should return raw data to the client, and let the client format the data with the user's timezone.
  repeated google.protobuf.Timestamp memo_display_timestamps = 2;

  // The stats of memo types.
  MemoTypeStats memo_type_stats = 3;

  // The count of tags.
  // Format: "tag1": 1, "tag2": 2
  map<string, int32> tag_count = 4;

  // The pinned memos of the user.
  repeated string pinned_memos = 5;

  int32 total_memo_count = 6;

  message MemoTypeStats {
    int32 link_count = 1;
    int32 code_count = 2;
    int32 todo_count = 3;
    int32 undo_count = 4;
  }
}

message ListAllUserStatsRequest {}

message ListAllUserStatsResponse {
  repeated UserStats user_stats = 1;
}

message GetUserStatsRequest {
  // The name of the user.
  string name = 1;
}

message UserSetting {
  // The name of the user.
  string name = 1;
  // The preferred locale of the user.
  string locale = 2;
  // The preferred appearance of the user.
  string appearance = 3;
  // The default visibility of the memo.
  string memo_visibility = 4;
}

message GetUserSettingRequest {
  // The name of the user.
  string name = 1;
}

message UpdateUserSettingRequest {
  UserSetting setting = 1 [(google.api.field_behavior) = REQUIRED];

  google.protobuf.FieldMask update_mask = 2;
}

message UserAccessToken {
  string access_token = 1;
  string description = 2;
  google.protobuf.Timestamp issued_at = 3;
  google.protobuf.Timestamp expires_at = 4;
}

message ListUserAccessTokensRequest {
  // The name of the user.
  string name = 1;
}

message ListUserAccessTokensResponse {
  repeated UserAccessToken access_tokens = 1;
}

message CreateUserAccessTokenRequest {
  // The name of the user.
  string name = 1;

  string description = 2;

  optional google.protobuf.Timestamp expires_at = 3;
}

message DeleteUserAccessTokenRequest {
  // The name of the user.
  string name = 1;
  // access_token is the access token to delete.
  string access_token = 2;
}
