mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 17:57:33 +00:00
feat: user v2 service query (#7095)
* feat: add query endpoints for user v2 api * fix: correct integration tests * fix: correct linting * fix: correct linting * fix: comment out permission check on user get and list * fix: permission check on user v2 query * fix: merge back origin/main * fix: add search query in user emails * fix: reset count for SearchUser if users are removed due to permissions * fix: reset count for SearchUser if users are removed due to permissions --------- Co-authored-by: Elio Bischof <elio@zitadel.com>
This commit is contained in:
@@ -97,3 +97,26 @@ message ListDetails {
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
enum TextQueryMethod {
|
||||
TEXT_QUERY_METHOD_EQUALS = 0;
|
||||
TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE = 1;
|
||||
TEXT_QUERY_METHOD_STARTS_WITH = 2;
|
||||
TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE = 3;
|
||||
TEXT_QUERY_METHOD_CONTAINS = 4;
|
||||
TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE = 5;
|
||||
TEXT_QUERY_METHOD_ENDS_WITH = 6;
|
||||
TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE = 7;
|
||||
}
|
||||
|
||||
enum ListQueryMethod {
|
||||
LIST_QUERY_METHOD_IN = 0;
|
||||
}
|
||||
|
||||
enum TimestampQueryMethod {
|
||||
TIMESTAMP_QUERY_METHOD_EQUALS = 0;
|
||||
TIMESTAMP_QUERY_METHOD_GREATER = 1;
|
||||
TIMESTAMP_QUERY_METHOD_GREATER_OR_EQUALS = 2;
|
||||
TIMESTAMP_QUERY_METHOD_LESS = 3;
|
||||
TIMESTAMP_QUERY_METHOD_LESS_OR_EQUALS = 4;
|
||||
}
|
@@ -38,7 +38,6 @@ message HumanEmail {
|
||||
bool is_verified = 2;
|
||||
}
|
||||
|
||||
|
||||
message SendEmailVerificationCode {
|
||||
optional string url_template = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
|
220
proto/zitadel/user/v2beta/query.proto
Normal file
220
proto/zitadel/user/v2beta/query.proto
Normal file
@@ -0,0 +1,220 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package zitadel.user.v2beta;
|
||||
|
||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/user/v2beta;user";
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "validate/validate.proto";
|
||||
import "zitadel/user/v2beta/user.proto";
|
||||
import "zitadel/object/v2beta/object.proto";
|
||||
|
||||
message SearchQuery {
|
||||
oneof query {
|
||||
option (validate.required) = true;
|
||||
|
||||
UserNameQuery user_name_query = 1;
|
||||
FirstNameQuery first_name_query = 2;
|
||||
LastNameQuery last_name_query = 3;
|
||||
NickNameQuery nick_name_query = 4;
|
||||
DisplayNameQuery display_name_query = 5;
|
||||
EmailQuery email_query = 6;
|
||||
StateQuery state_query = 7;
|
||||
TypeQuery type_query = 8;
|
||||
LoginNameQuery login_name_query = 9;
|
||||
InUserIDQuery in_user_ids_query = 10;
|
||||
OrQuery or_query = 11;
|
||||
AndQuery and_query = 12;
|
||||
NotQuery not_query = 13;
|
||||
InUserEmailsQuery in_user_emails_query = 14;
|
||||
}
|
||||
}
|
||||
|
||||
message OrQuery {
|
||||
repeated SearchQuery queries = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the sub queries to 'OR'"
|
||||
}
|
||||
];
|
||||
}
|
||||
message AndQuery {
|
||||
repeated SearchQuery queries = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the sub queries to 'AND'"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message NotQuery {
|
||||
SearchQuery query = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the sub query to negate (NOT)"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message InUserIDQuery {
|
||||
repeated string user_ids = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the ids of the users to include"
|
||||
example: "[\"69629023906488334\",\"69622366012355662\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message UserNameQuery {
|
||||
string user_name = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
max_length: 200;
|
||||
example: "\"gigi-giraffe\"";
|
||||
}
|
||||
];
|
||||
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message FirstNameQuery {
|
||||
string first_name = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
max_length: 200;
|
||||
example: "\"Gigi\"";
|
||||
}
|
||||
];
|
||||
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message LastNameQuery {
|
||||
string last_name = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
max_length: 200;
|
||||
example: "\"Giraffe\"";
|
||||
}
|
||||
];
|
||||
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message NickNameQuery {
|
||||
string nick_name = 1 [(validate.rules).string = {max_len: 200}];
|
||||
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message DisplayNameQuery {
|
||||
string display_name = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
max_length: 200;
|
||||
example: "\"Gigi Giraffe\"";
|
||||
}
|
||||
];
|
||||
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message EmailQuery {
|
||||
string email_address = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "email address of the user. (spec: https://tools.ietf.org/html/rfc2822#section-3.4.1)"
|
||||
max_length: 200;
|
||||
example: "\"gigi@zitadel.com\"";
|
||||
}
|
||||
];
|
||||
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message LoginNameQuery {
|
||||
string login_name = 1 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
max_length: 200;
|
||||
example: "\"gigi@zitadel.cloud\"";
|
||||
}
|
||||
];
|
||||
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "defines which text equality method is used";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
//UserStateQuery always equals
|
||||
message StateQuery {
|
||||
UserState state = 1 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "current state of the user";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
//UserTypeQuery always equals
|
||||
message TypeQuery {
|
||||
Type type = 1 [
|
||||
(validate.rules).enum.defined_only = true,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the type of the user";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message InUserEmailsQuery {
|
||||
repeated string user_emails = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "the emails of the users to include"
|
||||
example: "[\"test@example.com\",\"test@example.org\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
enum Type {
|
||||
TYPE_UNSPECIFIED = 0;
|
||||
TYPE_HUMAN = 1;
|
||||
TYPE_MACHINE = 2;
|
||||
}
|
||||
|
||||
enum UserFieldName {
|
||||
USER_FIELD_NAME_UNSPECIFIED = 0;
|
||||
USER_FIELD_NAME_USER_NAME = 1;
|
||||
USER_FIELD_NAME_FIRST_NAME = 2;
|
||||
USER_FIELD_NAME_LAST_NAME = 3;
|
||||
USER_FIELD_NAME_NICK_NAME = 4;
|
||||
USER_FIELD_NAME_DISPLAY_NAME = 5;
|
||||
USER_FIELD_NAME_EMAIL = 6;
|
||||
USER_FIELD_NAME_STATE = 7;
|
||||
USER_FIELD_NAME_TYPE = 8;
|
||||
USER_FIELD_NAME_CREATION_DATE = 9;
|
||||
}
|
@@ -58,7 +58,7 @@ message SetHumanProfile {
|
||||
example: "\"en\"";
|
||||
}
|
||||
];
|
||||
optional zitadel.user.v2beta.Gender gender = 6 [
|
||||
optional Gender gender = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"GENDER_FEMALE\"";
|
||||
}
|
||||
@@ -98,11 +98,17 @@ message HumanProfile {
|
||||
example: "\"en\"";
|
||||
}
|
||||
];
|
||||
optional zitadel.user.v2beta.Gender gender = 6 [
|
||||
optional Gender gender = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"GENDER_FEMALE\"";
|
||||
}
|
||||
];
|
||||
string avatar_url = 7 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "avatar URL of the user"
|
||||
example: "\"https://api.zitadel.ch/assets/v1/avatar-32432jkh4kj32\"";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message SetMetadataEntry {
|
||||
@@ -158,12 +164,79 @@ message HumanUser {
|
||||
HumanPhone phone = 8;
|
||||
}
|
||||
|
||||
message User {
|
||||
string user_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
|
||||
}
|
||||
];
|
||||
UserState state = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "current state of the user";
|
||||
}
|
||||
];
|
||||
string username = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"minnie-mouse\"";
|
||||
}
|
||||
];
|
||||
repeated string login_names = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"gigi@zitadel.com\", \"gigi@zitadel.zitadel.ch\"]";
|
||||
}
|
||||
];
|
||||
string preferred_login_name = 5 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"gigi@zitadel.com\"";
|
||||
}
|
||||
];
|
||||
oneof type {
|
||||
HumanUser human = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "one of type use human or machine"
|
||||
}
|
||||
];
|
||||
MachineUser machine = 7 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "one of type use human or machine"
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
message MachineUser {
|
||||
string name = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"zitadel\"";
|
||||
}
|
||||
];
|
||||
string description = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"The one and only IAM\"";
|
||||
}
|
||||
];
|
||||
bool has_secret = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"true\"";
|
||||
}
|
||||
];
|
||||
AccessTokenType access_token_type = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Type of access token to receive";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
enum AccessTokenType {
|
||||
ACCESS_TOKEN_TYPE_BEARER = 0;
|
||||
ACCESS_TOKEN_TYPE_JWT = 1;
|
||||
}
|
||||
|
||||
enum UserState {
|
||||
USER_STATE_UNSPECIFIED = 0;
|
||||
USER_STATE_ACTIVE = 1;
|
||||
USER_STATE_INACTIVE = 2;
|
||||
USER_STATE_DELETED = 3;
|
||||
USER_STATE_LOCKED = 4;
|
||||
USER_STATE_SUSPEND = 5;
|
||||
USER_STATE_INITIAL = 6;
|
||||
USER_STATE_INITIAL = 5;
|
||||
}
|
@@ -10,6 +10,7 @@ import "zitadel/user/v2beta/phone.proto";
|
||||
import "zitadel/user/v2beta/idp.proto";
|
||||
import "zitadel/user/v2beta/password.proto";
|
||||
import "zitadel/user/v2beta/user.proto";
|
||||
import "zitadel/user/v2beta/query.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
@@ -138,6 +139,73 @@ service UserService {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
rpc GetUserByID(GetUserByIDRequest) returns (GetUserByIDResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v2beta/users/{user_id}"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "authenticated"
|
||||
}
|
||||
http_response: {
|
||||
success_code: 200
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
summary: "User by ID";
|
||||
description: "Returns the full user object (human or machine) including the profile, email, etc."
|
||||
tags: "Users";
|
||||
responses: {
|
||||
key: "200"
|
||||
value: {
|
||||
description: "OK";
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v2beta/users"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "authenticated"
|
||||
}
|
||||
http_response: {
|
||||
success_code: 200
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
tags: "Users";
|
||||
summary: "Search Users";
|
||||
description: "Search for users. By default, we will return users of your organization. Make sure to include a limit and sorting for pagination."
|
||||
responses: {
|
||||
key: "200";
|
||||
value: {
|
||||
description: "A list of all users matching the query";
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
key: "400";
|
||||
value: {
|
||||
description: "invalid list query";
|
||||
schema: {
|
||||
json_schema: {
|
||||
ref: "#/definitions/rpcStatus";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Change the email of a user
|
||||
rpc SetEmail (SetEmailRequest) returns (SetEmailResponse) {
|
||||
option (google.api.http) = {
|
||||
@@ -368,7 +436,6 @@ service UserService {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
summary: "Delete user";
|
||||
description: "The state of the user will be changed to 'deleted'. The user will not be able to log in anymore. Endpoints requesting this user will return an error 'User not found"
|
||||
@@ -829,6 +896,40 @@ message AddHumanUserResponse {
|
||||
optional string phone_code = 4;
|
||||
}
|
||||
|
||||
message GetUserByIDRequest {
|
||||
string user_id = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(google.api.field_behavior) = REQUIRED,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
min_length: 1;
|
||||
max_length: 200;
|
||||
example: "\"69629012906488334\"";
|
||||
description: "User ID of the user you like to get."
|
||||
}
|
||||
];
|
||||
zitadel.object.v2beta.Organization organization = 2;
|
||||
}
|
||||
|
||||
message GetUserByIDResponse {
|
||||
zitadel.object.v2beta.Details details = 1;
|
||||
zitadel.user.v2beta.User user = 2;
|
||||
}
|
||||
|
||||
message ListUsersRequest {
|
||||
//list limitations and ordering
|
||||
zitadel.object.v2beta.ListQuery query = 1;
|
||||
// the field the result is sorted
|
||||
zitadel.user.v2beta.UserFieldName sorting_column = 2;
|
||||
//criteria the client is looking for
|
||||
repeated zitadel.user.v2beta.SearchQuery queries = 3;
|
||||
}
|
||||
|
||||
message ListUsersResponse {
|
||||
zitadel.object.v2beta.ListDetails details = 1;
|
||||
zitadel.user.v2beta.UserFieldName sorting_column = 2;
|
||||
repeated zitadel.user.v2beta.User result = 3;
|
||||
}
|
||||
|
||||
message SetEmailRequest{
|
||||
string user_id = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
@@ -962,24 +1063,6 @@ message DeleteUserResponse {
|
||||
zitadel.object.v2beta.Details details = 1;
|
||||
}
|
||||
|
||||
message GetUserByIDRequest {
|
||||
string user_id = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(google.api.field_behavior) = REQUIRED,
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
min_length: 1;
|
||||
max_length: 200;
|
||||
example: "\"69629012906488334\"";
|
||||
description: "User ID of the user you like to get."
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GetUserByIDResponse {
|
||||
zitadel.object.v2beta.Details details = 1;
|
||||
HumanUser user = 2;
|
||||
}
|
||||
|
||||
message UpdateHumanUserRequest{
|
||||
string user_id = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
|
Reference in New Issue
Block a user