feat: ListUsersByMetadata protobuf (#10349)

# Which Problems Are Solved

There is a good amount of people from the community that need to
retrieve users matching some metadata stored on the user itself.

It is currently not possible to achieve that, the current solution
entails retrieving the user first, reading the metas and aggregating the
data together based on the metas.

We want to offer a way to search through user metas and return the user
info matching the search.

# How the Problems Are Solved

This PR contains only the protobuf so that it's easier to review.

# Additional Changes

Converter methods have been moved to their own package to avoid
cluttering and have better organization. The converter methods have also
been tested

# Additional Context

Discussion #9053
This commit is contained in:
Marco A.
2025-07-31 16:49:53 +02:00
committed by GitHub
parent 6d98b33c56
commit 14c1800251
5 changed files with 673 additions and 298 deletions

View File

@@ -54,4 +54,28 @@ message MetadataKeyFilter {
description: "defines which text equality method is used";
}
];
}
message UserByMetadataSearchFilter {
oneof filter {
option (validate.required) = true;
MetadataKeyFilter key_filter = 1;
MetadataValueFilter value_filter = 2;
}
}
message MetadataValueFilter {
string value = 1 [
(validate.rules).string = {max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"my value\""
description: "A value matching the metadata values"
}
];
zitadel.filter.v2.TextFilterMethod method = 2 [
(validate.rules).enum.defined_only = true,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "defines which text equality method is used";
}
];
}

View File

@@ -11,6 +11,8 @@ 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 "zitadel/metadata/v2/metadata.proto";
import "zitadel/filter/v2/filter.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/duration.proto";
@@ -1065,6 +1067,35 @@ service UserService {
};
};
}
// List users by metadata
//
// Returns a list of users matching the input metadata key, value or both.
//
// Required permission:
// - `user.read`
rpc ListUsersByMetadata (ListUsersByMetadataRequest) returns (ListUsersByMetadataResponse) {
option (google.api.http) = {
post: "/v2beta/users/metadata/search"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
responses: {
key: "200"
value: {
description: "The list of users matching the search criteria";
}
};
};
}
}
message AddHumanUserRequest{
@@ -1948,3 +1979,17 @@ enum AuthenticationMethodType {
AUTHENTICATION_METHOD_TYPE_OTP_SMS = 6;
AUTHENTICATION_METHOD_TYPE_OTP_EMAIL = 7;
}
message ListUsersByMetadataRequest {
repeated zitadel.metadata.v2.UserByMetadataSearchFilter filters = 1;
// Pagination and sorting.
zitadel.filter.v2.PaginationRequest pagination = 2;
}
message ListUsersByMetadataResponse {
repeated User users = 1;
// Contains the total number of apps matching the query and the applied limit.
zitadel.filter.v2.PaginationResponse pagination = 2;
}